Skip to content

Commit 785d526

Browse files
committed
STM32: USART: Change eager_reads from bool to Option<usize>
1 parent d384400 commit 785d526

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))]
@@ -997,7 +998,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
997998
let info = self.info;
998999
let state = self.state;
9991000
state.tx_rx_refcount.store(1, Ordering::Relaxed);
1000-
state.eager_reads.store(config.eager_reads, Ordering::Relaxed);
1001+
state
1002+
.eager_reads
1003+
.store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
10011004

10021005
info.rcc.enable_and_reset();
10031006

@@ -1014,7 +1017,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
10141017

10151018
/// Reconfigure the driver
10161019
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1017-
self.state.eager_reads.store(config.eager_reads, Ordering::Relaxed);
1020+
self.state
1021+
.eager_reads
1022+
.store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
10181023
reconfigure(self.info, self.kernel_clock, config)
10191024
}
10201025

@@ -1495,7 +1500,9 @@ impl<'d, M: Mode> Uart<'d, M> {
14951500
let info = self.rx.info;
14961501
let state = self.rx.state;
14971502
state.tx_rx_refcount.store(2, Ordering::Relaxed);
1498-
state.eager_reads.store(config.eager_reads, Ordering::Relaxed);
1503+
state
1504+
.eager_reads
1505+
.store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
14991506

15001507
info.rcc.enable_and_reset();
15011508

@@ -2080,7 +2087,7 @@ struct State {
20802087
rx_waker: AtomicWaker,
20812088
tx_waker: AtomicWaker,
20822089
tx_rx_refcount: AtomicU8,
2083-
eager_reads: AtomicBool,
2090+
eager_reads: AtomicUsize,
20842091
}
20852092

20862093
impl State {
@@ -2089,7 +2096,7 @@ impl State {
20892096
rx_waker: AtomicWaker::new(),
20902097
tx_waker: AtomicWaker::new(),
20912098
tx_rx_refcount: AtomicU8::new(0),
2092-
eager_reads: AtomicBool::new(false),
2099+
eager_reads: AtomicUsize::new(0),
20932100
}
20942101
}
20952102
}

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)