diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-06-01 12:15:19 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-06-01 12:15:19 +0000 |
| commit | fc4139146f27f0b5b53dc0de40db910ecce461c2 (patch) | |
| tree | 2865f9d58e84fdca4066f05bfe2efa33cc3c2d7c /embassy-stm32/src | |
| parent | a2fdce88bd982d1a844ad1ff625f3fb6a7b0a2f0 (diff) | |
| parent | ca5fe2645dd5a969052081ab855aa88520198e12 (diff) | |
Merge pull request #4251 from kpfleming/improve-stm32-ringbuffereduart-docs
stm32: Expand documentation of RingBufferedUartRx.
Diffstat (limited to 'embassy-stm32/src')
| -rw-r--r-- | embassy-stm32/src/usart/ringbuffered.rs | 79 |
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. | ||
| 21 | pub struct RingBufferedUartRx<'d> { | 80 | pub 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 | ||
