Support overflow detection for more than one ring-period
This commit is contained in:
		
				
					committed by
					
						
						Dario Nieuwenhuis
					
				
			
			
				
	
			
			
			
						parent
						
							4ea6662e55
						
					
				
				
					commit
					fc268df6f5
				
			@@ -4,6 +4,7 @@ use core::pin::Pin;
 | 
				
			|||||||
use core::sync::atomic::{fence, Ordering};
 | 
					use core::sync::atomic::{fence, Ordering};
 | 
				
			||||||
use core::task::{Context, Poll, Waker};
 | 
					use core::task::{Context, Poll, Waker};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use atomic_polyfill::AtomicUsize;
 | 
				
			||||||
use embassy_cortex_m::interrupt::Priority;
 | 
					use embassy_cortex_m::interrupt::Priority;
 | 
				
			||||||
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
 | 
					use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
 | 
				
			||||||
use embassy_sync::waitqueue::AtomicWaker;
 | 
					use embassy_sync::waitqueue::AtomicWaker;
 | 
				
			||||||
@@ -129,13 +130,16 @@ impl From<FifoThreshold> for vals::Fth {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct State {
 | 
					struct State {
 | 
				
			||||||
    ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT],
 | 
					    ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT],
 | 
				
			||||||
 | 
					    complete_count: [AtomicUsize; DMA_CHANNEL_COUNT],
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl State {
 | 
					impl State {
 | 
				
			||||||
    const fn new() -> Self {
 | 
					    const fn new() -> Self {
 | 
				
			||||||
 | 
					        const ZERO: AtomicUsize = AtomicUsize::new(0);
 | 
				
			||||||
        const AW: AtomicWaker = AtomicWaker::new();
 | 
					        const AW: AtomicWaker = AtomicWaker::new();
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            ch_wakers: [AW; DMA_CHANNEL_COUNT],
 | 
					            ch_wakers: [AW; DMA_CHANNEL_COUNT],
 | 
				
			||||||
 | 
					            complete_count: [ZERO; DMA_CHANNEL_COUNT],
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -184,13 +188,43 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: usize, index:
 | 
				
			|||||||
        panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num);
 | 
					        panic!("DMA: error on DMA@{:08x} channel {}", dma.0 as u32, channel_num);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if isr.tcif(channel_num % 4) && cr.read().tcie() {
 | 
					    let mut wake = false;
 | 
				
			||||||
        /* acknowledge transfer complete interrupt */
 | 
					
 | 
				
			||||||
        dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true));
 | 
					    if isr.htif(channel_num % 4) && cr.read().htie() {
 | 
				
			||||||
 | 
					        // Acknowledge half transfer complete interrupt
 | 
				
			||||||
 | 
					        dma.ifcr(channel_num / 4).write(|w| w.set_htif(channel_num % 4, true));
 | 
				
			||||||
 | 
					        wake = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wake |= process_tcif(dma, channel_num, index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if wake {
 | 
				
			||||||
        STATE.ch_wakers[index].wake();
 | 
					        STATE.ch_wakers[index].wake();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsafe fn process_tcif(dma: pac::dma::Dma, channel_num: usize, index: usize) -> bool {
 | 
				
			||||||
 | 
					    let isr_reg = dma.isr(channel_num / 4);
 | 
				
			||||||
 | 
					    let cr_reg = dma.st(channel_num).cr();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // First, figure out if tcif is set without a cs.
 | 
				
			||||||
 | 
					    if isr_reg.read().tcif(channel_num % 4) && cr_reg.read().tcie() {
 | 
				
			||||||
 | 
					        // Make tcif test again within a cs to avoid race when incrementing complete_count.
 | 
				
			||||||
 | 
					        critical_section::with(|_| {
 | 
				
			||||||
 | 
					            if isr_reg.read().tcif(channel_num % 4) && cr_reg.read().tcie() {
 | 
				
			||||||
 | 
					                // Acknowledge transfer complete interrupt
 | 
				
			||||||
 | 
					                dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true));
 | 
				
			||||||
 | 
					                STATE.complete_count[index].fetch_add(1, Ordering::Release);
 | 
				
			||||||
 | 
					                true
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                false
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(any(dma_v2, dmamux))]
 | 
					#[cfg(any(dma_v2, dmamux))]
 | 
				
			||||||
pub type Request = u8;
 | 
					pub type Request = u8;
 | 
				
			||||||
#[cfg(not(any(dma_v2, dmamux)))]
 | 
					#[cfg(not(any(dma_v2, dmamux)))]
 | 
				
			||||||
@@ -530,6 +564,7 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            dma.ifcr(isrn).write(|w| {
 | 
					            dma.ifcr(isrn).write(|w| {
 | 
				
			||||||
 | 
					                w.set_htif(isrbit, true);
 | 
				
			||||||
                w.set_tcif(isrbit, true);
 | 
					                w.set_tcif(isrbit, true);
 | 
				
			||||||
                w.set_teif(isrbit, true);
 | 
					                w.set_teif(isrbit, true);
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
@@ -593,32 +628,28 @@ impl<'a, C: Channel, W: Word> Drop for DoubleBuffered<'a, C, W> {
 | 
				
			|||||||
// ==============================
 | 
					// ==============================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<C: Channel> DmaCtrl for C {
 | 
					impl<C: Channel> DmaCtrl for C {
 | 
				
			||||||
    fn tcif(&self) -> bool {
 | 
					 | 
				
			||||||
        let channel_number = self.num();
 | 
					 | 
				
			||||||
        let dma = self.regs();
 | 
					 | 
				
			||||||
        let isrn = channel_number / 4;
 | 
					 | 
				
			||||||
        let isrbit = channel_number % 4;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        unsafe { dma.isr(isrn).read() }.tcif(isrbit)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn clear_tcif(&mut self) {
 | 
					 | 
				
			||||||
        let channel_number = self.num();
 | 
					 | 
				
			||||||
        let dma = self.regs();
 | 
					 | 
				
			||||||
        let isrn = channel_number / 4;
 | 
					 | 
				
			||||||
        let isrbit = channel_number % 4;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        unsafe {
 | 
					 | 
				
			||||||
            dma.ifcr(isrn).write(|w| {
 | 
					 | 
				
			||||||
                w.set_tcif(isrbit, true);
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn ndtr(&self) -> usize {
 | 
					    fn ndtr(&self) -> usize {
 | 
				
			||||||
        let ch = self.regs().st(self.num());
 | 
					        let ch = self.regs().st(self.num());
 | 
				
			||||||
        unsafe { ch.ndtr().read() }.ndt() as usize
 | 
					        unsafe { ch.ndtr().read() }.ndt() as usize
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn get_complete_count(&self) -> usize {
 | 
				
			||||||
 | 
					        let dma = self.regs();
 | 
				
			||||||
 | 
					        let channel_num = self.num();
 | 
				
			||||||
 | 
					        let index = self.index();
 | 
				
			||||||
 | 
					        // Manually process tcif in case transfer was completed and we are in a higher priority task.
 | 
				
			||||||
 | 
					        unsafe { process_tcif(dma, channel_num, index) };
 | 
				
			||||||
 | 
					        STATE.complete_count[index].load(Ordering::Acquire)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn reset_complete_count(&mut self) -> usize {
 | 
				
			||||||
 | 
					        let dma = self.regs();
 | 
				
			||||||
 | 
					        let channel_num = self.num();
 | 
				
			||||||
 | 
					        let index = self.index();
 | 
				
			||||||
 | 
					        // Manually process tcif in case transfer was completed and we are in a higher priority task.
 | 
				
			||||||
 | 
					        unsafe { process_tcif(dma, channel_num, index) };
 | 
				
			||||||
 | 
					        STATE.complete_count[index].swap(0, Ordering::AcqRel)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct RingBuffer<'a, C: Channel, W: Word> {
 | 
					pub struct RingBuffer<'a, C: Channel, W: Word> {
 | 
				
			||||||
@@ -657,7 +688,8 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
 | 
				
			|||||||
        w.set_minc(vals::Inc::INCREMENTED);
 | 
					        w.set_minc(vals::Inc::INCREMENTED);
 | 
				
			||||||
        w.set_pinc(vals::Inc::FIXED);
 | 
					        w.set_pinc(vals::Inc::FIXED);
 | 
				
			||||||
        w.set_teie(true);
 | 
					        w.set_teie(true);
 | 
				
			||||||
        w.set_tcie(false);
 | 
					        w.set_htie(true);
 | 
				
			||||||
 | 
					        w.set_tcie(true);
 | 
				
			||||||
        w.set_circ(vals::Circ::ENABLED);
 | 
					        w.set_circ(vals::Circ::ENABLED);
 | 
				
			||||||
        #[cfg(dma_v1)]
 | 
					        #[cfg(dma_v1)]
 | 
				
			||||||
        w.set_trbuff(true);
 | 
					        w.set_trbuff(true);
 | 
				
			||||||
@@ -703,7 +735,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn clear(&mut self) {
 | 
					    pub fn clear(&mut self) {
 | 
				
			||||||
        self.ringbuf.clear();
 | 
					        self.ringbuf.clear(&mut *self.channel);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Read bytes from the ring buffer
 | 
					    /// Read bytes from the ring buffer
 | 
				
			||||||
@@ -712,6 +744,22 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
 | 
				
			|||||||
        self.ringbuf.read(&mut *self.channel, buf)
 | 
					        self.ringbuf.read(&mut *self.channel, buf)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn is_empty(&self) -> bool {
 | 
				
			||||||
 | 
					        self.ringbuf.is_empty()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn len(&self) -> usize {
 | 
				
			||||||
 | 
					        self.ringbuf.len()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn capacity(&self) -> usize {
 | 
				
			||||||
 | 
					        self.ringbuf.dma_buf.len()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn set_waker(&mut self, waker: &Waker) {
 | 
				
			||||||
 | 
					        STATE.ch_wakers[self.channel.index()].register(waker);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn clear_irqs(&mut self) {
 | 
					    fn clear_irqs(&mut self) {
 | 
				
			||||||
        let channel_number = self.channel.num();
 | 
					        let channel_number = self.channel.num();
 | 
				
			||||||
        let dma = self.channel.regs();
 | 
					        let dma = self.channel.regs();
 | 
				
			||||||
@@ -720,6 +768,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            dma.ifcr(isrn).write(|w| {
 | 
					            dma.ifcr(isrn).write(|w| {
 | 
				
			||||||
 | 
					                w.set_htif(isrbit, true);
 | 
				
			||||||
                w.set_tcif(isrbit, true);
 | 
					                w.set_tcif(isrbit, true);
 | 
				
			||||||
                w.set_teif(isrbit, true);
 | 
					                w.set_teif(isrbit, true);
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
@@ -733,6 +782,7 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
 | 
				
			|||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            ch.cr().write(|w| {
 | 
					            ch.cr().write(|w| {
 | 
				
			||||||
                w.set_teie(true);
 | 
					                w.set_teie(true);
 | 
				
			||||||
 | 
					                w.set_htie(true);
 | 
				
			||||||
                w.set_tcie(true);
 | 
					                w.set_tcie(true);
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -743,15 +793,10 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
 | 
				
			|||||||
        unsafe { ch.cr().read() }.en()
 | 
					        unsafe { ch.cr().read() }.en()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Gets the total remaining transfers for the channel
 | 
					    /// Synchronize the position of the ring buffer to the actual DMA controller position
 | 
				
			||||||
    /// Note: this will be zero for transfers that completed without cancellation.
 | 
					    pub fn reload_position(&mut self) {
 | 
				
			||||||
    pub fn get_remaining_transfers(&self) -> usize {
 | 
					 | 
				
			||||||
        let ch = self.channel.regs().st(self.channel.num());
 | 
					        let ch = self.channel.regs().st(self.channel.num());
 | 
				
			||||||
        unsafe { ch.ndtr().read() }.ndt() as usize
 | 
					        self.ringbuf.ndtr = unsafe { ch.ndtr().read() }.ndt() as usize;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_ndtr(&mut self, ndtr: usize) {
 | 
					 | 
				
			||||||
        self.ringbuf.ndtr = ndtr;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,14 +10,6 @@ use super::word::Word;
 | 
				
			|||||||
/// to the current register value. `ndtr` describes the current position of the DMA
 | 
					/// to the current register value. `ndtr` describes the current position of the DMA
 | 
				
			||||||
/// write.
 | 
					/// write.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// # Safety
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// The ring buffer controls the TCIF (transfer completed interrupt flag) to
 | 
					 | 
				
			||||||
/// detect buffer overruns, hence this interrupt must be disabled.
 | 
					 | 
				
			||||||
/// The buffer can detect overruns up to one period, that is, for a X byte buffer,
 | 
					 | 
				
			||||||
/// overruns can be detected if they happen from byte X+1 up to 2X. After this
 | 
					 | 
				
			||||||
/// point, overrunds may or may not be detected.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// # Buffer layout
 | 
					/// # Buffer layout
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// ```text
 | 
					/// ```text
 | 
				
			||||||
@@ -39,7 +31,6 @@ pub struct DmaRingBuffer<'a, W: Word> {
 | 
				
			|||||||
    pub(crate) dma_buf: &'a mut [W],
 | 
					    pub(crate) dma_buf: &'a mut [W],
 | 
				
			||||||
    first: usize,
 | 
					    first: usize,
 | 
				
			||||||
    pub ndtr: usize,
 | 
					    pub ndtr: usize,
 | 
				
			||||||
    expect_next_read_to_wrap: bool,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, PartialEq)]
 | 
					#[derive(Debug, PartialEq)]
 | 
				
			||||||
@@ -50,13 +41,13 @@ pub trait DmaCtrl {
 | 
				
			|||||||
    /// buffer until the dma writer wraps.
 | 
					    /// buffer until the dma writer wraps.
 | 
				
			||||||
    fn ndtr(&self) -> usize;
 | 
					    fn ndtr(&self) -> usize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Read the transfer completed interrupt flag
 | 
					    /// Get the transfer completed counter.
 | 
				
			||||||
    /// This flag is set by the dma controller when NDTR is reloaded,
 | 
					    /// This counter is incremented by the dma controller when NDTR is reloaded,
 | 
				
			||||||
    /// i.e. when the writing wraps.
 | 
					    /// i.e. when the writing wraps.
 | 
				
			||||||
    fn tcif(&self) -> bool;
 | 
					    fn get_complete_count(&self) -> usize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Clear the transfer completed interrupt flag
 | 
					    /// Reset the transfer completed counter to 0 and return the value just prior to the reset.
 | 
				
			||||||
    fn clear_tcif(&mut self);
 | 
					    fn reset_complete_count(&mut self) -> usize;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a, W: Word> DmaRingBuffer<'a, W> {
 | 
					impl<'a, W: Word> DmaRingBuffer<'a, W> {
 | 
				
			||||||
@@ -66,15 +57,14 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
 | 
				
			|||||||
            dma_buf,
 | 
					            dma_buf,
 | 
				
			||||||
            first: 0,
 | 
					            first: 0,
 | 
				
			||||||
            ndtr,
 | 
					            ndtr,
 | 
				
			||||||
            expect_next_read_to_wrap: false,
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Reset the ring buffer to its initial state
 | 
					    /// Reset the ring buffer to its initial state
 | 
				
			||||||
    pub fn clear(&mut self) {
 | 
					    pub fn clear(&mut self, dma: &mut impl DmaCtrl) {
 | 
				
			||||||
        self.first = 0;
 | 
					        self.first = 0;
 | 
				
			||||||
        self.ndtr = self.dma_buf.len();
 | 
					        self.ndtr = self.dma_buf.len();
 | 
				
			||||||
        self.expect_next_read_to_wrap = false;
 | 
					        dma.reset_complete_count();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The buffer end position
 | 
					    /// The buffer end position
 | 
				
			||||||
@@ -83,14 +73,12 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Returns whether the buffer is empty
 | 
					    /// Returns whether the buffer is empty
 | 
				
			||||||
    #[allow(dead_code)]
 | 
					 | 
				
			||||||
    pub fn is_empty(&self) -> bool {
 | 
					    pub fn is_empty(&self) -> bool {
 | 
				
			||||||
        self.first == self.end()
 | 
					        self.first == self.end()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The current number of bytes in the buffer
 | 
					    /// The current number of bytes in the buffer
 | 
				
			||||||
    /// This may change at any time if dma is currently active
 | 
					    /// This may change at any time if dma is currently active
 | 
				
			||||||
    #[allow(dead_code)]
 | 
					 | 
				
			||||||
    pub fn len(&self) -> usize {
 | 
					    pub fn len(&self) -> usize {
 | 
				
			||||||
        // Read out a stable end (the dma periheral can change it at anytime)
 | 
					        // Read out a stable end (the dma periheral can change it at anytime)
 | 
				
			||||||
        let end = self.end();
 | 
					        let end = self.end();
 | 
				
			||||||
@@ -112,27 +100,19 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
 | 
				
			|||||||
        if self.first == end {
 | 
					        if self.first == end {
 | 
				
			||||||
            // The buffer is currently empty
 | 
					            // The buffer is currently empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if dma.tcif() {
 | 
					            if dma.get_complete_count() > 0 {
 | 
				
			||||||
                // The dma controller has written such that the ring buffer now wraps
 | 
					                // The DMA has written such that the ring buffer wraps at least once
 | 
				
			||||||
                // This is the special case where exactly n*dma_buf.len(), n = 1,2,..., bytes was written,
 | 
					 | 
				
			||||||
                // but where additional bytes are now written causing the ring buffer to wrap.
 | 
					 | 
				
			||||||
                // This is only an error if the writing has passed the current unread region.
 | 
					 | 
				
			||||||
                self.ndtr = dma.ndtr();
 | 
					                self.ndtr = dma.ndtr();
 | 
				
			||||||
                if self.end() > self.first {
 | 
					                if self.end() > self.first || dma.get_complete_count() > 1 {
 | 
				
			||||||
                    dma.clear_tcif();
 | 
					 | 
				
			||||||
                    return Err(OverrunError);
 | 
					                    return Err(OverrunError);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.expect_next_read_to_wrap = false;
 | 
					 | 
				
			||||||
            Ok(0)
 | 
					            Ok(0)
 | 
				
			||||||
        } else if self.first < end {
 | 
					        } else if self.first < end {
 | 
				
			||||||
            // The available, unread portion in the ring buffer DOES NOT wrap
 | 
					            // The available, unread portion in the ring buffer DOES NOT wrap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if self.expect_next_read_to_wrap {
 | 
					            if dma.get_complete_count() > 1 {
 | 
				
			||||||
                // The read was expected to wrap but it did not
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                dma.clear_tcif();
 | 
					 | 
				
			||||||
                return Err(OverrunError);
 | 
					                return Err(OverrunError);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -141,35 +121,39 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            compiler_fence(Ordering::SeqCst);
 | 
					            compiler_fence(Ordering::SeqCst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if dma.tcif() {
 | 
					            match dma.get_complete_count() {
 | 
				
			||||||
                // The dma controller has written such that the ring buffer now wraps
 | 
					                0 => {
 | 
				
			||||||
 | 
					                    // The DMA writer has not wrapped before nor after the copy
 | 
				
			||||||
                self.ndtr = dma.ndtr();
 | 
					                }
 | 
				
			||||||
                if self.end() > self.first {
 | 
					                1 => {
 | 
				
			||||||
                    // The bytes that we have copied out have overflowed
 | 
					                    // The DMA writer has written such that the ring buffer now wraps
 | 
				
			||||||
                    // as the writer has now both wrapped and is currently writing
 | 
					                    self.ndtr = dma.ndtr();
 | 
				
			||||||
                    // within the region that we have just copied out
 | 
					                    if self.end() > self.first || dma.get_complete_count() > 1 {
 | 
				
			||||||
 | 
					                        // The bytes that we have copied out have overflowed
 | 
				
			||||||
                    // Clear transfer completed interrupt flag
 | 
					                        // as the writer has now both wrapped and is currently writing
 | 
				
			||||||
                    dma.clear_tcif();
 | 
					                        // within the region that we have just copied out
 | 
				
			||||||
 | 
					                        return Err(OverrunError);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                _ => {
 | 
				
			||||||
                    return Err(OverrunError);
 | 
					                    return Err(OverrunError);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.first = (self.first + len) % self.dma_buf.len();
 | 
					            self.first = (self.first + len) % self.dma_buf.len();
 | 
				
			||||||
            self.expect_next_read_to_wrap = false;
 | 
					 | 
				
			||||||
            Ok(len)
 | 
					            Ok(len)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // The available, unread portion in the ring buffer DOES wrap
 | 
					            // The available, unread portion in the ring buffer DOES wrap
 | 
				
			||||||
            // The dma controller has wrapped since we last read and is currently
 | 
					            // The DMA writer has wrapped since we last read and is currently
 | 
				
			||||||
            // writing (or the next byte added will be) in the beginning of the ring buffer.
 | 
					            // writing (or the next byte added will be) in the beginning of the ring buffer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // If the unread portion wraps then the writer must also have wrapped,
 | 
					            let complete_count = dma.get_complete_count();
 | 
				
			||||||
            // or it has wrapped and we already cleared the TCIF flag
 | 
					            if complete_count > 1 {
 | 
				
			||||||
            assert!(dma.tcif() || self.expect_next_read_to_wrap);
 | 
					                return Err(OverrunError);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Clear transfer completed interrupt flag
 | 
					            // If the unread portion wraps then the writer must also have wrapped
 | 
				
			||||||
            dma.clear_tcif();
 | 
					            assert!(complete_count == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if self.first + buf.len() < self.dma_buf.len() {
 | 
					            if self.first + buf.len() < self.dma_buf.len() {
 | 
				
			||||||
                // The provided read buffer is not large enough to include all bytes from the tail of the dma buffer.
 | 
					                // The provided read buffer is not large enough to include all bytes from the tail of the dma buffer.
 | 
				
			||||||
@@ -182,13 +166,12 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
 | 
				
			|||||||
                // We have now copied out the data from dma_buf
 | 
					                // We have now copied out the data from dma_buf
 | 
				
			||||||
                // Make sure that the just read part was not overwritten during the copy
 | 
					                // Make sure that the just read part was not overwritten during the copy
 | 
				
			||||||
                self.ndtr = dma.ndtr();
 | 
					                self.ndtr = dma.ndtr();
 | 
				
			||||||
                if self.end() > self.first || dma.tcif() {
 | 
					                if self.end() > self.first || dma.get_complete_count() > 1 {
 | 
				
			||||||
                    // The writer has entered the data that we have just read since we read out `end` in the beginning and until now.
 | 
					                    // The writer has entered the data that we have just read since we read out `end` in the beginning and until now.
 | 
				
			||||||
                    return Err(OverrunError);
 | 
					                    return Err(OverrunError);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                self.first = (self.first + len) % self.dma_buf.len();
 | 
					                self.first = (self.first + len) % self.dma_buf.len();
 | 
				
			||||||
                self.expect_next_read_to_wrap = true;
 | 
					 | 
				
			||||||
                Ok(len)
 | 
					                Ok(len)
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // The provided read buffer is large enough to include all bytes from the tail of the dma buffer,
 | 
					                // The provided read buffer is large enough to include all bytes from the tail of the dma buffer,
 | 
				
			||||||
@@ -201,14 +184,14 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
 | 
				
			|||||||
                compiler_fence(Ordering::SeqCst);
 | 
					                compiler_fence(Ordering::SeqCst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // We have now copied out the data from dma_buf
 | 
					                // We have now copied out the data from dma_buf
 | 
				
			||||||
                // Make sure that the just read part was not overwritten during the copy
 | 
					                // Reset complete counter and make sure that the just read part was not overwritten during the copy
 | 
				
			||||||
                self.ndtr = dma.ndtr();
 | 
					                self.ndtr = dma.ndtr();
 | 
				
			||||||
                if self.end() > self.first || dma.tcif() {
 | 
					                let complete_count = dma.reset_complete_count();
 | 
				
			||||||
 | 
					                if self.end() > self.first || complete_count > 1 {
 | 
				
			||||||
                    return Err(OverrunError);
 | 
					                    return Err(OverrunError);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                self.first = head;
 | 
					                self.first = head;
 | 
				
			||||||
                self.expect_next_read_to_wrap = false;
 | 
					 | 
				
			||||||
                Ok(tail + head)
 | 
					                Ok(tail + head)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -243,14 +226,14 @@ mod tests {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    struct TestCtrl {
 | 
					    struct TestCtrl {
 | 
				
			||||||
        next_ndtr: RefCell<Option<usize>>,
 | 
					        next_ndtr: RefCell<Option<usize>>,
 | 
				
			||||||
        tcif: bool,
 | 
					        complete_count: usize,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    impl TestCtrl {
 | 
					    impl TestCtrl {
 | 
				
			||||||
        pub const fn new() -> Self {
 | 
					        pub const fn new() -> Self {
 | 
				
			||||||
            Self {
 | 
					            Self {
 | 
				
			||||||
                next_ndtr: RefCell::new(None),
 | 
					                next_ndtr: RefCell::new(None),
 | 
				
			||||||
                tcif: false,
 | 
					                complete_count: 0,
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -264,12 +247,14 @@ mod tests {
 | 
				
			|||||||
            self.next_ndtr.borrow_mut().unwrap()
 | 
					            self.next_ndtr.borrow_mut().unwrap()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fn tcif(&self) -> bool {
 | 
					        fn get_complete_count(&self) -> usize {
 | 
				
			||||||
            self.tcif
 | 
					            self.complete_count
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fn clear_tcif(&mut self) {
 | 
					        fn reset_complete_count(&mut self) -> usize {
 | 
				
			||||||
            self.tcif = false;
 | 
					            let old = self.complete_count;
 | 
				
			||||||
 | 
					            self.complete_count = 0;
 | 
				
			||||||
 | 
					            old
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -320,7 +305,7 @@ mod tests {
 | 
				
			|||||||
        ringbuf.ndtr = 10;
 | 
					        ringbuf.ndtr = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // The dma controller has written 4 + 6 bytes and has reloaded NDTR
 | 
					        // The dma controller has written 4 + 6 bytes and has reloaded NDTR
 | 
				
			||||||
        ctrl.tcif = true;
 | 
					        ctrl.complete_count = 1;
 | 
				
			||||||
        ctrl.set_next_ndtr(10);
 | 
					        ctrl.set_next_ndtr(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert!(!ringbuf.is_empty());
 | 
					        assert!(!ringbuf.is_empty());
 | 
				
			||||||
@@ -346,14 +331,14 @@ mod tests {
 | 
				
			|||||||
        ringbuf.ndtr = 6;
 | 
					        ringbuf.ndtr = 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // The dma controller has written 6 + 2 bytes and has reloaded NDTR
 | 
					        // The dma controller has written 6 + 2 bytes and has reloaded NDTR
 | 
				
			||||||
        ctrl.tcif = true;
 | 
					        ctrl.complete_count = 1;
 | 
				
			||||||
        ctrl.set_next_ndtr(14);
 | 
					        ctrl.set_next_ndtr(14);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut buf = [0; 2];
 | 
					        let mut buf = [0; 2];
 | 
				
			||||||
        assert_eq!(2, ringbuf.read(&mut ctrl, &mut buf).unwrap());
 | 
					        assert_eq!(2, ringbuf.read(&mut ctrl, &mut buf).unwrap());
 | 
				
			||||||
        assert_eq!([2, 3], buf);
 | 
					        assert_eq!([2, 3], buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(true, ctrl.tcif); // The interrupt flag IS NOT cleared
 | 
					        assert_eq!(1, ctrl.complete_count); // The interrupt flag IS NOT cleared
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
@@ -365,14 +350,14 @@ mod tests {
 | 
				
			|||||||
        ringbuf.ndtr = 10;
 | 
					        ringbuf.ndtr = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // The dma controller has written 6 + 2 bytes and has reloaded NDTR
 | 
					        // The dma controller has written 6 + 2 bytes and has reloaded NDTR
 | 
				
			||||||
        ctrl.tcif = true;
 | 
					        ctrl.complete_count = 1;
 | 
				
			||||||
        ctrl.set_next_ndtr(14);
 | 
					        ctrl.set_next_ndtr(14);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut buf = [0; 10];
 | 
					        let mut buf = [0; 10];
 | 
				
			||||||
        assert_eq!(10, ringbuf.read(&mut ctrl, &mut buf).unwrap());
 | 
					        assert_eq!(10, ringbuf.read(&mut ctrl, &mut buf).unwrap());
 | 
				
			||||||
        assert_eq!([12, 13, 14, 15, 0, 1, 2, 3, 4, 5], buf);
 | 
					        assert_eq!([12, 13, 14, 15, 0, 1, 2, 3, 4, 5], buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(false, ctrl.tcif); // The interrupt flag IS cleared
 | 
					        assert_eq!(0, ctrl.complete_count); // The interrupt flag IS cleared
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
@@ -387,12 +372,12 @@ mod tests {
 | 
				
			|||||||
        assert!(ringbuf.is_empty()); // The ring buffer thinks that it is empty
 | 
					        assert!(ringbuf.is_empty()); // The ring buffer thinks that it is empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // The dma controller has written exactly 16 bytes
 | 
					        // The dma controller has written exactly 16 bytes
 | 
				
			||||||
        ctrl.tcif = true;
 | 
					        ctrl.complete_count = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut buf = [0; 2];
 | 
					        let mut buf = [0; 2];
 | 
				
			||||||
        assert_eq!(Err(OverrunError), ringbuf.read(&mut ctrl, &mut buf));
 | 
					        assert_eq!(Err(OverrunError), ringbuf.read(&mut ctrl, &mut buf));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(false, ctrl.tcif); // The interrupt flag IS cleared
 | 
					        assert_eq!(1, ctrl.complete_count); // The complete counter is not reset
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
@@ -404,13 +389,13 @@ mod tests {
 | 
				
			|||||||
        ringbuf.ndtr = 6;
 | 
					        ringbuf.ndtr = 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // The dma controller has written 6 + 3 bytes and has reloaded NDTR
 | 
					        // The dma controller has written 6 + 3 bytes and has reloaded NDTR
 | 
				
			||||||
        ctrl.tcif = true;
 | 
					        ctrl.complete_count = 1;
 | 
				
			||||||
        ctrl.set_next_ndtr(13);
 | 
					        ctrl.set_next_ndtr(13);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut buf = [0; 2];
 | 
					        let mut buf = [0; 2];
 | 
				
			||||||
        assert_eq!(Err(OverrunError), ringbuf.read(&mut ctrl, &mut buf));
 | 
					        assert_eq!(Err(OverrunError), ringbuf.read(&mut ctrl, &mut buf));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(false, ctrl.tcif); // The interrupt flag IS cleared
 | 
					        assert_eq!(1, ctrl.complete_count); // The complete counter is not reset
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
@@ -422,12 +407,12 @@ mod tests {
 | 
				
			|||||||
        ringbuf.ndtr = 10;
 | 
					        ringbuf.ndtr = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // The dma controller has written 6 + 13 bytes and has reloaded NDTR
 | 
					        // The dma controller has written 6 + 13 bytes and has reloaded NDTR
 | 
				
			||||||
        ctrl.tcif = true;
 | 
					        ctrl.complete_count = 1;
 | 
				
			||||||
        ctrl.set_next_ndtr(3);
 | 
					        ctrl.set_next_ndtr(3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut buf = [0; 2];
 | 
					        let mut buf = [0; 2];
 | 
				
			||||||
        assert_eq!(Err(OverrunError), ringbuf.read(&mut ctrl, &mut buf));
 | 
					        assert_eq!(Err(OverrunError), ringbuf.read(&mut ctrl, &mut buf));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_eq!(false, ctrl.tcif); // The interrupt flag IS cleared
 | 
					        assert_eq!(1, ctrl.complete_count); // The complete counter is not reset
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,8 +4,9 @@ use core::task::Poll;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use embassy_hal_common::drop::OnDrop;
 | 
					use embassy_hal_common::drop::OnDrop;
 | 
				
			||||||
use embassy_hal_common::PeripheralRef;
 | 
					use embassy_hal_common::PeripheralRef;
 | 
				
			||||||
 | 
					use futures::future::{select, Either};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{rdr, sr, BasicInstance, Error, UartRx};
 | 
					use super::{clear_interrupt_flags, rdr, sr, BasicInstance, Error, UartRx};
 | 
				
			||||||
use crate::dma::ringbuffer::OverrunError;
 | 
					use crate::dma::ringbuffer::OverrunError;
 | 
				
			||||||
use crate::dma::RingBuffer;
 | 
					use crate::dma::RingBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -98,7 +99,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Read bytes that are readily available in the ring buffer.
 | 
					    /// Read bytes that are readily available in the ring buffer.
 | 
				
			||||||
    /// If no bytes are currently available in the buffer the call waits until data are received.
 | 
					    /// If no bytes are currently available in the buffer the call waits until the some
 | 
				
			||||||
 | 
					    /// bytes are available (at least one byte and at most half the buffer size)
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Background receive is started if `start()` has not been previously called.
 | 
					    /// Background receive is started if `start()` has not been previously called.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
@@ -107,10 +109,9 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
 | 
				
			|||||||
    pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
 | 
					    pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
 | 
				
			||||||
        let r = T::regs();
 | 
					        let r = T::regs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Start background receive if it was not already started
 | 
				
			||||||
        // SAFETY: read only
 | 
					        // SAFETY: read only
 | 
				
			||||||
        let is_started = unsafe { r.cr3().read().dmar() };
 | 
					        let is_started = unsafe { r.cr3().read().dmar() };
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Start background receive if it was not already started
 | 
					 | 
				
			||||||
        if !is_started {
 | 
					        if !is_started {
 | 
				
			||||||
            self.start()?;
 | 
					            self.start()?;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -132,8 +133,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let ndtr = self.ring_buf.get_remaining_transfers();
 | 
					        self.ring_buf.reload_position();
 | 
				
			||||||
        self.ring_buf.set_ndtr(ndtr);
 | 
					 | 
				
			||||||
        match self.ring_buf.read(buf) {
 | 
					        match self.ring_buf.read(buf) {
 | 
				
			||||||
            Ok(len) if len == 0 => {}
 | 
					            Ok(len) if len == 0 => {}
 | 
				
			||||||
            Ok(len) => {
 | 
					            Ok(len) => {
 | 
				
			||||||
@@ -148,28 +148,32 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Wait for any data since `ndtr`
 | 
					        loop {
 | 
				
			||||||
        self.wait_for_data(ndtr).await?;
 | 
					            self.wait_for_data_or_idle().await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.ring_buf.reload_position();
 | 
				
			||||||
 | 
					            if !self.ring_buf.is_empty() {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // ndtr is now different than the value provided to `wait_for_data()`
 | 
					 | 
				
			||||||
        // Re-sample ndtr now when it has changed.
 | 
					 | 
				
			||||||
        self.ring_buf.set_ndtr(self.ring_buf.get_remaining_transfers());
 | 
					 | 
				
			||||||
        let len = self.ring_buf.read(buf).map_err(|_err| Error::Overrun)?;
 | 
					        let len = self.ring_buf.read(buf).map_err(|_err| Error::Overrun)?;
 | 
				
			||||||
        assert!(len > 0);
 | 
					        assert!(len > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(len)
 | 
					        Ok(len)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Wait for uart data
 | 
					    /// Wait for uart idle or dma half-full or full
 | 
				
			||||||
    async fn wait_for_data(&mut self, old_ndtr: usize) -> Result<(), Error> {
 | 
					    async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> {
 | 
				
			||||||
        let r = T::regs();
 | 
					        let r = T::regs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // make sure USART state is restored to neutral state when this future is dropped
 | 
					        // make sure USART state is restored to neutral state
 | 
				
			||||||
        let _drop = OnDrop::new(move || {
 | 
					        let _on_drop = OnDrop::new(move || {
 | 
				
			||||||
            // SAFETY: only clears Rx related flags
 | 
					            // SAFETY: only clears Rx related flags
 | 
				
			||||||
            unsafe {
 | 
					            unsafe {
 | 
				
			||||||
                r.cr1().modify(|w| {
 | 
					                r.cr1().modify(|w| {
 | 
				
			||||||
                    // disable RXNE interrupt
 | 
					                    // disable idle line interrupt
 | 
				
			||||||
                    w.set_rxneie(false);
 | 
					                    w.set_idleie(false);
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@@ -177,76 +181,65 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
 | 
				
			|||||||
        // SAFETY: only sets Rx related flags
 | 
					        // SAFETY: only sets Rx related flags
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            r.cr1().modify(|w| {
 | 
					            r.cr1().modify(|w| {
 | 
				
			||||||
                // enable RXNE interrupt
 | 
					                // enable idle line interrupt
 | 
				
			||||||
                w.set_rxneie(true);
 | 
					                w.set_idleie(true);
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // future which completes when RX "not empty" is detected,
 | 
					        compiler_fence(Ordering::SeqCst);
 | 
				
			||||||
        // i.e. when there is data in uart rx register
 | 
					 | 
				
			||||||
        let rxne = poll_fn(|cx| {
 | 
					 | 
				
			||||||
            let s = T::state();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Register waker to be awaken when RXNE interrupt is received
 | 
					        // Future which completes when there is dma is half full or full
 | 
				
			||||||
 | 
					        let dma = poll_fn(|cx| {
 | 
				
			||||||
 | 
					            self.ring_buf.set_waker(cx.waker());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            compiler_fence(Ordering::SeqCst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.ring_buf.reload_position();
 | 
				
			||||||
 | 
					            if !self.ring_buf.is_empty() {
 | 
				
			||||||
 | 
					                // Some data is now available
 | 
				
			||||||
 | 
					                Poll::Ready(())
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Poll::Pending
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Future which completes when idle line is detected
 | 
				
			||||||
 | 
					        let uart = poll_fn(|cx| {
 | 
				
			||||||
 | 
					            let s = T::state();
 | 
				
			||||||
            s.rx_waker.register(cx.waker());
 | 
					            s.rx_waker.register(cx.waker());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            compiler_fence(Ordering::SeqCst);
 | 
					            compiler_fence(Ordering::SeqCst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // SAFETY: read only and we only use Rx related flags
 | 
					            // SAFETY: read only and we only use Rx related flags
 | 
				
			||||||
            let s = unsafe { sr(r).read() };
 | 
					            let sr = unsafe { sr(r).read() };
 | 
				
			||||||
            let has_errors = s.pe() || s.fe() || s.ne() || s.ore();
 | 
					
 | 
				
			||||||
 | 
					            let has_errors = sr.pe() || sr.fe() || sr.ne() || sr.ore();
 | 
				
			||||||
            if has_errors {
 | 
					            if has_errors {
 | 
				
			||||||
                if s.pe() {
 | 
					                if sr.pe() {
 | 
				
			||||||
                    return Poll::Ready(Err(Error::Parity));
 | 
					                    return Poll::Ready(Err(Error::Parity));
 | 
				
			||||||
                } else if s.fe() {
 | 
					                } else if sr.fe() {
 | 
				
			||||||
                    return Poll::Ready(Err(Error::Framing));
 | 
					                    return Poll::Ready(Err(Error::Framing));
 | 
				
			||||||
                } else if s.ne() {
 | 
					                } else if sr.ne() {
 | 
				
			||||||
                    return Poll::Ready(Err(Error::Noise));
 | 
					                    return Poll::Ready(Err(Error::Noise));
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    return Poll::Ready(Err(Error::Overrun));
 | 
					                    return Poll::Ready(Err(Error::Overrun));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Re-sample ndtr and determine if it has changed since we started
 | 
					            if sr.idle() {
 | 
				
			||||||
            // waiting for data.
 | 
					                // Idle line is detected
 | 
				
			||||||
            let new_ndtr = self.ring_buf.get_remaining_transfers();
 | 
					 | 
				
			||||||
            if new_ndtr != old_ndtr {
 | 
					 | 
				
			||||||
                // Some data was received as NDTR has changed
 | 
					 | 
				
			||||||
                Poll::Ready(Ok(()))
 | 
					                Poll::Ready(Ok(()))
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                // It may be that the DMA controller is currently busy consuming the
 | 
					                Poll::Pending
 | 
				
			||||||
                // RX data register. We therefore wait register to become empty.
 | 
					 | 
				
			||||||
                while unsafe { sr(r).read().rxne() } {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                compiler_fence(Ordering::SeqCst);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Re-get again: This time we know that the DMA controller has consumed
 | 
					 | 
				
			||||||
                // the current read register if it was busy doing so
 | 
					 | 
				
			||||||
                let new_ndtr = self.ring_buf.get_remaining_transfers();
 | 
					 | 
				
			||||||
                if new_ndtr != old_ndtr {
 | 
					 | 
				
			||||||
                    // Some data was received as NDTR has changed
 | 
					 | 
				
			||||||
                    Poll::Ready(Ok(()))
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    Poll::Pending
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        compiler_fence(Ordering::SeqCst);
 | 
					        match select(dma, uart).await {
 | 
				
			||||||
 | 
					            Either::Left(((), _)) => Ok(()),
 | 
				
			||||||
        let new_ndtr = self.ring_buf.get_remaining_transfers();
 | 
					            Either::Right((Ok(()), _)) => Ok(()),
 | 
				
			||||||
        if new_ndtr != old_ndtr {
 | 
					            Either::Right((Err(e), _)) => {
 | 
				
			||||||
            // Fast path - NDTR has already changed, no reason to poll
 | 
					                self.teardown_uart();
 | 
				
			||||||
            Ok(())
 | 
					                Err(e)
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            // NDTR has not changed since we first read from the ring buffer
 | 
					 | 
				
			||||||
            // Wait for RXNE interrupt...
 | 
					 | 
				
			||||||
            match rxne.await {
 | 
					 | 
				
			||||||
                Ok(()) => Ok(()),
 | 
					 | 
				
			||||||
                Err(e) => {
 | 
					 | 
				
			||||||
                    self.teardown_uart();
 | 
					 | 
				
			||||||
                    Err(e)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,7 @@ mod board {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ONE_BYTE_DURATION_US: u32 = 9_000_000 / 115200;
 | 
					const ONE_BYTE_DURATION_US: u32 = 9_000_000 / 115200;
 | 
				
			||||||
 | 
					const DMA_BUF_SIZE: usize = 64;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[embassy_executor::main]
 | 
					#[embassy_executor::main]
 | 
				
			||||||
async fn main(spawner: Spawner) {
 | 
					async fn main(spawner: Spawner) {
 | 
				
			||||||
@@ -114,7 +115,7 @@ async fn main(spawner: Spawner) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config);
 | 
					    let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config);
 | 
				
			||||||
    let (tx, rx) = usart.split();
 | 
					    let (tx, rx) = usart.split();
 | 
				
			||||||
    static mut DMA_BUF: [u8; 64] = [0; 64];
 | 
					    static mut DMA_BUF: [u8; DMA_BUF_SIZE] = [0; DMA_BUF_SIZE];
 | 
				
			||||||
    let dma_buf = unsafe { DMA_BUF.as_mut() };
 | 
					    let dma_buf = unsafe { DMA_BUF.as_mut() };
 | 
				
			||||||
    let rx = rx.into_ring_buffered(dma_buf);
 | 
					    let rx = rx.into_ring_buffered(dma_buf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -159,7 +160,14 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx
 | 
				
			|||||||
    loop {
 | 
					    loop {
 | 
				
			||||||
        let mut buf = [0; 100];
 | 
					        let mut buf = [0; 100];
 | 
				
			||||||
        let max_len = 1 + (rng.next_u32() as usize % (buf.len() - 1));
 | 
					        let max_len = 1 + (rng.next_u32() as usize % (buf.len() - 1));
 | 
				
			||||||
        let received = rx.read(&mut buf[..max_len]).await.unwrap();
 | 
					        let received = match rx.read(&mut buf[..max_len]).await {
 | 
				
			||||||
 | 
					            Ok(r) => r,
 | 
				
			||||||
 | 
					            Err(e) => {
 | 
				
			||||||
 | 
					                error!("Test fail! read error: {:?}", e);
 | 
				
			||||||
 | 
					                cortex_m::asm::bkpt();
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if expected.is_none() {
 | 
					        if expected.is_none() {
 | 
				
			||||||
            info!("Test started");
 | 
					            info!("Test started");
 | 
				
			||||||
@@ -176,8 +184,11 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if received < max_len {
 | 
					        if received < max_len {
 | 
				
			||||||
            let byte_count = rng.next_u32() % 64;
 | 
					            let byte_count = rng.next_u32() % (DMA_BUF_SIZE as u32);
 | 
				
			||||||
            Timer::after(Duration::from_micros((byte_count * ONE_BYTE_DURATION_US) as _)).await;
 | 
					            let random_delay_us = (byte_count * ONE_BYTE_DURATION_US) as u64;
 | 
				
			||||||
 | 
					            if random_delay_us > 200 {
 | 
				
			||||||
 | 
					                Timer::after(Duration::from_micros(random_delay_us - 200)).await;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        i += 1;
 | 
					        i += 1;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,19 @@
 | 
				
			|||||||
use std::path::Path;
 | 
					use std::path::Path;
 | 
				
			||||||
use std::time::Duration;
 | 
					use std::time::Duration;
 | 
				
			||||||
use std::{env, io, thread};
 | 
					use std::{env, io, process, thread};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use rand::random;
 | 
					use rand::random;
 | 
				
			||||||
use serial::SerialPort;
 | 
					use serial::SerialPort;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn main() {
 | 
					pub fn main() {
 | 
				
			||||||
    if let Some(port_name) = env::args().nth(1) {
 | 
					    if let Some(port_name) = env::args().nth(1) {
 | 
				
			||||||
        let sleep = env::args().position(|x| x == "--sleep").is_some();
 | 
					        let idles = env::args().position(|x| x == "--idles").is_some();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        println!("Saturating port {:?} with 115200 8N1", port_name);
 | 
					        println!("Saturating port {:?} with 115200 8N1", port_name);
 | 
				
			||||||
        println!("Sleep: {}", sleep);
 | 
					        println!("Idles: {}", idles);
 | 
				
			||||||
 | 
					        println!("Process ID: {}", process::id());
 | 
				
			||||||
        let mut port = serial::open(&port_name).unwrap();
 | 
					        let mut port = serial::open(&port_name).unwrap();
 | 
				
			||||||
        if saturate(&mut port, sleep).is_err() {
 | 
					        if saturate(&mut port, idles).is_err() {
 | 
				
			||||||
            eprintln!("Unable to saturate port");
 | 
					            eprintln!("Unable to saturate port");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@@ -23,7 +24,7 @@ pub fn main() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn saturate<T: SerialPort>(port: &mut T, sleep: bool) -> io::Result<()> {
 | 
					fn saturate<T: SerialPort>(port: &mut T, idles: bool) -> io::Result<()> {
 | 
				
			||||||
    port.reconfigure(&|settings| {
 | 
					    port.reconfigure(&|settings| {
 | 
				
			||||||
        settings.set_baud_rate(serial::Baud115200)?;
 | 
					        settings.set_baud_rate(serial::Baud115200)?;
 | 
				
			||||||
        settings.set_char_size(serial::Bits8);
 | 
					        settings.set_char_size(serial::Bits8);
 | 
				
			||||||
@@ -39,7 +40,7 @@ fn saturate<T: SerialPort>(port: &mut T, sleep: bool) -> io::Result<()> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        port.write_all(&buf)?;
 | 
					        port.write_all(&buf)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if sleep {
 | 
					        if idles {
 | 
				
			||||||
            let micros = (random::<usize>() % 1000) as u64;
 | 
					            let micros = (random::<usize>() % 1000) as u64;
 | 
				
			||||||
            println!("Sleeping {}us", micros);
 | 
					            println!("Sleeping {}us", micros);
 | 
				
			||||||
            port.flush().unwrap();
 | 
					            port.flush().unwrap();
 | 
				
			||||||
@@ -49,4 +50,4 @@ fn saturate<T: SerialPort>(port: &mut T, sleep: bool) -> io::Result<()> {
 | 
				
			|||||||
        written += len;
 | 
					        written += len;
 | 
				
			||||||
        println!("Written: {}", written);
 | 
					        println!("Written: {}", written);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user