aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-hal-internal/src/atomic_ring_buffer.rs22
-rw-r--r--embassy-stm32/src/usart/buffered.rs28
-rw-r--r--embassy-stm32/src/usart/mod.rs37
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs30
4 files changed, 77 insertions, 40 deletions
diff --git a/embassy-hal-internal/src/atomic_ring_buffer.rs b/embassy-hal-internal/src/atomic_ring_buffer.rs
index 7de96e4e2..8c3889b85 100644
--- a/embassy-hal-internal/src/atomic_ring_buffer.rs
+++ b/embassy-hal-internal/src/atomic_ring_buffer.rs
@@ -133,6 +133,18 @@ impl RingBuffer {
133 self.len.load(Ordering::Relaxed) 133 self.len.load(Ordering::Relaxed)
134 } 134 }
135 135
136 /// Return number of items available to read.
137 pub fn available(&self) -> usize {
138 let end = self.end.load(Ordering::Relaxed);
139 let len = self.len.load(Ordering::Relaxed);
140 let start = self.start.load(Ordering::Relaxed);
141 if end >= start {
142 end - start
143 } else {
144 2 * len - start + end
145 }
146 }
147
136 /// Check if buffer is full. 148 /// Check if buffer is full.
137 pub fn is_full(&self) -> bool { 149 pub fn is_full(&self) -> bool {
138 let len = self.len.load(Ordering::Relaxed); 150 let len = self.len.load(Ordering::Relaxed);
@@ -144,15 +156,7 @@ impl RingBuffer {
144 156
145 /// Check if buffer is at least half full. 157 /// Check if buffer is at least half full.
146 pub fn is_half_full(&self) -> bool { 158 pub fn is_half_full(&self) -> bool {
147 let len = self.len.load(Ordering::Relaxed); 159 self.available() >= self.len.load(Ordering::Relaxed) / 2
148 let start = self.start.load(Ordering::Relaxed);
149 let end = self.end.load(Ordering::Relaxed);
150 let n = if end >= start {
151 end - start
152 } else {
153 2 * len - start + end
154 };
155 n >= len / 2
156 } 160 }
157 161
158 /// Check if buffer is empty. 162 /// Check if buffer is empty.
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 165f2e88e..10dc02334 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,7 +1,7 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::slice; 3use core::slice;
4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
@@ -68,8 +68,9 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full. 68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full.
69 } 69 }
70 70
71 if state.eager_reads.load(Ordering::Relaxed) { 71 let eager = state.eager_reads.load(Ordering::Relaxed);
72 if !state.rx_buf.is_empty() { 72 if eager > 0 {
73 if state.rx_buf.available() >= eager {
73 state.rx_waker.wake(); 74 state.rx_waker.wake();
74 } 75 }
75 } else { 76 } else {
@@ -138,7 +139,7 @@ pub(super) struct State {
138 tx_done: AtomicBool, 139 tx_done: AtomicBool,
139 tx_rx_refcount: AtomicU8, 140 tx_rx_refcount: AtomicU8,
140 half_duplex_readback: AtomicBool, 141 half_duplex_readback: AtomicBool,
141 eager_reads: AtomicBool, 142 eager_reads: AtomicUsize,
142} 143}
143 144
144impl State { 145impl State {
@@ -151,7 +152,7 @@ impl State {
151 tx_done: AtomicBool::new(true), 152 tx_done: AtomicBool::new(true),
152 tx_rx_refcount: AtomicU8::new(0), 153 tx_rx_refcount: AtomicU8::new(0),
153 half_duplex_readback: AtomicBool::new(false), 154 half_duplex_readback: AtomicBool::new(false),
154 eager_reads: AtomicBool::new(false), 155 eager_reads: AtomicUsize::new(0),
155 } 156 }
156 } 157 }
157} 158}
@@ -427,7 +428,9 @@ impl<'d> BufferedUart<'d> {
427 let state = T::buffered_state(); 428 let state = T::buffered_state();
428 let kernel_clock = T::frequency(); 429 let kernel_clock = T::frequency();
429 430
430 state.eager_reads.store(config.eager_reads, Ordering::Relaxed); 431 state
432 .eager_reads
433 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
431 state.half_duplex_readback.store( 434 state.half_duplex_readback.store(
432 config.duplex == Duplex::Half(HalfDuplexReadback::Readback), 435 config.duplex == Duplex::Half(HalfDuplexReadback::Readback),
433 Ordering::Relaxed, 436 Ordering::Relaxed,
@@ -465,7 +468,9 @@ impl<'d> BufferedUart<'d> {
465 let info = self.rx.info; 468 let info = self.rx.info;
466 let state = self.rx.state; 469 let state = self.rx.state;
467 state.tx_rx_refcount.store(2, Ordering::Relaxed); 470 state.tx_rx_refcount.store(2, Ordering::Relaxed);
468 state.eager_reads.store(config.eager_reads, Ordering::Relaxed); 471 state
472 .eager_reads
473 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
469 474
470 info.rcc.enable_and_reset(); 475 info.rcc.enable_and_reset();
471 476
@@ -537,7 +542,10 @@ impl<'d> BufferedUart<'d> {
537 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 542 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
538 reconfigure(self.rx.info, self.rx.kernel_clock, config)?; 543 reconfigure(self.rx.info, self.rx.kernel_clock, config)?;
539 544
540 self.rx.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); 545 self.rx
546 .state
547 .eager_reads
548 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
541 549
542 self.rx.info.regs.cr1().modify(|w| { 550 self.rx.info.regs.cr1().modify(|w| {
543 w.set_rxneie(true); 551 w.set_rxneie(true);
@@ -654,7 +662,9 @@ impl<'d> BufferedUartRx<'d> {
654 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 662 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
655 reconfigure(self.info, self.kernel_clock, config)?; 663 reconfigure(self.info, self.kernel_clock, config)?;
656 664
657 self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); 665 self.state
666 .eager_reads
667 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
658 668
659 self.info.regs.cr1().modify(|w| { 669 self.info.regs.cr1().modify(|w| {
660 w.set_rxneie(true); 670 w.set_rxneie(true);
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index c8012a9b4..0d2d86aca 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -4,7 +4,7 @@
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, Ordering}; 7use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
@@ -212,17 +212,20 @@ pub struct Config {
212 /// If false: the error is ignored and cleared 212 /// If false: the error is ignored and cleared
213 pub detect_previous_overrun: bool, 213 pub detect_previous_overrun: bool,
214 214
215 /// If true then read-like calls on `BufferedUartRx` and `RingBufferedUartRx` 215 /// If `None` (the default) then read-like calls on `BufferedUartRx` and `RingBufferedUartRx`
216 /// are woken/return as soon as any data is available in the buffer. 216 /// typically only wake/return after line idle or after the buffer is at least half full
217 /// (for `BufferedUartRx`) or the DMA buffer is written at the half or full positions
218 /// (for `RingBufferedUartRx`), though it may also wake/return earlier in some circumstances.
217 /// 219 ///
218 /// If false (the default) then reads started typically only wake/return after 220 /// If `Some(n)` then such reads are also woken/return as soon as at least `n` words are
219 /// line idle or after the buffer is at least half full (`BufferedUartRx`) or 221 /// available in the buffer, in addition to waking/returning when the conditions described
220 /// the DMA buffer is written at the half or full positions (`RingBufferedUartRx`), 222 /// above are met. `Some(0)` is treated as `None`. Setting this for `RingBufferedUartRx`
221 /// though it may also wake/return earlier in some circumstances. 223 /// will trigger an interrupt for every received word to check the buffer level, which may
224 /// impact performance at high data rates.
222 /// 225 ///
223 /// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either 226 /// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either
224 /// return a single word, a full buffer, or after line idle. 227 /// return a single word, a full buffer, or after line idle.
225 pub eager_reads: bool, 228 pub eager_reads: Option<usize>,
226 229
227 /// Set this to true if the line is considered noise free. 230 /// Set this to true if the line is considered noise free.
228 /// This will increase the receiver’s tolerance to clock deviations, 231 /// This will increase the receiver’s tolerance to clock deviations,
@@ -296,7 +299,7 @@ impl Default for Config {
296 parity: Parity::ParityNone, 299 parity: Parity::ParityNone,
297 // historical behavior 300 // historical behavior
298 detect_previous_overrun: false, 301 detect_previous_overrun: false,
299 eager_reads: false, 302 eager_reads: None,
300 #[cfg(not(usart_v1))] 303 #[cfg(not(usart_v1))]
301 assume_noise_free: false, 304 assume_noise_free: false,
302 #[cfg(any(usart_v3, usart_v4))] 305 #[cfg(any(usart_v3, usart_v4))]
@@ -997,7 +1000,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
997 let info = self.info; 1000 let info = self.info;
998 let state = self.state; 1001 let state = self.state;
999 state.tx_rx_refcount.store(1, Ordering::Relaxed); 1002 state.tx_rx_refcount.store(1, Ordering::Relaxed);
1000 state.eager_reads.store(config.eager_reads, Ordering::Relaxed); 1003 state
1004 .eager_reads
1005 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
1001 1006
1002 info.rcc.enable_and_reset(); 1007 info.rcc.enable_and_reset();
1003 1008
@@ -1014,7 +1019,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
1014 1019
1015 /// Reconfigure the driver 1020 /// Reconfigure the driver
1016 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 1021 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1017 self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); 1022 self.state
1023 .eager_reads
1024 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
1018 reconfigure(self.info, self.kernel_clock, config) 1025 reconfigure(self.info, self.kernel_clock, config)
1019 } 1026 }
1020 1027
@@ -1495,7 +1502,9 @@ impl<'d, M: Mode> Uart<'d, M> {
1495 let info = self.rx.info; 1502 let info = self.rx.info;
1496 let state = self.rx.state; 1503 let state = self.rx.state;
1497 state.tx_rx_refcount.store(2, Ordering::Relaxed); 1504 state.tx_rx_refcount.store(2, Ordering::Relaxed);
1498 state.eager_reads.store(config.eager_reads, Ordering::Relaxed); 1505 state
1506 .eager_reads
1507 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
1499 1508
1500 info.rcc.enable_and_reset(); 1509 info.rcc.enable_and_reset();
1501 1510
@@ -2080,7 +2089,7 @@ struct State {
2080 rx_waker: AtomicWaker, 2089 rx_waker: AtomicWaker,
2081 tx_waker: AtomicWaker, 2090 tx_waker: AtomicWaker,
2082 tx_rx_refcount: AtomicU8, 2091 tx_rx_refcount: AtomicU8,
2083 eager_reads: AtomicBool, 2092 eager_reads: AtomicUsize,
2084} 2093}
2085 2094
2086impl State { 2095impl State {
@@ -2089,7 +2098,7 @@ impl State {
2089 rx_waker: AtomicWaker::new(), 2098 rx_waker: AtomicWaker::new(),
2090 tx_waker: AtomicWaker::new(), 2099 tx_waker: AtomicWaker::new(),
2091 tx_rx_refcount: AtomicU8::new(0), 2100 tx_rx_refcount: AtomicU8::new(0),
2092 eager_reads: AtomicBool::new(false), 2101 eager_reads: AtomicUsize::new(0),
2093 } 2102 }
2094 } 2103 }
2095} 2104}
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index d818e0bcc..27071fb31 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -132,7 +132,9 @@ impl<'d> UartRx<'d, Async> {
132impl<'d> RingBufferedUartRx<'d> { 132impl<'d> RingBufferedUartRx<'d> {
133 /// Reconfigure the driver 133 /// Reconfigure the driver
134 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 134 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
135 self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed); 135 self.state
136 .eager_reads
137 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
136 reconfigure(self.info, self.kernel_clock, config) 138 reconfigure(self.info, self.kernel_clock, config)
137 } 139 }
138 140
@@ -149,7 +151,7 @@ impl<'d> RingBufferedUartRx<'d> {
149 // clear all interrupts and DMA Rx Request 151 // clear all interrupts and DMA Rx Request
150 r.cr1().modify(|w| { 152 r.cr1().modify(|w| {
151 // use RXNE only when returning reads early 153 // use RXNE only when returning reads early
152 w.set_rxneie(self.state.eager_reads.load(Ordering::Relaxed)); 154 w.set_rxneie(self.state.eager_reads.load(Ordering::Relaxed) > 0);
153 // enable parity interrupt if not ParityNone 155 // enable parity interrupt if not ParityNone
154 w.set_peie(w.pce()); 156 w.set_peie(w.pce());
155 // enable idle line interrupt 157 // enable idle line interrupt
@@ -261,11 +263,12 @@ impl<'d> RingBufferedUartRx<'d> {
261 // However, DMA will clear RXNE, so we can't check directly, and because 263 // However, DMA will clear RXNE, so we can't check directly, and because
262 // the other future borrows `ring_buf`, we can't check `len()` here either. 264 // the other future borrows `ring_buf`, we can't check `len()` here either.
263 // Instead, return from this future and we'll check the length afterwards. 265 // Instead, return from this future and we'll check the length afterwards.
264 let eager = s.eager_reads.load(Ordering::Relaxed); 266 let eager = s.eager_reads.load(Ordering::Relaxed) > 0;
265 267
266 if check_idle_and_errors(self.info.regs)? || (eager && uart_init) { 268 let idle = check_idle_and_errors(self.info.regs)?;
269 if idle || (eager && uart_init) {
267 // Idle line is detected, or eager reads is set and some data is available. 270 // Idle line is detected, or eager reads is set and some data is available.
268 Poll::Ready(Ok(())) 271 Poll::Ready(Ok(idle))
269 } else { 272 } else {
270 uart_init = true; 273 uart_init = true;
271 Poll::Pending 274 Poll::Pending
@@ -288,13 +291,24 @@ impl<'d> RingBufferedUartRx<'d> {
288 }); 291 });
289 292
290 match select(uart, dma).await { 293 match select(uart, dma).await {
291 Either::Left((result, _)) => { 294 // UART woke with line idle
292 if self.ring_buf.len().unwrap_or(0) > 0 || result.is_err() { 295 Either::Left((Ok(true), _)) => {
293 return result; 296 return Ok(());
297 }
298 // UART woke without idle or error: word received
299 Either::Left((Ok(false), _)) => {
300 let eager = self.state.eager_reads.load(Ordering::Relaxed);
301 if eager > 0 && self.ring_buf.len().unwrap_or(0) >= eager {
302 return Ok(());
294 } else { 303 } else {
295 continue; 304 continue;
296 } 305 }
297 } 306 }
307 // UART woke with error
308 Either::Left((Err(e), _)) => {
309 return Err(e);
310 }
311 // DMA woke
298 Either::Right(((), _)) => return Ok(()), 312 Either::Right(((), _)) => return Ok(()),
299 } 313 }
300 } 314 }