Skip to content

Commit 1ba5580

Browse files
committed
STM32: USART: Change eager_reads from bool to Option<usize>
1 parent 3205bf3 commit 1ba5580

File tree

3 files changed

+62
-31
lines changed

3 files changed

+62
-31
lines changed

embassy-stm32/src/usart/buffered.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::future::poll_fn;
22
use core::marker::PhantomData;
33
use core::slice;
4-
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
4+
use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
55
use core::task::Poll;
66

77
use embassy_embedded_hal::SetConfig;
@@ -68,8 +68,9 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
6868
// FIXME: Should we disable any further RX interrupts when the buffer becomes full.
6969
}
7070

71-
if state.eager_reads.load(Ordering::Relaxed) {
72-
if !state.rx_buf.is_empty() {
71+
let eager = state.eager_reads.load(Ordering::Relaxed);
72+
if eager > 0 {
73+
if state.rx_buf.len() >= eager {
7374
state.rx_waker.wake();
7475
}
7576
} else {
@@ -138,7 +139,7 @@ pub(super) struct State {
138139
tx_done: AtomicBool,
139140
tx_rx_refcount: AtomicU8,
140141
half_duplex_readback: AtomicBool,
141-
eager_reads: AtomicBool,
142+
eager_reads: AtomicUsize,
142143
}
143144

144145
impl State {
@@ -151,7 +152,7 @@ impl State {
151152
tx_done: AtomicBool::new(true),
152153
tx_rx_refcount: AtomicU8::new(0),
153154
half_duplex_readback: AtomicBool::new(false),
154-
eager_reads: AtomicBool::new(false),
155+
eager_reads: AtomicUsize::new(0),
155156
}
156157
}
157158
}
@@ -427,7 +428,9 @@ impl<'d> BufferedUart<'d> {
427428
let state = T::buffered_state();
428429
let kernel_clock = T::frequency();
429430

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);
431434
state.half_duplex_readback.store(
432435
config.duplex == Duplex::Half(HalfDuplexReadback::Readback),
433436
Ordering::Relaxed,
@@ -465,7 +468,9 @@ impl<'d> BufferedUart<'d> {
465468
let info = self.rx.info;
466469
let state = self.rx.state;
467470
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);
469474

470475
info.rcc.enable_and_reset();
471476

@@ -537,7 +542,10 @@ impl<'d> BufferedUart<'d> {
537542
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
538543
reconfigure(self.rx.info, self.rx.kernel_clock, config)?;
539544

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);
541549

542550
self.rx.info.regs.cr1().modify(|w| {
543551
w.set_rxneie(true);
@@ -654,7 +662,9 @@ impl<'d> BufferedUartRx<'d> {
654662
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
655663
reconfigure(self.info, self.kernel_clock, config)?;
656664

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);
658668

659669
self.info.regs.cr1().modify(|w| {
660670
w.set_rxneie(true);

embassy-stm32/src/usart/mod.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use core::future::poll_fn;
66
use core::marker::PhantomData;
7-
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, Ordering};
7+
use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
88
use core::task::Poll;
99

1010
use embassy_embedded_hal::SetConfig;
@@ -212,17 +212,18 @@ pub struct Config {
212212
/// If false: the error is ignored and cleared
213213
pub detect_previous_overrun: bool,
214214

215-
/// If true then read-like calls on `BufferedUartRx` and `RingBufferedUartRx`
216-
/// are woken/return as soon as any data is available in the buffer.
215+
/// If `None` (the default) then read-like calls on `BufferedUartRx` and `RingBufferedUartRx`
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.
217219
///
218-
/// If false (the default) then reads started typically only wake/return after
219-
/// line idle or after the buffer is at least half full (`BufferedUartRx`) or
220-
/// the DMA buffer is written at the half or full positions (`RingBufferedUartRx`),
221-
/// though it may also wake/return earlier in some circumstances.
220+
/// If `Some(n)` then such reads are also woken/return as soon as at least `n` words are
221+
/// available in the buffer, in addition to waking/returning when the conditions described
222+
/// above are met. `Some(0)` is treated as `None`.
222223
///
223224
/// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either
224225
/// return a single word, a full buffer, or after line idle.
225-
pub eager_reads: bool,
226+
pub eager_reads: Option<usize>,
226227

227228
/// Set this to true if the line is considered noise free.
228229
/// This will increase the receiver’s tolerance to clock deviations,
@@ -296,7 +297,7 @@ impl Default for Config {
296297
parity: Parity::ParityNone,
297298
// historical behavior
298299
detect_previous_overrun: false,
299-
eager_reads: false,
300+
eager_reads: None,
300301
#[cfg(not(usart_v1))]
301302
assume_noise_free: false,
302303
#[cfg(any(usart_v3, usart_v4))]
@@ -995,7 +996,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
995996
let info = self.info;
996997
let state = self.state;
997998
state.tx_rx_refcount.store(1, Ordering::Relaxed);
998-
state.eager_reads.store(config.eager_reads, Ordering::Relaxed);
999+
state
1000+
.eager_reads
1001+
.store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
9991002

10001003
info.rcc.enable_and_reset();
10011004

@@ -1012,7 +1015,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
10121015

10131016
/// Reconfigure the driver
10141017
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1015-
self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed);
1018+
self.state
1019+
.eager_reads
1020+
.store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
10161021
reconfigure(self.info, self.kernel_clock, config)
10171022
}
10181023

@@ -1493,7 +1498,9 @@ impl<'d, M: Mode> Uart<'d, M> {
14931498
let info = self.rx.info;
14941499
let state = self.rx.state;
14951500
state.tx_rx_refcount.store(2, Ordering::Relaxed);
1496-
state.eager_reads.store(config.eager_reads, Ordering::Relaxed);
1501+
state
1502+
.eager_reads
1503+
.store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
14971504

14981505
info.rcc.enable_and_reset();
14991506

@@ -2078,7 +2085,7 @@ struct State {
20782085
rx_waker: AtomicWaker,
20792086
tx_waker: AtomicWaker,
20802087
tx_rx_refcount: AtomicU8,
2081-
eager_reads: AtomicBool,
2088+
eager_reads: AtomicUsize,
20822089
}
20832090

20842091
impl State {
@@ -2087,7 +2094,7 @@ impl State {
20872094
rx_waker: AtomicWaker::new(),
20882095
tx_waker: AtomicWaker::new(),
20892096
tx_rx_refcount: AtomicU8::new(0),
2090-
eager_reads: AtomicBool::new(false),
2097+
eager_reads: AtomicUsize::new(0),
20912098
}
20922099
}
20932100
}

embassy-stm32/src/usart/ringbuffered.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ impl<'d> UartRx<'d, Async> {
132132
impl<'d> RingBufferedUartRx<'d> {
133133
/// Reconfigure the driver
134134
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);
136138
reconfigure(self.info, self.kernel_clock, config)
137139
}
138140

@@ -149,7 +151,7 @@ impl<'d> RingBufferedUartRx<'d> {
149151
// clear all interrupts and DMA Rx Request
150152
r.cr1().modify(|w| {
151153
// 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);
153155
// enable parity interrupt if not ParityNone
154156
w.set_peie(w.pce());
155157
// enable idle line interrupt
@@ -261,11 +263,12 @@ impl<'d> RingBufferedUartRx<'d> {
261263
// However, DMA will clear RXNE, so we can't check directly, and because
262264
// the other future borrows `ring_buf`, we can't check `len()` here either.
263265
// 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;
265267

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) {
267270
// Idle line is detected, or eager reads is set and some data is available.
268-
Poll::Ready(Ok(()))
271+
Poll::Ready(Ok(idle))
269272
} else {
270273
uart_init = true;
271274
Poll::Pending
@@ -288,13 +291,24 @@ impl<'d> RingBufferedUartRx<'d> {
288291
});
289292

290293
match select(uart, dma).await {
291-
Either::Left((result, _)) => {
292-
if self.ring_buf.len().unwrap_or(0) > 0 || result.is_err() {
293-
return result;
294+
// UART woke with line idle
295+
Either::Left((Ok(true), _)) => {
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(());
294303
} else {
295304
continue;
296305
}
297306
}
307+
// UART woke with error
308+
Either::Left((Err(e), _)) => {
309+
return Err(e);
310+
}
311+
// DMA woke
298312
Either::Right(((), _)) => return Ok(()),
299313
}
300314
}

0 commit comments

Comments
 (0)