Merge pull request #2324 from barnabywalters/stm32-usart-docs

stm32: Documented usart public API
This commit is contained in:
Dario Nieuwenhuis 2023-12-19 16:58:27 +01:00 committed by GitHub
commit 7ec1ed4de3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 6 deletions

View File

@ -82,6 +82,7 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
} }
} }
/// Buffered UART State
pub struct State { pub struct State {
rx_waker: AtomicWaker, rx_waker: AtomicWaker,
rx_buf: RingBuffer, rx_buf: RingBuffer,
@ -91,6 +92,7 @@ pub struct State {
} }
impl State { impl State {
/// Create new state
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
rx_buf: RingBuffer::new(), rx_buf: RingBuffer::new(),
@ -101,15 +103,18 @@ impl State {
} }
} }
/// Bidirectional buffered UART
pub struct BufferedUart<'d, T: BasicInstance> { pub struct BufferedUart<'d, T: BasicInstance> {
rx: BufferedUartRx<'d, T>, rx: BufferedUartRx<'d, T>,
tx: BufferedUartTx<'d, T>, tx: BufferedUartTx<'d, T>,
} }
/// Tx-only buffered UART
pub struct BufferedUartTx<'d, T: BasicInstance> { pub struct BufferedUartTx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
} }
/// Rx-only buffered UART
pub struct BufferedUartRx<'d, T: BasicInstance> { pub struct BufferedUartRx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>, 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> { impl<'d, T: BasicInstance> BufferedUart<'d, T> {
/// Create a new bidirectional buffered UART driver
pub fn new( pub fn new(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -158,6 +164,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 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( pub fn new_with_rtscts(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -185,6 +192,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 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)))] #[cfg(not(any(usart_v1, usart_v2)))]
pub fn new_with_de( pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + '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>) { pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
(self.tx, self.rx) (self.tx, self.rx)
} }
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)?; reconfigure::<T>(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> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)?; reconfigure::<T>(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> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)?; reconfigure::<T>(config)?;

View File

@ -1,5 +1,6 @@
//! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART) //! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART)
#![macro_use] #![macro_use]
#![warn(missing_docs)]
use core::future::poll_fn; use core::future::poll_fn;
use core::marker::PhantomData; use core::marker::PhantomData;
@ -77,21 +78,29 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Number of data bits
pub enum DataBits { pub enum DataBits {
/// 8 Data Bits
DataBits8, DataBits8,
/// 9 Data Bits
DataBits9, DataBits9,
} }
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Parity
pub enum Parity { pub enum Parity {
/// No parity
ParityNone, ParityNone,
/// Even Parity
ParityEven, ParityEven,
/// Odd Parity
ParityOdd, ParityOdd,
} }
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Number of stop bits
pub enum StopBits { pub enum StopBits {
#[doc = "1 stop bit"] #[doc = "1 stop bit"]
STOP1, STOP1,
@ -106,26 +115,37 @@ pub enum StopBits {
#[non_exhaustive] #[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Config Error
pub enum ConfigError { pub enum ConfigError {
/// Baudrate too low
BaudrateTooLow, BaudrateTooLow,
/// Baudrate too high
BaudrateTooHigh, BaudrateTooHigh,
/// Rx or Tx not enabled
RxOrTxNotEnabled, RxOrTxNotEnabled,
} }
#[non_exhaustive] #[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
/// Config
pub struct Config { pub struct Config {
/// Baud rate
pub baudrate: u32, pub baudrate: u32,
/// Number of data bits
pub data_bits: DataBits, pub data_bits: DataBits,
/// Number of stop bits
pub stop_bits: StopBits, pub stop_bits: StopBits,
/// Parity type
pub parity: Parity, 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 true: on a read-like method, if there is a latent error pending,
/// if false, the error is ignored and cleared /// 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, pub detect_previous_overrun: bool,
/// Set this to true if the line is considered noise free. /// Set this to true if the line is considered noise free.
/// This will increase the receivers tolerance to clock deviations, /// This will increase the receivers tolerance to clock deviations,
/// but will effectively disable noise detection. /// but will effectively disable noise detection.
#[cfg(not(usart_v1))] #[cfg(not(usart_v1))]
pub assume_noise_free: bool, pub assume_noise_free: bool,
@ -188,6 +208,7 @@ enum ReadCompletionEvent {
Idle(usize), Idle(usize),
} }
/// Bidirectional UART Driver
pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
tx: UartTx<'d, T, TxDma>, tx: UartTx<'d, T, TxDma>,
rx: UartRx<'d, T, RxDma>, 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> { pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
tx_dma: PeripheralRef<'d, TxDma>, 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> { pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
rx_dma: PeripheralRef<'d, RxDma>, 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) 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( pub fn new_with_cts(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd, tx: impl Peripheral<P = impl TxPin<T>> + '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> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config) reconfigure::<T>(config)
} }
/// Initiate an asynchronous UART write
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
where where
TxDma: crate::usart::TxDma<T>, TxDma: crate::usart::TxDma<T>,
@ -308,6 +334,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
Ok(()) Ok(())
} }
/// Perform a blocking UART write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
for &b in buffer { for &b in buffer {
@ -317,6 +344,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
Ok(()) Ok(())
} }
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> { pub fn blocking_flush(&mut self) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
while !sr(r).read().tc() {} 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) 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( pub fn new_with_rts(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + '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> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config) reconfigure::<T>(config)
} }
@ -444,6 +474,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Ok(sr.rxne()) Ok(sr.rxne())
} }
/// Initiate an asynchronous UART read
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
where where
RxDma: crate::usart::RxDma<T>, RxDma: crate::usart::RxDma<T>,
@ -453,6 +484,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Ok(()) Ok(())
} }
/// Read a single u8 if there is one available, otherwise return WouldBlock
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
let r = T::regs(); let r = T::regs();
if self.check_rx_flags()? { 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> { pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
for b in buffer { for b in buffer {
@ -471,6 +504,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Ok(()) Ok(())
} }
/// Initiate an asynchronous read with idle line detection enabled
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
where where
RxDma: crate::usart::RxDma<T>, RxDma: crate::usart::RxDma<T>,
@ -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> { impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
/// Create a new bidirectional UART
pub fn new( pub fn new(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + '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) 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( pub fn new_with_rtscts(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -738,6 +774,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
} }
#[cfg(not(any(usart_v1, usart_v2)))] #[cfg(not(any(usart_v1, usart_v2)))]
/// Create a new bidirectional UART with a driver-enable pin
pub fn new_with_de( pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + '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> pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
where where
TxDma: crate::usart::TxDma<T>, TxDma: crate::usart::TxDma<T>,
@ -820,14 +858,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
self.tx.write(buffer).await self.tx.write(buffer).await
} }
/// Perform a blocking write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.blocking_write(buffer) self.tx.blocking_write(buffer)
} }
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> { pub fn blocking_flush(&mut self) -> Result<(), Error> {
self.tx.blocking_flush() self.tx.blocking_flush()
} }
/// Initiate an asynchronous read into `buffer`
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
where where
RxDma: crate::usart::RxDma<T>, RxDma: crate::usart::RxDma<T>,
@ -835,14 +876,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
self.rx.read(buffer).await self.rx.read(buffer).await
} }
/// Read a single `u8` or return `WouldBlock`
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
self.rx.nb_read() self.rx.nb_read()
} }
/// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.blocking_read(buffer) 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<usize, Error> pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
where where
RxDma: crate::usart::RxDma<T>, RxDma: crate::usart::RxDma<T>,
@ -1292,8 +1336,10 @@ pub(crate) mod sealed {
} }
} }
/// Basic UART driver instance
pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {}
/// Full UART driver instance
pub trait FullInstance: sealed::FullInstance {} pub trait FullInstance: sealed::FullInstance {}
pin_trait!(RxPin, BasicInstance); pin_trait!(RxPin, BasicInstance);

View File

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