From 5d696f6d0d2bf84dbf17d5b372f557acbeb1e9ba Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Tue, 19 Dec 2023 16:41:00 +0100 Subject: [PATCH] Documented usart public API --- .vscode/settings.json | 6 +-- embassy-stm32/src/usart/buffered.rs | 12 ++++++ embassy-stm32/src/usart/mod.rs | 54 +++++++++++++++++++++++-- embassy-stm32/src/usart/ringbuffered.rs | 7 +++- 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d46ce603..016df796 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,12 +17,12 @@ //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", "rust-analyzer.cargo.features": [ // Uncomment if the example has a "nightly" feature. - "nightly", + //"nightly", ], "rust-analyzer.linkedProjects": [ // Uncomment ONE line for the chip you want to work on. // This makes rust-analyzer work on the example crate and all its dependencies. - "examples/nrf52840/Cargo.toml", + //"examples/nrf52840/Cargo.toml", // "examples/nrf52840-rtic/Cargo.toml", // "examples/nrf5340/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", @@ -39,7 +39,7 @@ // "examples/stm32g0/Cargo.toml", // "examples/stm32g4/Cargo.toml", // "examples/stm32h5/Cargo.toml", - // "examples/stm32h7/Cargo.toml", + "examples/stm32h7/Cargo.toml", // "examples/stm32l0/Cargo.toml", // "examples/stm32l1/Cargo.toml", // "examples/stm32l4/Cargo.toml", diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index a2e4ceaa..962547bd 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -82,6 +82,7 @@ impl interrupt::typelevel::Handler for Interrupt } } +/// Buffered UART State pub struct State { rx_waker: AtomicWaker, rx_buf: RingBuffer, @@ -91,6 +92,7 @@ pub struct State { } impl State { + /// Create new state pub const fn new() -> Self { Self { rx_buf: RingBuffer::new(), @@ -101,15 +103,18 @@ impl State { } } +/// Bidirectional buffered UART pub struct BufferedUart<'d, T: BasicInstance> { rx: BufferedUartRx<'d, T>, tx: BufferedUartTx<'d, T>, } +/// Tx-only buffered UART pub struct BufferedUartTx<'d, T: BasicInstance> { phantom: PhantomData<&'d mut T>, } +/// Rx-only buffered UART pub struct BufferedUartRx<'d, T: BasicInstance> { phantom: PhantomData<&'d mut T>, } @@ -142,6 +147,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> { } impl<'d, T: BasicInstance> BufferedUart<'d, T> { + /// Create a new bidirectional buffered UART driver pub fn new( peri: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -158,6 +164,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) } + /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins pub fn new_with_rtscts( peri: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -185,6 +192,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) } + /// Create a new bidirectional buffered UART driver with a driver-enable pin #[cfg(not(any(usart_v1, usart_v2)))] pub fn new_with_de( peri: impl Peripheral

+ 'd, @@ -246,10 +254,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { }) } + /// Split the driver into a Tx and Rx part (useful for sending to separate tasks) pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { (self.tx, self.rx) } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config)?; @@ -337,6 +347,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { } } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config)?; @@ -418,6 +429,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { } } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config)?; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index e2e3bd3e..8a0c85d2 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,5 +1,6 @@ //! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART) #![macro_use] +#![warn(missing_docs)] use core::future::poll_fn; use core::marker::PhantomData; @@ -77,21 +78,29 @@ impl interrupt::typelevel::Handler for Interrupt #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Number of data bits pub enum DataBits { + /// 8 Data Bits DataBits8, + /// 9 Data Bits DataBits9, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Parity pub enum Parity { + /// No parity ParityNone, + /// Even Parity ParityEven, + /// Odd Parity ParityOdd, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Number of stop bits pub enum StopBits { #[doc = "1 stop bit"] STOP1, @@ -106,26 +115,37 @@ pub enum StopBits { #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Config Error pub enum ConfigError { + /// Baudrate too low BaudrateTooLow, + /// Baudrate too high BaudrateTooHigh, + /// Rx or Tx not enabled RxOrTxNotEnabled, } #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] +/// Config pub struct Config { + /// Baud rate pub baudrate: u32, + /// Number of data bits pub data_bits: DataBits, + /// Number of stop bits pub stop_bits: StopBits, + /// Parity type pub parity: Parity, - /// if true, on read-like method, if there is a latent error pending, - /// read will abort, the error reported and cleared - /// if false, the error is ignored and cleared + + /// If true: on a read-like method, if there is a latent error pending, + /// the read will abort and the error will be reported and cleared + /// + /// If false: the error is ignored and cleared pub detect_previous_overrun: bool, /// Set this to true if the line is considered noise free. - /// This will increase the receivers tolerance to clock deviations, + /// This will increase the receiver’s tolerance to clock deviations, /// but will effectively disable noise detection. #[cfg(not(usart_v1))] pub assume_noise_free: bool, @@ -188,6 +208,7 @@ enum ReadCompletionEvent { Idle(usize), } +/// Bidirectional UART Driver pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { tx: UartTx<'d, T, TxDma>, rx: UartRx<'d, T, RxDma>, @@ -203,6 +224,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma> } } +/// Tx-only UART Driver pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { phantom: PhantomData<&'d mut T>, tx_dma: PeripheralRef<'d, TxDma>, @@ -217,6 +239,7 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> { } } +/// Rx-only UART Driver pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { _peri: PeripheralRef<'d, T>, rx_dma: PeripheralRef<'d, RxDma>, @@ -247,6 +270,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { Self::new_inner(peri, tx, tx_dma, config) } + /// Create a new tx-only UART with a clear-to-send pin pub fn new_with_cts( peri: impl Peripheral

+ 'd, tx: impl Peripheral

> + 'd, @@ -288,10 +312,12 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { }) } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } + /// Initiate an asynchronous UART write pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> where TxDma: crate::usart::TxDma, @@ -308,6 +334,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { Ok(()) } + /// Perform a blocking UART write pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { let r = T::regs(); for &b in buffer { @@ -317,6 +344,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { Ok(()) } + /// Block until transmission complete pub fn blocking_flush(&mut self) -> Result<(), Error> { let r = T::regs(); while !sr(r).read().tc() {} @@ -338,6 +366,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { Self::new_inner(peri, rx, rx_dma, config) } + /// Create a new rx-only UART with a request-to-send pin pub fn new_with_rts( peri: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -387,6 +416,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { }) } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -444,6 +474,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { Ok(sr.rxne()) } + /// Initiate an asynchronous UART read pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> where RxDma: crate::usart::RxDma, @@ -453,6 +484,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { Ok(()) } + /// Read a single u8 if there is one available, otherwise return WouldBlock pub fn nb_read(&mut self) -> Result> { let r = T::regs(); if self.check_rx_flags()? { @@ -462,6 +494,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { } } + /// Perform a blocking read into `buffer` pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { let r = T::regs(); for b in buffer { @@ -471,6 +504,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { Ok(()) } + /// Initiate an asynchronous read with idle line detection enabled pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result where RxDma: crate::usart::RxDma, @@ -695,6 +729,7 @@ impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> { } impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { + /// Create a new bidirectional UART pub fn new( peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, @@ -711,6 +746,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) } + /// Create a new bidirectional UART with request-to-send and clear-to-send pins pub fn new_with_rtscts( peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, @@ -738,6 +774,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } #[cfg(not(any(usart_v1, usart_v2)))] + /// Create a new bidirectional UART with a driver-enable pin pub fn new_with_de( peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, @@ -813,6 +850,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { }) } + /// Initiate an asynchronous write pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> where TxDma: crate::usart::TxDma, @@ -820,14 +858,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { self.tx.write(buffer).await } + /// Perform a blocking write pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { self.tx.blocking_write(buffer) } + /// Block until transmission complete pub fn blocking_flush(&mut self) -> Result<(), Error> { self.tx.blocking_flush() } + /// Initiate an asynchronous read into `buffer` pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> where RxDma: crate::usart::RxDma, @@ -835,14 +876,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { self.rx.read(buffer).await } + /// Read a single `u8` or return `WouldBlock` pub fn nb_read(&mut self) -> Result> { self.rx.nb_read() } + /// Perform a blocking read into `buffer` pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.rx.blocking_read(buffer) } + /// Initiate an an asynchronous read with idle line detection enabled pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result where RxDma: crate::usart::RxDma, @@ -1292,8 +1336,10 @@ pub(crate) mod sealed { } } +/// Basic UART driver instance pub trait BasicInstance: Peripheral

+ sealed::BasicInstance + 'static + Send {} +/// Full UART driver instance pub trait FullInstance: sealed::FullInstance {} pin_trait!(RxPin, BasicInstance); diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index f8ada392..4391bfef 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -11,6 +11,7 @@ use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config, use crate::dma::ReadableRingBuffer; use crate::usart::{Regs, Sr}; +/// Rx-only Ring-buffered UART Driver pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma> { _peri: PeripheralRef<'d, T>, ring_buf: ReadableRingBuffer<'d, RxDma, u8>, @@ -27,8 +28,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> SetConfig for RingBufferedUar impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { /// Turn the `UartRx` into a buffered uart which can continously receive in the background - /// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the - /// DMA controller, and must be sufficiently large, such that it will not overflow. + /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the + /// DMA controller, and must be large enough to prevent overflows. pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); @@ -49,6 +50,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> UartRx<'d, T, RxDma> { } impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxDma> { + /// Clear the ring buffer and start receiving in the background pub fn start(&mut self) -> Result<(), Error> { // Clear the ring buffer so that it is ready to receive data self.ring_buf.clear(); @@ -64,6 +66,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD Err(err) } + /// Cleanly stop and reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { self.teardown_uart(); reconfigure::(config)