aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-06-01 12:15:19 +0000
committerGitHub <[email protected]>2025-06-01 12:15:19 +0000
commitfc4139146f27f0b5b53dc0de40db910ecce461c2 (patch)
tree2865f9d58e84fdca4066f05bfe2efa33cc3c2d7c
parenta2fdce88bd982d1a844ad1ff625f3fb6a7b0a2f0 (diff)
parentca5fe2645dd5a969052081ab855aa88520198e12 (diff)
Merge pull request #4251 from kpfleming/improve-stm32-ringbuffereduart-docs
stm32: Expand documentation of RingBufferedUartRx.
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs79
1 files changed, 71 insertions, 8 deletions
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index eaa9424c5..1d4a44896 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -18,6 +18,65 @@ use crate::Peri;
18/// Rx-only Ring-buffered UART Driver 18/// Rx-only Ring-buffered UART Driver
19/// 19///
20/// Created with [UartRx::into_ring_buffered] 20/// Created with [UartRx::into_ring_buffered]
21///
22/// ### Notes on 'waiting for bytes'
23///
24/// The `read(buf)` (but not `read()`) and `read_exact(buf)` functions
25/// may need to wait for bytes to arrive, if the ring buffer does not
26/// contain enough bytes to fill the buffer passed by the caller of
27/// the function, or is empty.
28///
29/// Waiting for bytes operates in one of two modes, depending on
30/// the behavior of the sender and the size of the buffer passed
31/// to the function:
32///
33/// - If the sender sends intermittently, the 'idle line'
34/// condition will be detected when the sender stops, and any
35/// bytes in the ring buffer will be returned. If there are no
36/// bytes in the buffer, the check will be repeated each time the
37/// 'idle line' condition is detected, so if the sender sends just
38/// a single byte, it will be returned once the 'idle line'
39/// condition is detected.
40///
41/// - If the sender sends continuously, the call will wait until
42/// the DMA controller indicates that it has written to either the
43/// middle byte or last byte of the ring buffer ('half transfer'
44/// or 'transfer complete', respectively). This does not indicate
45/// the buffer is half-full or full, though, because the DMA
46/// controller does not detect those conditions; it sends an
47/// interrupt when those specific buffer addresses have been
48/// written.
49///
50/// In both cases this will result in variable latency due to the
51/// buffering effect. For example, if the baudrate is 2400 bps, and
52/// the configuration is 8 data bits, no parity bit, and one stop bit,
53/// then a byte will be received every ~4.16ms. If the ring buffer is
54/// 32 bytes, then a 'wait for bytes' delay may have to wait for 16
55/// bytes in the worst case, resulting in a delay (latency) of
56/// ~62.46ms for the first byte in the ring buffer. If the sender
57/// sends only 6 bytes and then stops, but the buffer was empty when
58/// the read function was called, then those bytes may not be returned
59/// until ~24.96ms after the first byte was received (time for 5
60/// additional bytes plus the 'idle frame' which triggers the 'idle
61/// line' condition).
62///
63/// Applications subject to this latency must be careful if they
64/// also apply timeouts during reception, as it may appear (to
65/// them) that the sender has stopped sending when it did not. In
66/// the example above, a 50ms timeout (12 bytes at 2400bps) might
67/// seem to be reasonable to detect that the sender has stopped
68/// sending, but would be falsely triggered in the worst-case
69/// buffer delay scenario.
70///
71/// Note: This latency is caused by the limited capabilities of the
72/// STM32 DMA controller; since it cannot generate an interrupt when
73/// it stores a byte into an empty ring buffer, or in any other
74/// configurable conditions, it is not possible to take notice of the
75/// contents of the ring buffer more quickly without introducing
76/// polling. As a result the latency can be reduced by calling the
77/// read functions repeatedly with smaller buffers to receive the
78/// available bytes, as each call to a read function will explicitly
79/// check the ring buffer for available bytes.
21pub struct RingBufferedUartRx<'d> { 80pub struct RingBufferedUartRx<'d> {
22 info: &'static Info, 81 info: &'static Info,
23 state: &'static State, 82 state: &'static State,
@@ -79,7 +138,8 @@ impl<'d> RingBufferedUartRx<'d> {
79 138
80 /// Configure and start the DMA backed UART receiver 139 /// Configure and start the DMA backed UART receiver
81 /// 140 ///
82 /// Note: This is also done automatically by [`read()`] if required. 141 /// Note: This is also done automatically by the read functions if
142 /// required.
83 pub fn start_uart(&mut self) { 143 pub fn start_uart(&mut self) {
84 // Clear the buffer so that it is ready to receive data 144 // Clear the buffer so that it is ready to receive data
85 compiler_fence(Ordering::SeqCst); 145 compiler_fence(Ordering::SeqCst);
@@ -139,14 +199,16 @@ impl<'d> RingBufferedUartRx<'d> {
139 Ok(()) 199 Ok(())
140 } 200 }
141 201
142 /// Read bytes that are readily available in the ring buffer. 202 /// Read bytes that are available in the ring buffer, or wait for
143 /// If no bytes are currently available in the buffer the call waits until the some 203 /// bytes to become available and return them.
144 /// bytes are available (at least one byte and at most half the buffer size)
145 /// 204 ///
146 /// Background receive is started if `start()` has not been previously called. 205 /// Background reception is started if necessary (if `start_uart()` had
206 /// not previously been called, or if an error was detected which
207 /// caused background reception to be stopped).
147 /// 208 ///
148 /// Receive in the background is terminated if an error is returned. 209 /// Background reception is terminated when an error is returned.
149 /// It must then manually be started again by calling `start()` or by re-calling `read()`. 210 /// It must be started again by calling `start_uart()` or by
211 /// calling a read function again.
150 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 212 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
151 self.start_dma_or_check_errors()?; 213 self.start_dma_or_check_errors()?;
152 214
@@ -202,7 +264,8 @@ impl<'d> RingBufferedUartRx<'d> {
202 }); 264 });
203 265
204 let mut dma_init = false; 266 let mut dma_init = false;
205 // Future which completes when there is dma is half full or full 267 // Future which completes when the DMA controller indicates it
268 // has written to the ring buffer's middle byte, or last byte
206 let dma = poll_fn(|cx| { 269 let dma = poll_fn(|cx| {
207 self.ring_buf.set_waker(cx.waker()); 270 self.ring_buf.set_waker(cx.waker());
208 271