//! # UART driver //! //! ## Overview //! In embedded system applications, data is required to be transferred in a //! simple way with minimal system resources. This can be achieved by a //! Universal Asynchronous Receiver/Transmitter (UART), which flexibly exchanges //! data with other peripheral devices in full-duplex mode. //! The UART driver provides an interface to communicate with UART peripherals //! on ESP chips. It enables serial communication between the microcontroller //! and external devices using the UART protocol. //! //! ## Example //! ```no_run //! let config = Config { //! baudrate: 115200, //! data_bits: DataBits::DataBits8, //! parity: Parity::ParityNone, //! stop_bits: StopBits::STOP1, //! }; //! //! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); //! let pins = TxRxPins::new_tx_rx( //! io.pins.gpio1.into_push_pull_output(), //! io.pins.gpio2.into_floating_input(), //! ); //! //! let mut serial1 = 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(); //! } //! ``` use core::marker::PhantomData; use self::config::Config; use crate::{ clock::Clocks, gpio::{InputPin, InputSignal, OutputPin, OutputSignal}, peripheral::{Peripheral, PeripheralRef}, peripherals::uart0::{fifo::FIFO_SPEC, RegisterBlock}, system::PeripheralClockControl, }; const UART_FIFO_SIZE: u16 = 128; /// Custom serial error type #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { InvalidArgument, #[cfg(feature = "async")] RxFifoOvf, } #[cfg(feature = "eh1")] impl embedded_hal_nb::serial::Error for Error { fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { embedded_hal_nb::serial::ErrorKind::Other } } impl embedded_io::Error for Error { fn kind(&self) -> embedded_io::ErrorKind { embedded_io::ErrorKind::Other } } /// UART configuration pub mod config { /// Number of data bits #[derive(PartialEq, Eq, Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum DataBits { DataBits5 = 0, DataBits6 = 1, DataBits7 = 2, DataBits8 = 3, } /// Parity check #[derive(PartialEq, Eq, Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Parity { ParityNone, ParityEven, ParityOdd, } /// Number of stop bits #[derive(PartialEq, Eq, Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum StopBits { /// 1 stop bit STOP1 = 1, /// 1.5 stop bits STOP1P5 = 2, /// 2 stop bits STOP2 = 3, } /// UART configuration #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Config { pub baudrate: u32, pub data_bits: DataBits, pub parity: Parity, pub stop_bits: StopBits, } impl Config { pub fn baudrate(mut self, baudrate: u32) -> Self { self.baudrate = baudrate; self } pub fn parity_none(mut self) -> Self { self.parity = Parity::ParityNone; self } pub fn parity_even(mut self) -> Self { self.parity = Parity::ParityEven; self } pub fn parity_odd(mut self) -> Self { self.parity = Parity::ParityOdd; self } pub fn data_bits(mut self, data_bits: DataBits) -> Self { self.data_bits = data_bits; self } pub fn stop_bits(mut self, stop_bits: StopBits) -> Self { self.stop_bits = stop_bits; self } } impl Default for Config { fn default() -> Config { Config { baudrate: 115_200, data_bits: DataBits::DataBits8, parity: Parity::ParityNone, stop_bits: StopBits::STOP1, } } } /// Configuration for the AT-CMD detection functionality pub struct AtCmdConfig { pub pre_idle_count: Option, pub post_idle_count: Option, pub gap_timeout: Option, pub cmd_char: u8, pub char_num: Option, } impl AtCmdConfig { pub fn new( pre_idle_count: Option, post_idle_count: Option, gap_timeout: Option, cmd_char: u8, char_num: Option, ) -> AtCmdConfig { Self { pre_idle_count, post_idle_count, gap_timeout, cmd_char, char_num, } } } } /// Pins used by the UART interface pub trait UartPins { fn configure_pins( &mut self, tx_signal: OutputSignal, rx_signal: InputSignal, cts_signal: InputSignal, rts_signal: OutputSignal, ); } /// All pins offered by UART pub struct AllPins<'d, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> { pub(crate) tx: Option>, pub(crate) rx: Option>, pub(crate) cts: Option>, pub(crate) rts: Option>, } /// Tx and Rx pins impl<'d, TX: OutputPin, RX: InputPin, CTS: InputPin, RTS: OutputPin> AllPins<'d, TX, RX, CTS, RTS> { pub fn new( tx: impl Peripheral

+ 'd, rx: impl Peripheral

+ 'd, cts: impl Peripheral

+ 'd, rts: impl Peripheral

+ 'd, ) -> AllPins<'d, TX, RX, CTS, RTS> { crate::into_ref!(tx, rx, cts, rts); AllPins { tx: Some(tx), rx: Some(rx), cts: Some(cts), rts: Some(rts), } } } impl UartPins for AllPins<'_, TX, RX, CTS, RTS> { fn configure_pins( &mut self, tx_signal: OutputSignal, rx_signal: InputSignal, cts_signal: InputSignal, rts_signal: OutputSignal, ) { if let Some(ref mut tx) = self.tx { tx.set_to_push_pull_output() .connect_peripheral_to_output(tx_signal); } if let Some(ref mut rx) = self.rx { rx.set_to_input().connect_input_to_peripheral(rx_signal); } if let Some(ref mut cts) = self.cts { cts.set_to_input().connect_input_to_peripheral(cts_signal); } if let Some(ref mut rts) = self.rts { rts.set_to_push_pull_output() .connect_peripheral_to_output(rts_signal); } } } pub struct TxRxPins<'d, TX: OutputPin, RX: InputPin> { pub tx: Option>, pub rx: Option>, } impl<'d, TX: OutputPin, RX: InputPin> TxRxPins<'d, TX, RX> { pub fn new_tx_rx( tx: impl Peripheral

+ 'd, rx: impl Peripheral

+ 'd, ) -> TxRxPins<'d, TX, RX> { crate::into_ref!(tx, rx); TxRxPins { tx: Some(tx), rx: Some(rx), } } } impl UartPins for TxRxPins<'_, TX, RX> { fn configure_pins( &mut self, tx_signal: OutputSignal, rx_signal: InputSignal, _cts_signal: InputSignal, _rts_signal: OutputSignal, ) { if let Some(ref mut tx) = self.tx { tx.set_to_push_pull_output() .connect_peripheral_to_output(tx_signal); } if let Some(ref mut rx) = self.rx { rx.set_to_input().connect_input_to_peripheral(rx_signal); } } } /// UART driver pub struct Uart<'d, T> { tx: UartTx<'d, T>, rx: UartRx<'d, T>, } /// UART TX pub struct UartTx<'d, T> { phantom: PhantomData<&'d mut T>, } /// UART RX pub struct UartRx<'d, T> { phantom: PhantomData<&'d mut T>, at_cmd_config: Option, } impl<'d, T> UartTx<'d, T> where T: Instance, { // if we want to implement a standalone UartTx, // uncomment below and take care of the configuration // pub fn new(_uart: impl Peripheral

+ 'd) -> Self { // Self::new_inner() // } fn new_inner() -> Self { Self { phantom: PhantomData, } } /// Writes bytes pub fn write_bytes(&mut self, data: &[u8]) -> Result { let count = data.len(); data.iter() .try_for_each(|c| nb::block!(self.write_byte(*c)))?; Ok(count) } fn write_byte(&mut self, word: u8) -> nb::Result<(), Error> { if T::get_tx_fifo_count() < UART_FIFO_SIZE { T::register_block() .fifo .write(|w| unsafe { w.rxfifo_rd_byte().bits(word) }); Ok(()) } else { Err(nb::Error::WouldBlock) } } fn flush_tx(&self) -> nb::Result<(), Error> { if T::is_tx_idle() { Ok(()) } else { Err(nb::Error::WouldBlock) } } } impl<'d, T> UartRx<'d, T> where T: Instance, { // if we want to implement a standalone UartRx, // uncomment below and take care of the configuration // pub fn new(_uart: impl Peripheral

+ 'd) -> Self { // Self::new_inner() // } fn new_inner() -> Self { Self { phantom: PhantomData, at_cmd_config: None, } } fn read_byte(&mut self) -> nb::Result { #[allow(unused_variables)] let offset = 0; // on ESP32-S2 we need to use PeriBus2 to read the FIFO #[cfg(esp32s2)] let offset = 0x20c00000; if T::get_rx_fifo_count() > 0 { let value = unsafe { let fifo = (T::register_block().fifo.as_ptr() as *mut u8).offset(offset) as *mut crate::peripherals::generic::Reg; (*fifo).read().rxfifo_rd_byte().bits() }; Ok(value) } else { Err(nb::Error::WouldBlock) } } } impl<'d, T> Uart<'d, T> where T: Instance, { /// Create a new UART instance with defaults pub fn new_with_config

( _uart: impl Peripheral

+ 'd, config: Config, mut pins: Option

, clocks: &Clocks, ) -> Self where P: UartPins, { T::enable_peripheral(); T::disable_rx_interrupts(); T::disable_tx_interrupts(); if let Some(ref mut pins) = pins { pins.configure_pins( T::tx_signal(), T::rx_signal(), T::cts_signal(), T::rts_signal(), ); } let mut serial = Uart { tx: UartTx::new_inner(), rx: UartRx::new_inner(), }; serial.change_data_bits(config.data_bits); serial.change_parity(config.parity); serial.change_stop_bits(config.stop_bits); serial.change_baud(config.baudrate, clocks); serial } /// Create a new UART instance with defaults pub fn new(uart: impl Peripheral

+ 'd, clocks: &Clocks) -> Self { use crate::gpio::*; // not real, just to satify the type type Pins<'a> = TxRxPins<'a, GpioPin, 2>, GpioPin, 0>>; Self::new_with_config(uart, Default::default(), None::>, clocks) } /// Split the Uart into a transmitter and receiver, which is /// particuarly useful when having two tasks correlating to /// transmitting and receiving. pub fn split(self) -> (UartTx<'d, T>, UartRx<'d, T>) { (self.tx, self.rx) } /// Writes bytes pub fn write_bytes(&mut self, data: &[u8]) -> Result { self.tx.write_bytes(data) } /// Configures the AT-CMD detection settings. pub fn set_at_cmd(&mut self, config: config::AtCmdConfig) { #[cfg(not(any(esp32, esp32s2)))] T::register_block() .clk_conf .modify(|_, w| w.sclk_en().clear_bit()); T::register_block().at_cmd_char.write(|w| unsafe { w.at_cmd_char() .bits(config.cmd_char) .char_num() .bits(config.char_num.or(Some(1)).unwrap()) }); if let Some(pre_idle_count) = config.pre_idle_count { T::register_block() .at_cmd_precnt .write(|w| unsafe { w.pre_idle_num().bits(pre_idle_count.into()) }); } if let Some(post_idle_count) = config.post_idle_count { T::register_block() .at_cmd_postcnt .write(|w| unsafe { w.post_idle_num().bits(post_idle_count.into()) }); } if let Some(gap_timeout) = config.gap_timeout { T::register_block() .at_cmd_gaptout .write(|w| unsafe { w.rx_gap_tout().bits(gap_timeout.into()) }); } #[cfg(not(any(esp32, esp32s2)))] T::register_block() .clk_conf .modify(|_, w| w.sclk_en().set_bit()); self.sync_regs(); self.rx.at_cmd_config = Some(config); } /// Configures the RX-FIFO threshold /// /// # Errors /// `Err(Error::InvalidArgument)` if provided value exceeds maximum value /// for SOC : /// - `esp32` **0x7F** /// - `esp32c6`, `esp32h2` **0xFF** /// - `esp32c3`, `esp32c2`, `esp32s2` **0x1FF** /// - `esp32s3` **0x3FF** pub fn set_rx_fifo_full_threshold(&mut self, threshold: u16) -> Result<(), Error> { #[cfg(esp32)] const MAX_THRHD: u16 = 0x7F; #[cfg(any(esp32c6, esp32h2))] const MAX_THRHD: u16 = 0xFF; #[cfg(any(esp32c3, esp32c2, esp32s2))] const MAX_THRHD: u16 = 0x1FF; #[cfg(esp32s3)] const MAX_THRHD: u16 = 0x3FF; if threshold > MAX_THRHD { return Err(Error::InvalidArgument); } #[cfg(any(esp32, esp32c6, esp32h2))] let threshold: u8 = threshold as u8; T::register_block() .conf1 .modify(|_, w| unsafe { w.rxfifo_full_thrhd().bits(threshold) }); Ok(()) } /// Listen for AT-CMD interrupts pub fn listen_at_cmd(&mut self) { T::register_block() .int_ena .modify(|_, w| w.at_cmd_char_det_int_ena().set_bit()); } /// Stop listening for AT-CMD interrupts pub fn unlisten_at_cmd(&mut self) { T::register_block() .int_ena .modify(|_, w| w.at_cmd_char_det_int_ena().clear_bit()); } /// Listen for TX-DONE interrupts pub fn listen_tx_done(&mut self) { T::register_block() .int_ena .modify(|_, w| w.tx_done_int_ena().set_bit()); } /// Stop listening for TX-DONE interrupts pub fn unlisten_tx_done(&mut self) { T::register_block() .int_ena .modify(|_, w| w.tx_done_int_ena().clear_bit()); } /// Listen for RX-FIFO-FULL interrupts pub fn listen_rx_fifo_full(&mut self) { T::register_block() .int_ena .modify(|_, w| w.rxfifo_full_int_ena().set_bit()); } /// Stop listening for RX-FIFO-FULL interrupts pub fn unlisten_rx_fifo_full(&mut self) { T::register_block() .int_ena .modify(|_, w| w.rxfifo_full_int_ena().clear_bit()); } /// Checks if AT-CMD interrupt is set pub fn at_cmd_interrupt_set(&self) -> bool { T::register_block() .int_raw .read() .at_cmd_char_det_int_raw() .bit_is_set() } /// Checks if TX-DONE interrupt is set pub fn tx_done_interrupt_set(&self) -> bool { T::register_block() .int_raw .read() .tx_done_int_raw() .bit_is_set() } /// Checks if RX-FIFO-FULL interrupt is set pub fn rx_fifo_full_interrupt_set(&self) -> bool { T::register_block() .int_raw .read() .rxfifo_full_int_raw() .bit_is_set() } /// Reset AT-CMD interrupt pub fn reset_at_cmd_interrupt(&self) { T::register_block() .int_clr .write(|w| w.at_cmd_char_det_int_clr().set_bit()); } /// Reset TX-DONE interrupt pub fn reset_tx_done_interrupt(&self) { T::register_block() .int_clr .write(|w| w.tx_done_int_clr().set_bit()); } /// Reset RX-FIFO-FULL interrupt pub fn reset_rx_fifo_full_interrupt(&self) { T::register_block() .int_clr .write(|w| w.rxfifo_full_int_clr().set_bit()); } #[cfg(feature = "eh1")] fn write_byte(&mut self, word: u8) -> nb::Result<(), Error> { self.tx.write_byte(word) } #[cfg(feature = "eh1")] fn flush_tx(&self) -> nb::Result<(), Error> { self.tx.flush_tx() } #[cfg(feature = "eh1")] fn read_byte(&mut self) -> nb::Result { self.rx.read_byte() } /// Change the number of stop bits pub fn change_stop_bits(&mut self, stop_bits: config::StopBits) -> &mut Self { // workaround for hardware issue, when UART stop bit set as 2-bit mode. #[cfg(esp32)] if stop_bits == config::StopBits::STOP2 { T::register_block() .rs485_conf .modify(|_, w| w.dl1_en().bit(true)); T::register_block() .conf0 .modify(|_, w| unsafe { w.stop_bit_num().bits(1) }); } else { T::register_block() .rs485_conf .modify(|_, w| w.dl1_en().bit(false)); T::register_block() .conf0 .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8) }); } #[cfg(not(esp32))] T::register_block() .conf0 .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8) }); self } /// Change the number of data bits fn change_data_bits(&mut self, data_bits: config::DataBits) -> &mut Self { T::register_block() .conf0 .modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) }); self } /// Change the type of parity checking fn change_parity(&mut self, parity: config::Parity) -> &mut Self { T::register_block().conf0.modify(|_, w| match parity { config::Parity::ParityNone => w.parity_en().clear_bit(), config::Parity::ParityEven => w.parity_en().set_bit().parity().clear_bit(), config::Parity::ParityOdd => w.parity_en().set_bit().parity().set_bit(), }); self } #[cfg(any(esp32c2, esp32c3, esp32s3))] fn change_baud(&self, baudrate: u32, clocks: &Clocks) { // we force the clock source to be APB and don't use the decimal part of the // divider let clk = clocks.apb_clock.to_Hz(); let max_div = 0b1111_1111_1111 - 1; let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate); T::register_block().clk_conf.write(|w| unsafe { w.sclk_sel() .bits(1) // APB .sclk_div_a() .bits(0) .sclk_div_b() .bits(0) .sclk_div_num() .bits(clk_div as u8 - 1) .rx_sclk_en() .bit(true) .tx_sclk_en() .bit(true) }); let clk = clk / clk_div; let divider = clk / baudrate; let divider = divider as u16; T::register_block() .clkdiv .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); } #[cfg(any(esp32c6, esp32h2))] fn change_baud(&self, baudrate: u32, clocks: &Clocks) { // we force the clock source to be XTAL and don't use the decimal part of // the divider let clk = clocks.xtal_clock.to_Hz(); let max_div = 0b1111_1111_1111 - 1; let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate); // UART clocks are configured via PCR let pcr = unsafe { &*crate::peripherals::PCR::PTR }; match T::uart_number() { 0 => { pcr.uart0_conf .modify(|_, w| w.uart0_rst_en().clear_bit().uart0_clk_en().set_bit()); pcr.uart0_sclk_conf.modify(|_, w| unsafe { w.uart0_sclk_div_a() .bits(0) .uart0_sclk_div_b() .bits(0) .uart0_sclk_div_num() .bits(clk_div as u8 - 1) .uart0_sclk_sel() .bits(0x3) // TODO: this probably shouldn't be hard-coded .uart0_sclk_en() .set_bit() }); } 1 => { pcr.uart1_conf .modify(|_, w| w.uart1_rst_en().clear_bit().uart1_clk_en().set_bit()); pcr.uart1_sclk_conf.modify(|_, w| unsafe { w.uart1_sclk_div_a() .bits(0) .uart1_sclk_div_b() .bits(0) .uart1_sclk_div_num() .bits(clk_div as u8 - 1) .uart1_sclk_sel() .bits(0x3) // TODO: this probably shouldn't be hard-coded .uart1_sclk_en() .set_bit() }); } _ => unreachable!(), // ESP32-C6 only has 2 UART instances } let clk = clk / clk_div; let divider = clk / baudrate; let divider = divider as u16; T::register_block() .clkdiv .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); self.sync_regs(); } #[cfg(any(esp32, esp32s2))] fn change_baud(&self, baudrate: u32, clocks: &Clocks) { // we force the clock source to be APB and don't use the decimal part of the // divider let clk = clocks.apb_clock.to_Hz(); T::register_block() .conf0 .modify(|_, w| w.tick_ref_always_on().bit(true)); let divider = clk / baudrate; T::register_block() .clkdiv .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); } #[cfg(any(esp32c6, esp32h2))] // TODO introduce a cfg symbol for this #[inline(always)] fn sync_regs(&self) { T::register_block() .reg_update .modify(|_, w| w.reg_update().set_bit()); while T::register_block() .reg_update .read() .reg_update() .bit_is_set() { // wait } } #[cfg(not(any(esp32c6, esp32h2)))] #[inline(always)] fn sync_regs(&mut self) {} } /// UART peripheral instance pub trait Instance { fn register_block() -> &'static RegisterBlock; fn uart_number() -> usize; fn disable_tx_interrupts() { Self::register_block().int_clr.write(|w| { w.txfifo_empty_int_clr() .set_bit() .tx_brk_done_int_clr() .set_bit() .tx_brk_idle_done_int_clr() .set_bit() .tx_done_int_clr() .set_bit() }); Self::register_block().int_ena.write(|w| { w.txfifo_empty_int_ena() .clear_bit() .tx_brk_done_int_ena() .clear_bit() .tx_brk_idle_done_int_ena() .clear_bit() .tx_done_int_ena() .clear_bit() }); } fn disable_rx_interrupts() { Self::register_block().int_clr.write(|w| { w.rxfifo_full_int_clr() .set_bit() .rxfifo_ovf_int_clr() .set_bit() .rxfifo_tout_int_clr() .set_bit() .at_cmd_char_det_int_clr() .set_bit() }); Self::register_block().int_ena.write(|w| { w.rxfifo_full_int_ena() .clear_bit() .rxfifo_ovf_int_ena() .clear_bit() .rxfifo_tout_int_ena() .clear_bit() .at_cmd_char_det_int_ena() .clear_bit() }); } fn get_tx_fifo_count() -> u16 { Self::register_block() .status .read() .txfifo_cnt() .bits() .into() } fn get_rx_fifo_count() -> u16 { let fifo_cnt: u16 = Self::register_block() .status .read() .rxfifo_cnt() .bits() .into(); // Calculate the real count based on the FIFO read and write offset address: // https://www.espressif.com/sites/default/files/documentation/esp32_errata_en.pdf // section 3.17 #[cfg(esp32)] { let rd_addr: u16 = Self::register_block() .mem_rx_status .read() .mem_rx_rd_addr() .bits() .into(); let wr_addr: u16 = Self::register_block() .mem_rx_status .read() .mem_rx_wr_addr() .bits() .into(); if wr_addr > rd_addr { wr_addr - rd_addr } else if wr_addr < rd_addr { (wr_addr + UART_FIFO_SIZE) - rd_addr } else { if fifo_cnt > 0 { UART_FIFO_SIZE } else { 0 } } } #[cfg(not(esp32))] fifo_cnt } fn is_tx_idle() -> bool { #[cfg(esp32)] let idle = Self::register_block().status.read().st_utx_out().bits() == 0x0u8; #[cfg(not(esp32))] let idle = Self::register_block().fsm_status.read().st_utx_out().bits() == 0x0u8; idle } fn is_rx_idle() -> bool { #[cfg(esp32)] let idle = Self::register_block().status.read().st_urx_out().bits() == 0x0u8; #[cfg(not(esp32))] let idle = Self::register_block().fsm_status.read().st_urx_out().bits() == 0x0u8; idle } fn tx_signal() -> OutputSignal; fn rx_signal() -> InputSignal; fn cts_signal() -> InputSignal; fn rts_signal() -> OutputSignal; fn enable_peripheral(); } macro_rules! impl_instance { ($inst:ident, $num:expr, $txd:ident, $rxd:ident, $cts:ident, $rts:ident, $peri:ident) => { impl Instance for crate::peripherals::$inst { #[inline(always)] fn register_block() -> &'static RegisterBlock { unsafe { &*crate::peripherals::$inst::PTR } } #[inline(always)] fn uart_number() -> usize { $num } fn tx_signal() -> OutputSignal { OutputSignal::$txd } fn rx_signal() -> InputSignal { InputSignal::$rxd } fn cts_signal() -> InputSignal { InputSignal::$cts } fn rts_signal() -> OutputSignal { OutputSignal::$rts } fn enable_peripheral() { PeripheralClockControl::enable(crate::system::Peripheral::$peri); } } }; } impl_instance!(UART0, 0, U0TXD, U0RXD, U0CTS, U0RTS, Uart0); impl_instance!(UART1, 1, U1TXD, U1RXD, U1CTS, U1RTS, Uart1); #[cfg(uart2)] impl_instance!(UART2, 2, U2TXD, U2RXD, U2CTS, U2RTS, Uart2); #[cfg(feature = "ufmt")] impl ufmt_write::uWrite for Uart<'_, T> where T: Instance, { type Error = Error; #[inline] fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { self.tx.write_str(s) } #[inline] fn write_char(&mut self, ch: char) -> Result<(), Self::Error> { self.tx.write_char(ch) } } #[cfg(feature = "ufmt")] impl ufmt_write::uWrite for UartTx<'_, T> where T: Instance, { type Error = Error; #[inline] fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { self.write_bytes(s.as_bytes())?; Ok(()) } #[inline] fn write_char(&mut self, ch: char) -> Result<(), Self::Error> { let mut buffer = [0u8; 4]; self.write_bytes(ch.encode_utf8(&mut buffer).as_bytes())?; Ok(()) } } impl core::fmt::Write for Uart<'_, T> where T: Instance, { #[inline] fn write_str(&mut self, s: &str) -> core::fmt::Result { self.tx.write_str(s) } } impl core::fmt::Write for UartTx<'_, T> where T: Instance, { #[inline] fn write_str(&mut self, s: &str) -> core::fmt::Result { self.write_bytes(s.as_bytes()) .map_err(|_| core::fmt::Error)?; Ok(()) } } impl embedded_hal::serial::Write for Uart<'_, T> where T: Instance, { type Error = Error; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.tx.write(word) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.tx.flush() } } impl embedded_hal::serial::Write for UartTx<'_, T> where T: Instance, { type Error = Error; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.write_byte(word) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.flush_tx() } } impl embedded_hal::serial::Read for Uart<'_, T> where T: Instance, { type Error = Error; fn read(&mut self) -> nb::Result { self.rx.read() } } impl embedded_hal::serial::Read for UartRx<'_, T> where T: Instance, { type Error = Error; fn read(&mut self) -> nb::Result { self.read_byte() } } #[cfg(feature = "eh1")] impl embedded_hal_nb::serial::ErrorType for Uart<'_, T> { type Error = Error; } #[cfg(feature = "eh1")] impl embedded_hal_nb::serial::ErrorType for UartTx<'_, T> { type Error = Error; } #[cfg(feature = "eh1")] impl embedded_hal_nb::serial::ErrorType for UartRx<'_, T> { type Error = Error; } #[cfg(feature = "eh1")] impl embedded_hal_nb::serial::Read for Uart<'_, T> where T: Instance, { fn read(&mut self) -> nb::Result { self.read_byte() } } #[cfg(feature = "eh1")] impl embedded_hal_nb::serial::Read for UartRx<'_, T> where T: Instance, { fn read(&mut self) -> nb::Result { self.read_byte() } } #[cfg(feature = "eh1")] impl embedded_hal_nb::serial::Write for Uart<'_, T> where T: Instance, { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.write_byte(word) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.flush_tx() } } #[cfg(feature = "eh1")] impl embedded_hal_nb::serial::Write for UartTx<'_, T> where T: Instance, { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.write_byte(word) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.flush_tx() } } impl embedded_io::ErrorType for Uart<'_, T> { type Error = Error; } impl embedded_io::ErrorType for UartTx<'_, T> { type Error = Error; } impl embedded_io::ErrorType for UartRx<'_, T> { type Error = Error; } impl embedded_io::Read for Uart<'_, T> where T: Instance, { fn read(&mut self, buf: &mut [u8]) -> Result { self.rx.read(buf) } } impl embedded_io::Read for UartRx<'_, T> where T: Instance, { fn read(&mut self, buf: &mut [u8]) -> Result { let mut count = 0; loop { if count >= buf.len() { break; } match self.read_byte() { Ok(byte) => { buf[count] = byte; count += 1; } Err(nb::Error::WouldBlock) => { // Block until we have read at least one byte if count > 0 { break; } } Err(nb::Error::Other(e)) => return Err(e), } } Ok(count) } } impl embedded_io::Write for Uart<'_, T> where T: Instance, { fn write(&mut self, buf: &[u8]) -> Result { self.tx.write(buf) } fn flush(&mut self) -> Result<(), Self::Error> { self.tx.flush() } } impl embedded_io::Write for UartTx<'_, T> where T: Instance, { fn write(&mut self, buf: &[u8]) -> Result { self.write_bytes(buf) } fn flush(&mut self) -> Result<(), Self::Error> { loop { match self.flush_tx() { Ok(_) => break, Err(nb::Error::WouldBlock) => { /* Wait */ } Err(nb::Error::Other(e)) => return Err(e), } } Ok(()) } } #[cfg(feature = "async")] mod asynch { use core::{marker::PhantomData, task::Poll}; use cfg_if::cfg_if; use embassy_futures::select::{select, select3, Either, Either3}; use embassy_sync::waitqueue::AtomicWaker; use procmacros::interrupt; use super::{Error, Instance}; use crate::{ uart::{RegisterBlock, UART_FIFO_SIZE}, Uart, UartRx, UartTx, }; cfg_if! { if #[cfg(all(uart0, uart1, uart2))] { const NUM_UART: usize = 3; } else if #[cfg(all(uart0, uart1))] { const NUM_UART: usize = 2; } else if #[cfg(uart0)] { const NUM_UART: usize = 1; } } const INIT: AtomicWaker = AtomicWaker::new(); static WAKERS: [AtomicWaker; NUM_UART] = [INIT; NUM_UART]; pub(crate) enum Event { TxDone, TxFiFoEmpty, RxFifoFull, RxCmdCharDetected, RxFifoOvf, } pub(crate) struct UartFuture<'d, T: Instance> { event: Event, phantom: PhantomData<&'d mut T>, } impl<'d, T: Instance> UartFuture<'d, T> { pub fn new(event: Event) -> Self { match event { Event::TxDone => T::register_block() .int_ena .modify(|_, w| w.tx_done_int_ena().set_bit()), Event::TxFiFoEmpty => T::register_block() .int_ena .modify(|_, w| w.txfifo_empty_int_ena().set_bit()), Event::RxFifoFull => T::register_block() .int_ena .modify(|_, w| w.rxfifo_full_int_ena().set_bit()), Event::RxCmdCharDetected => T::register_block() .int_ena .modify(|_, w| w.at_cmd_char_det_int_ena().set_bit()), Event::RxFifoOvf => T::register_block() .int_ena .modify(|_, w| w.rxfifo_ovf_int_ena().set_bit()), } Self { event, phantom: PhantomData, } } fn event_bit_is_clear(&self) -> bool { match self.event { Event::TxDone => T::register_block() .int_ena .read() .tx_done_int_ena() .bit_is_clear(), Event::TxFiFoEmpty => T::register_block() .int_ena .read() .txfifo_empty_int_ena() .bit_is_clear(), Event::RxFifoFull => T::register_block() .int_ena .read() .rxfifo_full_int_ena() .bit_is_clear(), Event::RxCmdCharDetected => T::register_block() .int_ena .read() .at_cmd_char_det_int_ena() .bit_is_clear(), Event::RxFifoOvf => T::register_block() .int_ena .read() .rxfifo_ovf_int_ena() .bit_is_clear(), } } } impl<'d, T: Instance> core::future::Future for UartFuture<'d, T> { type Output = (); fn poll( self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>, ) -> core::task::Poll { WAKERS[T::uart_number()].register(cx.waker()); if self.event_bit_is_clear() { Poll::Ready(()) } else { Poll::Pending } } } impl Uart<'_, T> where T: Instance, { /// Read async to buffer slice `buf`. Wait for Rx Fifo Full interrupt /// (set by `set_rx_fifo_full_threshold`) and/or Rx AT_CMD character /// interrupt if `set_at_cmd` was called. /// /// # Params /// - `buf` buffer slice to write the bytes into /// /// # Errors /// - `Err(RxFifoOvf)` when MCU Rx Fifo Overflow interrupt is triggered. /// To avoid this error, call this function more often. /// - `Err(Error::ReadNoConfig)` if neither `set_rx_fifo_full_threshold` /// or `set_at_cmd` was called /// /// # Ok /// When succesfull, returns the number of bytes written to /// buf async fn read_async(&mut self, buf: &mut [u8]) -> Result { self.rx.read_async(buf).await } async fn write_async(&mut self, words: &[u8]) -> Result { self.tx.write_async(words).await } async fn flush_async(&mut self) -> Result<(), Error> { self.tx.flush_async().await } } impl UartTx<'_, T> where T: Instance, { async fn write_async(&mut self, words: &[u8]) -> Result { let mut count = 0; let mut offset: usize = 0; loop { let mut next_offset = offset + (UART_FIFO_SIZE - T::get_tx_fifo_count()) as usize; if next_offset > words.len() { next_offset = words.len(); } for byte in &words[offset..next_offset] { self.write_byte(*byte).unwrap(); // should never fail count += 1; } if next_offset >= words.len() { break; } offset = next_offset; UartFuture::::new(Event::TxFiFoEmpty).await; } Ok(count) } async fn flush_async(&mut self) -> Result<(), Error> { let count = T::get_tx_fifo_count(); if count > 0 { UartFuture::::new(Event::TxDone).await; } Ok(()) } } impl UartRx<'_, T> where T: Instance, { /// Read async to buffer slice `buf`. Wait for Rx Fifo Full interrupt /// (set by `set_rx_fifo_full_threshold`) and/or Rx AT_CMD character /// interrupt if `set_at_cmd` was called. /// /// # Params /// - `buf` buffer slice to write the bytes into /// /// # Errors /// - `Err(RxFifoOvf)` when MCU Rx Fifo Overflow interrupt is triggered. /// To avoid this error, call this function more often. /// - `Err(Error::ReadNoConfig)` if neither `set_rx_fifo_full_threshold` /// or `set_at_cmd` was called /// /// # Ok /// When succesfull, returns the number of bytes written to /// buf async fn read_async(&mut self, buf: &mut [u8]) -> Result { if buf.len() == 0 { return Ok(0); } let mut read_bytes = 0; if self.at_cmd_config.is_some() { if let Either3::Third(_) = select3( UartFuture::::new(Event::RxCmdCharDetected), UartFuture::::new(Event::RxFifoFull), UartFuture::::new(Event::RxFifoOvf), ) .await { return Err(Error::RxFifoOvf); } } else { if let Either::Second(_) = select( UartFuture::::new(Event::RxFifoFull), UartFuture::::new(Event::RxFifoOvf), ) .await { return Err(Error::RxFifoOvf); } } while let Ok(byte) = self.read_byte() { if read_bytes < buf.len() { buf[read_bytes] = byte; read_bytes += 1; } else { break; } } Ok(read_bytes) } } impl embedded_io_async::Read for Uart<'_, T> where T: Instance, { async fn read(&mut self, buf: &mut [u8]) -> Result { self.read_async(buf).await } } impl embedded_io_async::Read for UartRx<'_, T> where T: Instance, { async fn read(&mut self, buf: &mut [u8]) -> Result { self.read_async(buf).await } } impl embedded_io_async::Write for Uart<'_, T> where T: Instance, { async fn write(&mut self, buf: &[u8]) -> Result { self.write_async(buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { self.flush_async().await } } impl embedded_io_async::Write for UartTx<'_, T> where T: Instance, { async fn write(&mut self, buf: &[u8]) -> Result { self.write_async(buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { self.flush_async().await } } fn intr_handler(uart: &RegisterBlock) -> bool { let int_raw_val = uart.int_raw.read(); let int_ena_val = uart.int_ena.read(); let mut wake = false; if int_ena_val.txfifo_empty_int_ena().bit_is_set() && int_raw_val.txfifo_empty_int_raw().bit_is_set() { uart.int_clr.write(|w| w.txfifo_empty_int_clr().set_bit()); uart.int_ena .modify(|_, w| w.txfifo_empty_int_ena().clear_bit()); wake = true; } if int_ena_val.tx_done_int_ena().bit_is_set() && int_raw_val.tx_done_int_raw().bit_is_set() { uart.int_clr.write(|w| w.tx_done_int_clr().set_bit()); uart.int_ena.modify(|_, w| w.tx_done_int_ena().clear_bit()); wake = true; } if int_ena_val.at_cmd_char_det_int_ena().bit_is_set() && int_raw_val.at_cmd_char_det_int_raw().bit_is_set() { uart.int_clr .write(|w| w.at_cmd_char_det_int_clr().set_bit()); uart.int_ena .modify(|_, w| w.at_cmd_char_det_int_ena().clear_bit()); wake = true; } if int_ena_val.rxfifo_full_int_ena().bit_is_set() && int_raw_val.rxfifo_full_int_raw().bit_is_set() { uart.int_clr.write(|w| w.rxfifo_full_int_clr().set_bit()); uart.int_ena .modify(|_, w| w.rxfifo_full_int_ena().clear_bit()); wake = true; } if int_ena_val.rxfifo_ovf_int_ena().bit_is_set() && int_raw_val.rxfifo_ovf_int_raw().bit_is_set() { uart.int_clr.write(|w| w.rxfifo_ovf_int_clr().set_bit()); uart.int_ena .modify(|_, w| w.rxfifo_ovf_int_ena().clear_bit()); wake = true; } wake } #[cfg(uart0)] #[interrupt] fn UART0() { let uart = unsafe { &*crate::peripherals::UART0::ptr() }; if intr_handler(uart) { WAKERS[0].wake(); } } #[cfg(uart1)] #[interrupt] fn UART1() { let uart = unsafe { &*crate::peripherals::UART1::ptr() }; if intr_handler(uart) { WAKERS[1].wake(); } } #[cfg(uart2)] #[interrupt] fn UART2() { let uart = unsafe { &*crate::peripherals::UART2::ptr() }; if intr_handler(uart) { WAKERS[2].wake(); } } }