Update module documentation for UART driver, make some more methods public (#1347)

This commit is contained in:
Jesse Braham 2024-03-26 13:50:47 +00:00 committed by GitHub
parent f18e8ae33c
commit 65dca0025b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,18 +1,26 @@
//! # UART driver //! Universal Asynchronous Receiver/Transmitter (UART)
//! //!
//! ## Overview //! The UART is a hardware peripheral which handles communication using serial
//! In embedded system applications, data is required to be transferred in a //! communication interfaces, such as RS232 and RS485. This peripheral provides
//! simple way with minimal system resources. This can be achieved by a //! a cheap and ubiquitous method for full- and half-duplex communication
//! Universal Asynchronous Receiver/Transmitter (UART), which flexibly exchanges //! between devices.
//! data with other peripheral devices in full-duplex mode. //!
//! The UART driver provides an interface to communicate with UART peripherals //! Depending on your device, two or more UART controllers are available for
//! on ESP chips. It enables serial communication between the microcontroller //! use, all of which can be configured and used in the same way. All UART
//! and external devices using the UART protocol. //! controllers are compatible with UART-enabled devices from various
//! manufacturers, and can also support Infrared Data Association (IrDA)
//! protocols.
//!
//! ## Configuration
//!
//! Each UART controller is individually configurable, and the usual setting
//! such as baud rate, data bits, parity, and stop bits can easily be
//! configured. Additionally, the transmit (TX) and receive (RX) pins can be
//! specified.
//! //!
//! ## Example
//! ```no_run //! ```no_run
//! let config = Config { //! let config = Config {
//! baudrate: 115200, //! baudrate: 115_200,
//! data_bits: DataBits::DataBits8, //! data_bits: DataBits::DataBits8,
//! parity: Parity::ParityNone, //! parity: Parity::ParityNone,
//! stop_bits: StopBits::STOP1, //! stop_bits: StopBits::STOP1,
@ -24,23 +32,45 @@
//! io.pins.gpio2.into_floating_input(), //! io.pins.gpio2.into_floating_input(),
//! ); //! );
//! //!
//! let mut serial1 = Uart::new_with_config(peripherals.UART1, config, Some(pins), &clocks); //! let mut uart1 = Uart::new_with_config(peripherals.UART1, config, Some(pins), &clocks);
//!
//! timer0.start(250u64.millis());
//!
//! println!("Start");
//! loop {
//! serial1.write(0x42).ok();
//! let read = block!(serial1.read());
//!
//! match read {
//! Ok(read) => println!("Read 0x{:02x}", read),
//! Err(err) => println!("Error {:?}", err),
//! }
//!
//! block!(timer0.wait()).unwrap();
//! }
//! ``` //! ```
//!
//! ## Usage
//!
//! The UART driver implements a number of third-party traits, with the
//! intention of making the HAL inter-compatible with various device drivers
//! from the community. This includes, but is not limited to, the [embedded-hal]
//! and [embedded-io] blocking traits, and the [embedded-hal-async] and
//! [embedded-io-async] asynchronous traits.
//!
//! In addition to the interfaces provided by these traits, native APIs are also
//! available. See the examples below for more information on how to interact
//! with this driver.
//!
//! ### Examples
//!
//! #### Sending and Receiving Data
//!
//! ```no_run
//! // Write bytes out over the UART:
//! uart1.write_bytes("Hello, world!".as_bytes())?;
//! ```
//!
//! #### Splitting the UART into TX and RX Components
//!
//! ```no_run
//! // The UART can be split into separate Transmit and Receive components:
//! let (mut tx, rx) = uart1.split();
//!
//! // Each component can be used individually to interact with the UART:
//! tx.write_bytes(&[42u8])?;
//! let byte = rx.read_byte()?;
//! ```
//!
//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
//! [embedded-io]: https://docs.rs/embedded-io/latest/embedded_io/
//! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/
//! [embedded-io-async]: https://docs.rs/embedded-io-async/latest/embedded_io_async/
use core::marker::PhantomData; use core::marker::PhantomData;
@ -62,11 +92,13 @@ use crate::{
const CONSOLE_UART_NUM: usize = 0; const CONSOLE_UART_NUM: usize = 0;
const UART_FIFO_SIZE: u16 = 128; const UART_FIFO_SIZE: u16 = 128;
/// Custom serial error type /// UART Error
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
/// An invalid configuration argument was provided
InvalidArgument, InvalidArgument,
/// The RX FIFO overflowed
#[cfg(feature = "async")] #[cfg(feature = "async")]
RxFifoOvf, RxFifoOvf,
} }
@ -85,7 +117,7 @@ impl embedded_io::Error for Error {
} }
} }
/// UART configuration /// UART Configuration
pub mod config { pub mod config {
/// Number of data bits /// Number of data bits
#[derive(PartialEq, Eq, Copy, Clone, Debug)] #[derive(PartialEq, Eq, Copy, Clone, Debug)]
@ -118,7 +150,7 @@ pub mod config {
STOP2 = 3, STOP2 = 3,
} }
/// UART configuration /// UART Configuration
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Config { pub struct Config {
@ -229,7 +261,7 @@ pub trait UartPins {
); );
} }
/// All pins offered by UART /// All UART pins (TX, RX, CTS, RTS)
pub struct AllPins<'d, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> { pub struct AllPins<'d, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> {
pub(crate) tx: Option<PeripheralRef<'d, TX>>, pub(crate) tx: Option<PeripheralRef<'d, TX>>,
pub(crate) rx: Option<PeripheralRef<'d, RX>>, pub(crate) rx: Option<PeripheralRef<'d, RX>>,
@ -237,7 +269,6 @@ pub struct AllPins<'d, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPi
pub(crate) rts: Option<PeripheralRef<'d, RTS>>, pub(crate) rts: Option<PeripheralRef<'d, RTS>>,
} }
/// Tx and Rx pins
impl<'d, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> AllPins<'d, TX, RX, CTS, RTS> { impl<'d, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> AllPins<'d, TX, RX, CTS, RTS> {
pub fn new( pub fn new(
tx: impl Peripheral<P = TX> + 'd, tx: impl Peripheral<P = TX> + 'd,
@ -285,6 +316,7 @@ impl<TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> UartPins
} }
} }
/// TX and RX pins
pub struct TxRxPins<'d, TX: OutputPin, RX: InputPin> { pub struct TxRxPins<'d, TX: OutputPin, RX: InputPin> {
pub tx: Option<PeripheralRef<'d, TX>>, pub tx: Option<PeripheralRef<'d, TX>>,
pub rx: Option<PeripheralRef<'d, RX>>, pub rx: Option<PeripheralRef<'d, RX>>,
@ -322,7 +354,7 @@ impl<TX: OutputPin, RX: InputPin> UartPins for TxRxPins<'_, TX, RX> {
} }
} }
/// UART driver /// UART (Full-duplex)
pub struct Uart<'d, T, M> { pub struct Uart<'d, T, M> {
#[cfg(not(esp32))] #[cfg(not(esp32))]
symbol_len: u8, symbol_len: u8,
@ -330,12 +362,12 @@ pub struct Uart<'d, T, M> {
rx: UartRx<'d, T, M>, rx: UartRx<'d, T, M>,
} }
/// UART TX /// UART (Transmit)
pub struct UartTx<'d, T, M> { pub struct UartTx<'d, T, M> {
phantom: PhantomData<(&'d mut T, M)>, phantom: PhantomData<(&'d mut T, M)>,
} }
/// UART RX /// UART (Receive)
pub struct UartRx<'d, T, M> { pub struct UartRx<'d, T, M> {
phantom: PhantomData<(&'d mut T, M)>, phantom: PhantomData<(&'d mut T, M)>,
at_cmd_config: Option<config::AtCmdConfig>, at_cmd_config: Option<config::AtCmdConfig>,
@ -530,19 +562,20 @@ where
) )
} }
/// Split the Uart into a transmitter and receiver, which is /// Split the UART into a transmitter and receiver
/// particularly useful when having two tasks correlating to ///
/// This is particularly useful when having two tasks correlating to
/// transmitting and receiving. /// transmitting and receiving.
pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
(self.tx, self.rx) (self.tx, self.rx)
} }
/// Writes bytes /// Write bytes out over the UART
pub fn write_bytes(&mut self, data: &[u8]) -> Result<usize, Error> { pub fn write_bytes(&mut self, data: &[u8]) -> Result<usize, Error> {
self.tx.write_bytes(data) self.tx.write_bytes(data)
} }
/// Configures the AT-CMD detection settings. /// Configures the AT-CMD detection settings
#[allow(clippy::useless_conversion)] #[allow(clippy::useless_conversion)]
pub fn set_at_cmd(&mut self, config: config::AtCmdConfig) { pub fn set_at_cmd(&mut self, config: config::AtCmdConfig) {
#[cfg(not(any(esp32, esp32s2)))] #[cfg(not(any(esp32, esp32s2)))]
@ -590,14 +623,12 @@ where
/// `timeout` - the number of symbols ("bytes") to wait for before /// `timeout` - the number of symbols ("bytes") to wait for before
/// triggering a timeout. Pass None to disable the timeout. /// triggering a timeout. Pass None to disable the timeout.
/// ///
///
/// # Errors /// # Errors
/// `Err(Error::InvalidArgument)` if the provided value exceeds the maximum /// `Err(Error::InvalidArgument)` if the provided value exceeds the maximum
/// value for SOC : /// value for SOC :
/// - `esp32`: Symbol size is fixed to 8, do not pass a value > **0x7F**. /// - `esp32`: Symbol size is fixed to 8, do not pass a value > **0x7F**.
/// - `esp32c2`, `esp32c3`, `esp32c6`, `esp32h2`, esp32s2`, esp32s3`: The /// - `esp32c2`, `esp32c3`, `esp32c6`, `esp32h2`, esp32s2`, esp32s3`: The
/// value you pass times the symbol size must be <= **0x3FF** /// value you pass times the symbol size must be <= **0x3FF**
pub fn set_rx_timeout(&mut self, timeout: Option<u8>) -> Result<(), Error> { pub fn set_rx_timeout(&mut self, timeout: Option<u8>) -> Result<(), Error> {
#[cfg(esp32)] #[cfg(esp32)]
const MAX_THRHD: u8 = 0x7F; // 7 bits const MAX_THRHD: u8 = 0x7F; // 7 bits
@ -766,18 +797,18 @@ where
.write(|w| w.rxfifo_full_int_clr().set_bit()); .write(|w| w.rxfifo_full_int_clr().set_bit());
} }
#[cfg(feature = "embedded-hal")] /// Write a byte out over the UART
fn write_byte(&mut self, word: u8) -> nb::Result<(), Error> { pub fn write_byte(&mut self, word: u8) -> nb::Result<(), Error> {
self.tx.write_byte(word) self.tx.write_byte(word)
} }
#[cfg(feature = "embedded-hal")] /// Flush the transmit buffer of the UART
fn flush_tx(&self) -> nb::Result<(), Error> { pub fn flush_tx(&self) -> nb::Result<(), Error> {
self.tx.flush_tx() self.tx.flush_tx()
} }
#[cfg(feature = "embedded-hal")] /// Read a byte from the UART
fn read_byte(&mut self) -> nb::Result<u8, Error> { pub fn read_byte(&mut self) -> nb::Result<u8, Error> {
self.rx.read_byte() self.rx.read_byte()
} }
@ -811,7 +842,6 @@ where
self self
} }
/// Change the number of data bits
fn change_data_bits(&mut self, data_bits: config::DataBits) -> &mut Self { fn change_data_bits(&mut self, data_bits: config::DataBits) -> &mut Self {
T::register_block() T::register_block()
.conf0() .conf0()
@ -820,7 +850,6 @@ where
self self
} }
/// Change the type of parity checking
fn change_parity(&mut self, parity: config::Parity) -> &mut Self { fn change_parity(&mut self, parity: config::Parity) -> &mut Self {
T::register_block().conf0().modify(|_, w| match parity { T::register_block().conf0().modify(|_, w| match parity {
config::Parity::ParityNone => w.parity_en().clear_bit(), config::Parity::ParityNone => w.parity_en().clear_bit(),
@ -1052,7 +1081,7 @@ where
} }
} }
/// UART peripheral instance /// UART Peripheral Instance
pub trait Instance: crate::private::Sealed { pub trait Instance: crate::private::Sealed {
fn register_block() -> &'static RegisterBlock; fn register_block() -> &'static RegisterBlock;
fn uart_number() -> usize; fn uart_number() -> usize;
@ -1985,6 +2014,7 @@ mod asynch {
} }
} }
/// Low-power UART
#[cfg(lp_uart)] #[cfg(lp_uart)]
pub mod lp_uart { pub mod lp_uart {
use crate::{ use crate::{