aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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