aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin P. Fleming <[email protected]>2025-05-24 16:39:25 -0400
committerKevin P. Fleming <[email protected]>2025-05-24 16:39:25 -0400
commit2ed5e04fd0fa216502c20ec4571a4b553bb86f1f (patch)
treefea84f3b99b5f813fd9b4d7b635b8833faf87bbb
parent94f9b2707486ca3eade5bf4b237edf3d6aa90f35 (diff)
stm32: Expand documentation of RingBufferedUartRx.
Explain to users of this driver how 'waiting for bytes' actually works, and what that may mean for latency introduced in their application. Also correct references to 'start' to be 'start_uart'.
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs73
1 files changed, 65 insertions, 8 deletions
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index eaa9424c5..9280dbd18 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -79,7 +79,7 @@ impl<'d> RingBufferedUartRx<'d> {
79 79
80 /// Configure and start the DMA backed UART receiver 80 /// Configure and start the DMA backed UART receiver
81 /// 81 ///
82 /// Note: This is also done automatically by [`read()`] if required. 82 /// Note: This is also done automatically by `read()` if required.
83 pub fn start_uart(&mut self) { 83 pub fn start_uart(&mut self) {
84 // Clear the buffer so that it is ready to receive data 84 // Clear the buffer so that it is ready to receive data
85 compiler_fence(Ordering::SeqCst); 85 compiler_fence(Ordering::SeqCst);
@@ -139,14 +139,70 @@ impl<'d> RingBufferedUartRx<'d> {
139 Ok(()) 139 Ok(())
140 } 140 }
141 141
142 /// Read bytes that are readily available in the ring buffer. 142 /// 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 143 /// bytes to become available and return them.
144 /// bytes are available (at least one byte and at most half the buffer size)
145 /// 144 ///
146 /// Background receive is started if `start()` has not been previously called. 145 /// Background reception is started if necessary (if `start_uart()` had
146 /// not previously been called, or if an error was detected which
147 /// caused background reception to be stopped).
147 /// 148 ///
148 /// Receive in the background is terminated if an error is returned. 149 /// 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()`. 150 /// It must be started again by calling `start_uart()` or by
151 /// calling `read()` again.
152 ///
153 /// ### Notes on 'waiting for bytes'
154 ///
155 /// Waiting for bytes operates in one of two modes, depending on
156 /// the behavior of the sender and the size of the buffer passed
157 /// to `read()`:
158 ///
159 /// - If the sender sends intermittently, the 'idle line'
160 /// condition will be detected when the sender stops, and any
161 /// bytes in the ring buffer will be returned. If there are no
162 /// bytes in the buffer, the check will be repeated each time the
163 /// 'idle line' condition is detected, so if the sender sends just
164 /// a single byte, it will be returned once the 'idle line'
165 /// condition is detected.
166 ///
167 /// - If the sender sends continuously, the call will wait until
168 /// the DMA controller indicates that it has written to either the
169 /// middle byte or last byte of the ring buffer ('half transfer'
170 /// or 'transfer complete', respectively). This does not indicate
171 /// the buffer is half-full or full, though, because the DMA
172 /// controller does not detect those conditions; it sends an
173 /// interrupt when those specific buffer addresses have been
174 /// written.
175 ///
176 /// In both cases this will result in variable latency due to the
177 /// buffering effect. For example, if the baudrate is 2400 bps,
178 /// and the configuration is 8 data bits, no parity bit, and one
179 /// stop bit, then a byte will be received every ~4.16ms. If the
180 /// ring buffer is 32 bytes, then a 'wait for bytes' delay may
181 /// have to wait for 16 bytes in the worst case, resulting in a
182 /// delay (latency) of ~62.46ms for the first byte in the ring
183 /// buffer. If the sender sends only 6 bytes and then stops, but
184 /// the buffer was empty when `read()` was called, then those
185 /// bytes may not be returned until ~24.96ms after the first byte
186 /// was received (time for 5 additional bytes plus the 'idle
187 /// frame' which triggers the 'idle line' condition).
188 ///
189 /// Applications subject to this latency must be careful if they
190 /// also apply timeouts during reception, as it may appear (to
191 /// them) that the sender has stopped sending when it did not. In
192 /// the example above, a 50ms timeout (12 bytes at 2400bps) might
193 /// seem to be reasonable to detect that the sender has stopped
194 /// sending, but would be falsely triggered in the worst-case
195 /// buffer delay scenario.
196 ///
197 /// Note: This latency is caused by the limited capabilities of
198 /// the STM32 DMA controller; since it cannot generate an
199 /// interrupt when it stores a byte into an empty ring buffer, or
200 /// in any other configurable conditions, it is not possible to
201 /// take notice of the contents of the ring buffer more quickly
202 /// without introducing polling. As a result the latency can be
203 /// reduced by calling `read()` repeatedly with smaller buffers to
204 /// receive the available bytes, as each call to `read()` will
205 /// explicitly check the ring buffer for available bytes.
150 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 206 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
151 self.start_dma_or_check_errors()?; 207 self.start_dma_or_check_errors()?;
152 208
@@ -202,7 +258,8 @@ impl<'d> RingBufferedUartRx<'d> {
202 }); 258 });
203 259
204 let mut dma_init = false; 260 let mut dma_init = false;
205 // Future which completes when there is dma is half full or full 261 // Future which completes when the DMA controller indicates it
262 // has written to the ring buffer's middle byte, or last byte
206 let dma = poll_fn(|cx| { 263 let dma = poll_fn(|cx| {
207 self.ring_buf.set_waker(cx.waker()); 264 self.ring_buf.set_waker(cx.waker());
208 265