#![macro_use] use core::fmt::Debug; use core::future::poll_fn; use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; use embassy_futures::select::{Either, select}; use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use embedded_io::{self, ErrorKind}; use crate::dma::{AnyChannel, Channel}; use crate::gpio::{AnyPin, SealedPin}; use crate::interrupt::Interrupt; use crate::interrupt::typelevel::Binding; use crate::pac::flexcomm::Flexcomm as FlexcommReg; use crate::pac::iocon::vals::PioFunc; use crate::pac::usart::Usart as UsartReg; use crate::pac::*; use crate::{Async, Blocking, Mode}; /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { /// Triggered when the FIFO (or shift-register) is overflowed. Overrun, /// Triggered when there is a parity mismatch between what's received and /// our settings. Parity, /// Triggered when the received character didn't have a valid stop bit. Framing, /// Triggered when the receiver detects noise Noise, /// Triggered when the receiver gets a break Break, } impl embedded_io::Error for Error { fn kind(&self) -> ErrorKind { match self { Error::Overrun => ErrorKind::Other, Error::Parity => ErrorKind::InvalidData, Error::Framing => ErrorKind::InvalidData, Error::Noise => ErrorKind::Other, Error::Break => ErrorKind::Interrupted, } } } impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { core::fmt::Debug::fmt(self, f) } } impl core::error::Error for Error {} /// Word length. #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum DataBits { /// 7 bits data length. DataBits7, /// 8 bits data length. DataBits8, /// 9 bits data length. The 9th bit is commonly used for addressing in multidrop mode. DataBits9, } /// Parity bit. #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Parity { /// No parity. ParityNone, /// Even parity. ParityEven, /// Odd parity. ParityOdd, } /// Stop bits. #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum StopBits { /// 1 stop bit. Stop1, /// 2 stop bits. This setting should only be used for asynchronous communication. Stop2, } /// UART config. #[non_exhaustive] #[derive(Clone, Debug)] pub struct Config { /// Baud rate. pub baudrate: u32, /// Word length. pub data_bits: DataBits, /// Stop bits. pub stop_bits: StopBits, /// Parity bit. pub parity: Parity, /// Invert the tx pin output pub invert_tx: bool, /// Invert the rx pin input pub invert_rx: bool, } impl Default for Config { fn default() -> Self { Self { baudrate: 115200, data_bits: DataBits::DataBits8, stop_bits: StopBits::Stop1, parity: Parity::ParityNone, invert_rx: false, invert_tx: false, } } } /// Internal DMA state of UART RX. pub struct DmaState { pub(crate) rx_err_waker: AtomicWaker, pub(crate) rx_err: AtomicBool, } /// # Type parameters /// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time /// T: the peripheral instance type allowing usage of peripheral specific registers /// M: the operating mode of USART peripheral pub struct Usart<'d, M: Mode> { tx: UsartTx<'d, M>, rx: UsartRx<'d, M>, } pub struct UsartTx<'d, M: Mode> { info: &'static Info, tx_dma: Option>, phantom: PhantomData, } pub struct UsartRx<'d, M: Mode> { info: &'static Info, dma_state: &'static DmaState, rx_dma: Option>, phantom: PhantomData, } impl<'d, M: Mode> UsartTx<'d, M> { pub fn new( _usart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, tx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { let tx_func = tx.pin_func(); Usart::::init::(Some((tx.into(), tx_func)), None, config); Self::new_inner(T::info(), Some(tx_dma.into())) } #[inline] fn new_inner(info: &'static Info, tx_dma: Option>) -> Self { Self { info, tx_dma, phantom: PhantomData, } } pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { for &b in buffer { while !(self.info.usart_reg.fifostat().read().txnotfull()) {} self.info.usart_reg.fifowr().write(|w| w.set_txdata(b as u16)); } Ok(()) } pub fn blocking_flush(&mut self) -> Result<(), Error> { while !(self.info.usart_reg.fifostat().read().txempty()) {} Ok(()) } pub fn tx_busy(&self) -> bool { !(self.info.usart_reg.fifostat().read().txempty()) } } impl<'d> UsartTx<'d, Blocking> { pub fn new_blocking(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, config: Config) -> Self { let tx_func = tx.pin_func(); Usart::::init::(Some((tx.into(), tx_func)), None, config); Self::new_inner(T::info(), None) } } impl<'d> UsartTx<'d, Async> { /// Write to UART TX from the provided buffer using DMA. pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { // Unwrap() can be used because UsartTx::new() in Async mode always sets it to Some let ch = self.tx_dma.as_mut().unwrap().reborrow(); let transfer = unsafe { // Enable to pace DMA transfers. self.info.usart_reg.fifocfg().modify(|w| w.set_dmatx(true)); // If future is not assigned to a variable, the data register pointer // is held across an await and makes the future non-Send. crate::dma::write(ch, buffer, self.info.usart_reg.fifowr().as_ptr() as *mut _) }; transfer.await; Ok(()) } } impl<'d, M: Mode> UsartRx<'d, M> { pub fn new( _usart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, has_irq: bool, rx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { let rx_func = rx.pin_func(); Usart::::init::(None, Some((rx.into(), rx_func)), config); Self::new_inner(T::info(), T::dma_state(), has_irq, Some(rx_dma.into())) } fn new_inner( info: &'static Info, dma_state: &'static DmaState, has_irq: bool, rx_dma: Option>, ) -> Self { core::debug_assert_eq!(has_irq, rx_dma.is_some()); if has_irq { // Disable all the related interrupts for now. info.usart_reg.intenclr().write(|w| { w.set_framerrclr(true); w.set_parityerrclr(true); w.set_rxnoiseclr(true); }); info.usart_reg.fifointenclr().modify(|w| { w.set_rxlvl(true); w.set_rxerr(true); }); info.interrupt.unpend(); unsafe { info.interrupt.enable(); } } Self { info, dma_state, rx_dma, phantom: PhantomData, } } pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { while !buffer.is_empty() { match Self::drain_fifo(self, buffer) { Ok(0) => continue, // Wait for more data Ok(n) => buffer = &mut buffer[n..], Err((_, err)) => return Err(err), } } Ok(()) } /// Returns: /// - Ok(n) -> read n bytes /// - Err(n, Error) -> read n-1 bytes, but encountered an error while reading nth byte fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result { for (i, b) in buffer.iter_mut().enumerate() { while !(self.info.usart_reg.fifostat().read().rxnotempty()) {} if self.info.usart_reg.fifostat().read().rxerr() { return Err((i, Error::Overrun)); } else if self.info.usart_reg.fifordnopop().read().parityerr() { return Err((i, Error::Parity)); } else if self.info.usart_reg.fifordnopop().read().framerr() { return Err((i, Error::Framing)); } else if self.info.usart_reg.fifordnopop().read().rxnoise() { return Err((i, Error::Noise)); } else if self.info.usart_reg.intstat().read().deltarxbrk() { return Err((i, Error::Break)); } let dr = self.info.usart_reg.fiford().read().rxdata() as u8; *b = dr; } Ok(buffer.len()) } } impl<'d> UsartRx<'d, Blocking> { pub fn new_blocking(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, config: Config) -> Self { let rx_func = rx.pin_func(); Usart::::init::(None, Some((rx.into(), rx_func)), config); Self::new_inner(T::info(), T::dma_state(), false, None) } } /// Interrupt handler. pub struct InterruptHandler { _uart: PhantomData, } impl crate::interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { let regs = T::info().usart_reg; if !regs.fifocfg().read().dmarx() { return; } let state = T::dma_state(); state.rx_err.store(true, Ordering::Relaxed); state.rx_err_waker.wake(); // Disable the error interrupts instead of clearing the flags. Clearing the // flags would allow the DMA transfer to continue, potentially signaling // completion before we can check for errors that happened *during* the transfer. regs.intenclr().write(|w| { w.set_framerrclr(true); w.set_rxnoiseclr(true); w.set_parityerrclr(true); }); regs.fifointenclr().write(|w| w.set_rxerr(true)); } } impl<'d> UsartRx<'d, Async> { /// Read from USART RX into the provided buffer. pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { // Clear error flags before the FIFO is drained. Errors that have accumulated // in the flags will also be present in the FIFO. self.dma_state.rx_err.store(false, Ordering::Relaxed); self.info.usart_reg.intenclr().write(|w| { w.set_framerrclr(true); w.set_parityerrclr(true); w.set_rxnoiseclr(true); }); self.info.usart_reg.fifointenclr().modify(|w| w.set_rxerr(true)); // Then drain the fifo. It is necessary to read at most 16 bytes (the size of FIFO). // Errors that apply to FIFO bytes will be reported directly. let buffer = match { let limit = buffer.len().min(16); self.drain_fifo(&mut buffer[0..limit]) } { Ok(len) if len < buffer.len() => &mut buffer[len..], Ok(_) => return Ok(()), Err((_i, e)) => return Err(e), }; // Start a DMA transfer. If errors have happened in the interim some error // interrupt flags will have been raised, and those will be picked up immediately // by the interrupt handler. // Unwrap() can be used because UsartRx::new() in Async mode always sets it to Some let ch = self.rx_dma.as_mut().unwrap().reborrow(); self.info.usart_reg.intenset().write(|w| { w.set_framerren(true); w.set_parityerren(true); w.set_rxnoiseen(true); }); self.info.usart_reg.fifointenset().modify(|w| w.set_rxerr(true)); self.info.usart_reg.fifocfg().modify(|w| w.set_dmarx(true)); let transfer = unsafe { // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. crate::dma::read(ch, self.info.usart_reg.fiford().as_ptr() as *const _, buffer) }; // wait for either the transfer to complete or an error to happen. let transfer_result = select( transfer, poll_fn(|cx| { self.dma_state.rx_err_waker.register(cx.waker()); match self.dma_state.rx_err.swap(false, Ordering::Relaxed) { false => Poll::Pending, e => Poll::Ready(e), } }), ) .await; let errors = match transfer_result { Either::First(()) => { // The DMA controller finished, BUT if an error occurred on the LAST // byte, then we may still need to grab the error state! self.dma_state.rx_err.swap(false, Ordering::Relaxed) } Either::Second(e) => { // There is an error, which means this is the error that // was problematic. e } }; // If we got no error, just return at this point if !errors { return Ok(()); } // If we DID get an error, we need to figure out which one it was. if self.info.usart_reg.intstat().read().framerrint() { return Err(Error::Framing); } else if self.info.usart_reg.intstat().read().parityerrint() { return Err(Error::Parity); } else if self.info.usart_reg.intstat().read().rxnoiseint() { return Err(Error::Noise); } else if self.info.usart_reg.fifointstat().read().rxerr() { return Err(Error::Overrun); } unreachable!("unrecognized rx error"); } } impl<'d> Usart<'d, Blocking> { pub fn new_blocking( usart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, config: Config, ) -> Self { let tx_func = tx.pin_func(); let rx_func = rx.pin_func(); Self::new_inner(usart, tx.into(), tx_func, rx.into(), rx_func, false, None, None, config) } } impl<'d> Usart<'d, Async> { pub fn new( uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, _irq: impl Binding>, tx_dma: Peri<'d, impl TxChannel>, rx_dma: Peri<'d, impl RxChannel>, config: Config, ) -> Self { let tx_func = tx.pin_func(); let rx_func = rx.pin_func(); Self::new_inner( uart, tx.into(), tx_func, rx.into(), rx_func, true, Some(tx_dma.into()), Some(rx_dma.into()), config, ) } } impl<'d, M: Mode> Usart<'d, M> { fn new_inner( _usart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, tx_func: PioFunc, mut rx: Peri<'d, AnyPin>, rx_func: PioFunc, has_irq: bool, tx_dma: Option>, rx_dma: Option>, config: Config, ) -> Self { Self::init::(Some((tx.reborrow(), tx_func)), Some((rx.reborrow(), rx_func)), config); Self { tx: UsartTx::new_inner(T::info(), tx_dma), rx: UsartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma), } } fn init( tx: Option<(Peri<'_, AnyPin>, PioFunc)>, rx: Option<(Peri<'_, AnyPin>, PioFunc)>, config: Config, ) { Self::configure_flexcomm(T::info().fc_reg, T::instance_number()); Self::configure_clock::(&config); Self::pin_config::(tx, rx); Self::configure_usart(T::info(), &config); } fn configure_clock(config: &Config) { // Select source clock // Adaptive clock choice based on baud rate // To get the desired baud rate, it is essential to choose the clock bigger than baud rate so that it can be 'chiseled' // There are two types of dividers: integer divider (baud rate generator register and oversample selection value) // and fractional divider (fractional rate divider). // By default, oversampling rate is 16 which is an industry standard. // That means 16 clocks are used to deliver the byte to recipient. // In this way the probability of getting correct bytes instead of noise directly increases as oversampling increases as well. // Minimum and maximum values were computed taking these formulas into account: // For minimum value, MULT = 0, BRGVAL = 0 // For maximum value, MULT = 255, BRGVAL = 255 // Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1 + MULT / DIV) // By default, OSRVAL = 15 (see above) // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1) let source_clock = match config.baudrate { 750_001..=6_000_000 => { SYSCON .fcclksel(T::instance_number()) .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X3)); // 96 MHz 96_000_000 } 1501..=750_000 => { SYSCON .fcclksel(T::instance_number()) .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X2)); // 12 MHz 12_000_000 } 121..=1500 => { SYSCON .fcclksel(T::instance_number()) .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X4)); // 1 MHz 1_000_000 } _ => { panic!("{} baudrate is not permitted in this mode", config.baudrate); } }; // Calculate MULT and BRG values based on baudrate // There are two types of dividers: integer divider (baud rate generator register and oversample selection value) // and fractional divider (fractional rate divider). // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15 // The formulas are: // FLCK = (clock selected via FCCLKSEL) / (1 + MULT / DIV) // DIV is always 256, then: // FLCK = (clock selected via FCCLKSEL) / (1 + MULT / 256) // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1) => // Baud rate = [FCLK / 16] / (BRGVAL + 1) // There are 2 unknowns: MULT and BRGVAL. // MULT is responsible for fractional division // BRGVAL is responsible for integer division // The Fractional Rate Generator can be used to obtain more precise baud rates when the // function clock is not a good multiple of standard (or otherwise desirable) baud rates. // The FRG is typically set up to produce an integer multiple of the highest required baud // rate, or a very close approximation. The BRG is then used to obtain the actual baud rate // needed. // Firstly, BRGVAL is calculated to get the raw clock which is a rough approximation that has to be adjusted // so that the desired baud rate is obtained. // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate. // The deduced formulas are written below. let brg_value = (source_clock / (16 * config.baudrate)).min(255); let raw_clock = source_clock / (16 * brg_value); let mult_value = ((raw_clock * 256 / config.baudrate) - 256).min(255); // Write values to the registers // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV) // Remark: To use the fractional baud rate generator, 0xFF must be wirtten to the DIV value // to yield a denominator vale of 256. All other values are not supported SYSCON.flexfrgctrl(T::instance_number()).modify(|w| { w.set_div(0xFF); w.set_mult(mult_value as u8); }); // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1) // By default, oversampling is 16x, i.e. OSRVAL = 15 // Typical industry standard USARTs use a 16x oversample clock to transmit and receive // asynchronous data. This is the number of BRG clocks used for one data bit. The // Oversample Select Register (OSR) allows this USART to use a 16x down to a 5x // oversample clock. There is no oversampling in synchronous modes. T::info() .usart_reg .brg() .modify(|w| w.set_brgval((brg_value - 1) as u16)); } fn pin_config(tx: Option<(Peri<'_, AnyPin>, PioFunc)>, rx: Option<(Peri<'_, AnyPin>, PioFunc)>) { if let Some((tx_pin, func)) = tx { tx_pin.pio().modify(|w| { w.set_func(func); w.set_mode(iocon::vals::PioMode::INACTIVE); w.set_slew(iocon::vals::PioSlew::STANDARD); w.set_invert(false); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); w.set_od(iocon::vals::PioOd::NORMAL); }); } if let Some((rx_pin, func)) = rx { rx_pin.pio().modify(|w| { w.set_func(func); w.set_mode(iocon::vals::PioMode::INACTIVE); w.set_slew(iocon::vals::PioSlew::STANDARD); w.set_invert(false); w.set_digimode(iocon::vals::PioDigimode::DIGITAL); w.set_od(iocon::vals::PioOd::NORMAL); }); }; } fn configure_flexcomm(flexcomm_register: crate::pac::flexcomm::Flexcomm, instance_number: usize) { critical_section::with(|_cs| { if !(SYSCON.ahbclkctrl0().read().iocon()) { SYSCON.ahbclkctrl0().modify(|w| w.set_iocon(true)); } }); critical_section::with(|_cs| { if !(SYSCON.ahbclkctrl1().read().fc(instance_number)) { SYSCON.ahbclkctrl1().modify(|w| w.set_fc(instance_number, true)); } }); SYSCON .presetctrl1() .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::ASSERTED)); SYSCON .presetctrl1() .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::RELEASED)); flexcomm_register.pselid().modify(|w| { w.set_persel(flexcomm::vals::Persel::USART); // This will lock the peripheral PERSEL and will not allow any changes until the board is reset. w.set_lock(true); }); } fn configure_usart(info: &'static Info, config: &Config) { let registers = info.usart_reg; // See section 34.6.1 registers.cfg().modify(|w| { // LIN break mode enable // Disabled. Break detect and generate is configured for normal operation. w.set_linmode(false); //CTS Enable. Determines whether CTS is used for flow control. CTS can be from the //input pin, or from the USART’s own RTS if loopback mode is enabled. // No flow control. The transmitter does not receive any automatic flow control signal. w.set_ctsen(false); // Selects synchronous or asynchronous operation. w.set_syncen(usart::vals::Syncen::ASYNCHRONOUS_MODE); // Selects the clock polarity and sampling edge of received data in synchronous mode. w.set_clkpol(usart::vals::Clkpol::RISING_EDGE); // Synchronous mode Master select. // When synchronous mode is enabled, the USART is a master. w.set_syncmst(usart::vals::Syncmst::MASTER); // Selects data loopback mode w.set_loop_(usart::vals::Loop::NORMAL); // Output Enable Turnaround time enable for RS-485 operation. // Disabled. If selected by OESEL, the Output Enable signal deasserted at the end of // the last stop bit of a transmission. w.set_oeta(false); // Output enable select. // Standard. The RTS signal is used as the standard flow control function. w.set_oesel(usart::vals::Oesel::STANDARD); // Automatic address matching enable. // Disabled. When addressing is enabled by ADDRDET, address matching is done by // software. This provides the possibility of versatile addressing (e.g. respond to more // than one address) w.set_autoaddr(false); // Output enable polarity. // Low. If selected by OESEL, the output enable is active low. w.set_oepol(usart::vals::Oepol::LOW); }); // Configurations based on the config written by a user registers.cfg().modify(|w| { w.set_datalen(match config.data_bits { DataBits::DataBits7 => usart::vals::Datalen::BIT_7, DataBits::DataBits8 => usart::vals::Datalen::BIT_8, DataBits::DataBits9 => usart::vals::Datalen::BIT_9, }); w.set_paritysel(match config.parity { Parity::ParityNone => usart::vals::Paritysel::NO_PARITY, Parity::ParityEven => usart::vals::Paritysel::EVEN_PARITY, Parity::ParityOdd => usart::vals::Paritysel::ODD_PARITY, }); w.set_stoplen(match config.stop_bits { StopBits::Stop1 => usart::vals::Stoplen::BIT_1, StopBits::Stop2 => usart::vals::Stoplen::BITS_2, }); w.set_rxpol(match config.invert_rx { false => usart::vals::Rxpol::STANDARD, true => usart::vals::Rxpol::INVERTED, }); w.set_txpol(match config.invert_tx { false => usart::vals::Txpol::STANDARD, true => usart::vals::Txpol::INVERTED, }); }); // DMA-related settings registers.fifocfg().modify(|w| { w.set_dmatx(false); w.set_dmatx(false); }); // Enabling USART registers.fifocfg().modify(|w| { w.set_enabletx(true); w.set_enablerx(true); }); registers.cfg().modify(|w| w.set_enable(true)); registers.fifointenset().modify(|w| w.set_rxerr(true)); // Drain RX FIFO in case it still has some unrelevant data while registers.fifostat().read().rxnotempty() { let _ = registers.fiford().read().0; } } } impl<'d, M: Mode> Usart<'d, M> { /// Transmit the provided buffer blocking execution until done. pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { self.tx.blocking_write(buffer) } /// Flush USART TX blocking execution until done. pub fn blocking_flush(&mut self) -> Result<(), Error> { self.tx.blocking_flush() } /// Read from USART RX blocking execution until done. pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.rx.blocking_read(buffer) } /// Check if UART is busy transmitting. pub fn tx_busy(&self) -> bool { self.tx.tx_busy() } /// Split the Usart into a transmitter and receiver, which is particularly /// useful when having two tasks correlating to transmitting and receiving. pub fn split(self) -> (UsartTx<'d, M>, UsartRx<'d, M>) { (self.tx, self.rx) } /// Split the Usart into a transmitter and receiver by mutable reference, /// which is particularly useful when having two tasks correlating to /// transmitting and receiving. pub fn split_ref(&mut self) -> (&mut UsartTx<'d, M>, &mut UsartRx<'d, M>) { (&mut self.tx, &mut self.rx) } } impl<'d> Usart<'d, Async> { /// Write to UART TX from the provided buffer. pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { self.tx.write(buffer).await } /// Read from UART RX into the provided buffer. pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.rx.read(buffer).await } } impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write for UsartTx<'d, M> { type Error = Error; fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { self.blocking_write(buffer) } fn bflush(&mut self) -> Result<(), Self::Error> { self.blocking_flush() } } impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write for Usart<'d, M> { type Error = Error; fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { self.blocking_write(buffer) } fn bflush(&mut self) -> Result<(), Self::Error> { self.blocking_flush() } } impl<'d> embedded_io::ErrorType for UsartTx<'d, Blocking> { type Error = Error; } impl<'d> embedded_io::Write for UsartTx<'d, Blocking> { fn write(&mut self, buf: &[u8]) -> Result { self.blocking_write(buf).map(|_| buf.len()) } fn flush(&mut self) -> Result<(), Self::Error> { self.blocking_flush() } } impl<'d> embedded_io::ErrorType for UsartRx<'d, Blocking> { type Error = Error; } impl<'d> embedded_io::Read for UsartRx<'d, Blocking> { fn read(&mut self, buf: &mut [u8]) -> Result { self.blocking_read(buf).map(|_| buf.len()) } } impl<'d> embedded_io::ErrorType for Usart<'d, Blocking> { type Error = Error; } impl<'d> embedded_io::Write for Usart<'d, Blocking> { fn write(&mut self, buf: &[u8]) -> Result { self.blocking_write(buf).map(|_| buf.len()) } fn flush(&mut self) -> Result<(), Self::Error> { self.blocking_flush() } } impl<'d> embedded_io::Read for Usart<'d, Blocking> { fn read(&mut self, buf: &mut [u8]) -> Result { self.blocking_read(buf).map(|_| buf.len()) } } pub(crate) struct Info { pub(crate) usart_reg: UsartReg, pub(crate) fc_reg: FlexcommReg, pub(crate) interrupt: Interrupt, } pub(crate) trait SealedInstance { fn info() -> &'static Info; fn dma_state() -> &'static DmaState; fn instance_number() -> usize; } /// UART instance. #[allow(private_bounds)] pub trait Instance: SealedInstance + PeripheralType { /// Interrupt for this instance. type Interrupt: crate::interrupt::typelevel::Interrupt; } macro_rules! impl_usart_instance { ($inst:ident, $fc:ident, $fc_num:expr) => { impl crate::usart::SealedInstance for $crate::peripherals::$inst { fn info() -> &'static crate::usart::Info { use crate::interrupt::typelevel::Interrupt; use crate::usart::Info; static INFO: Info = Info { usart_reg: crate::pac::$inst, fc_reg: crate::pac::$fc, interrupt: crate::interrupt::typelevel::$fc::IRQ, }; &INFO } fn dma_state() -> &'static crate::usart::DmaState { use core::sync::atomic::AtomicBool; use embassy_sync::waitqueue::AtomicWaker; use crate::usart::DmaState; static STATE: DmaState = DmaState { rx_err_waker: AtomicWaker::new(), rx_err: AtomicBool::new(false), }; &STATE } #[inline] fn instance_number() -> usize { $fc_num } } impl $crate::usart::Instance for $crate::peripherals::$inst { type Interrupt = crate::interrupt::typelevel::$fc; } }; } pub(crate) trait SealedTxPin: crate::gpio::Pin { fn pin_func(&self) -> PioFunc; } pub(crate) trait SealedRxPin: crate::gpio::Pin { fn pin_func(&self) -> PioFunc; } /// Trait for TX pins. #[allow(private_bounds)] pub trait TxPin: SealedTxPin + crate::gpio::Pin {} /// Trait for RX pins. #[allow(private_bounds)] pub trait RxPin: SealedRxPin + crate::gpio::Pin {} macro_rules! impl_usart_txd_pin { ($pin:ident, $instance:ident, $func: ident) => { impl crate::usart::SealedTxPin for crate::peripherals::$pin { fn pin_func(&self) -> crate::pac::iocon::vals::PioFunc { use crate::pac::iocon::vals::PioFunc; PioFunc::$func } } impl crate::usart::TxPin for crate::peripherals::$pin {} }; } macro_rules! impl_usart_rxd_pin { ($pin:ident, $instance:ident, $func: ident) => { impl crate::usart::SealedRxPin for crate::peripherals::$pin { fn pin_func(&self) -> crate::pac::iocon::vals::PioFunc { use crate::pac::iocon::vals::PioFunc; PioFunc::$func } } impl crate::usart::RxPin for crate::peripherals::$pin {} }; } /// Marker trait indicating a DMA channel may be used for USART transmit. pub trait TxChannel: crate::dma::Channel {} /// Marker trait indicating a DMA channel may be used for USART recieve. pub trait RxChannel: crate::dma::Channel {} macro_rules! impl_usart_tx_channel { ($instance: ident, $channel: ident) => { impl crate::usart::TxChannel for crate::peripherals::$channel {} }; } macro_rules! impl_usart_rx_channel { ($instance: ident, $channel: ident) => { impl crate::usart::RxChannel for crate::peripherals::$channel {} }; }