//! API for the integrated USART ports //! //! This only implements the usual asynchronous bidirectional 8-bit transfers. //! //! It's possible to use a read-only/write-only serial implementation with //! `usartXrx`/`usartXtx`. //! //! # Examples //! Echo //! ``` no_run //! use stm32f0xx_hal as hal; //! //! use crate::hal::prelude::*; //! use crate::hal::serial::Serial; //! use crate::hal::pac; //! //! use nb::block; //! //! cortex_m::interrupt::free(|cs| { //! let rcc = p.RCC.configure().sysclk(48.mhz()).freeze(); //! //! let gpioa = p.GPIOA.split(&mut rcc); //! //! let tx = gpioa.pa9.into_alternate_af1(cs); //! let rx = gpioa.pa10.into_alternate_af1(cs); //! //! let mut serial = Serial::usart1(p.USART1, (tx, rx), 115_200.bps(), &mut rcc); //! //! loop { //! let received = block!(serial.read()).unwrap(); //! block!(serial.write(received)).ok(); //! } //! }); //! ``` //! //! Hello World //! ``` no_run //! use stm32f0xx_hal as hal; //! //! use crate::hal::prelude::*; //! use crate::hal::serial::Serial; //! use crate::hal::pac; //! //! use nb::block; //! //! cortex_m::interrupt::free(|cs| { //! let rcc = p.RCC.configure().sysclk(48.mhz()).freeze(); //! //! let gpioa = p.GPIOA.split(&mut rcc); //! //! let tx = gpioa.pa9.into_alternate_af1(cs); //! //! let mut serial = Serial::usart1tx(p.USART1, tx, 115_200.bps(), &mut rcc); //! //! loop { //! serial.write_str("Hello World!\r\n"); //! } //! }); //! ``` use core::{ convert::Infallible, fmt::{Result, Write}, ops::Deref, }; use embedded_hal::prelude::*; use crate::{gpio::*, rcc::Rcc, time::Bps}; use core::marker::PhantomData; /// Serial error #[derive(Debug)] pub enum Error { /// Framing error Framing, /// Noise error Noise, /// RX buffer overrun Overrun, /// Parity check error Parity, #[doc(hidden)] _Extensible, } /// Interrupt event pub enum Event { /// New data has been received Rxne, /// New data can be sent Txe, /// Idle line state detected Idle, } pub trait TxPin {} pub trait RxPin {} macro_rules! usart_pins { ($($USART:ident => { tx => [$($tx:ty),+ $(,)*], rx => [$($rx:ty),+ $(,)*], })+) => { $( $( impl TxPin for $tx {} )+ $( impl RxPin for $rx {} )+ )+ } } #[cfg(any( feature = "stm32f030", feature = "stm32f031", feature = "stm32f038", feature = "stm32f042", feature = "stm32f048", feature = "stm32f051", feature = "stm32f058", feature = "stm32f070", feature = "stm32f071", feature = "stm32f072", feature = "stm32f078", feature = "stm32f091", feature = "stm32f098", ))] usart_pins! { USART1 => { tx => [gpioa::PA9>, gpiob::PB6>], rx => [gpioa::PA10>, gpiob::PB7>], } } #[cfg(any( feature = "stm32f030x4", feature = "stm32f030x6", feature = "stm32f031", feature = "stm32f038", ))] usart_pins! { USART1 => { tx => [gpioa::PA2>, gpioa::PA14>], rx => [gpioa::PA3>, gpioa::PA15>], } } #[cfg(any( feature = "stm32f030x8", feature = "stm32f030xc", feature = "stm32f042", feature = "stm32f048", feature = "stm32f051", feature = "stm32f058", feature = "stm32f070", feature = "stm32f071", feature = "stm32f072", feature = "stm32f078", feature = "stm32f091", feature = "stm32f098", ))] usart_pins! { USART2 => { tx => [gpioa::PA2>, gpioa::PA14>], rx => [gpioa::PA3>, gpioa::PA15>], } } #[cfg(any( feature = "stm32f071", feature = "stm32f072", feature = "stm32f078", feature = "stm32f091", feature = "stm32f098", ))] usart_pins! { USART2 => { tx => [gpiod::PD5>], rx => [gpiod::PD6>], } } #[cfg(any( feature = "stm32f030xc", feature = "stm32f070xb", feature = "stm32f071", feature = "stm32f072", feature = "stm32f078", feature = "stm32f091", feature = "stm32f098", ))] usart_pins! { USART3 => { // According to the datasheet PB10 is both tx and rx, but in stm32cubemx it's only tx tx => [gpiob::PB10>, gpioc::PC4>, gpioc::PC10>], rx => [gpiob::PB11>, gpioc::PC5>, gpioc::PC11>], } USART4 => { tx => [gpioa::PA0>, gpioc::PC10>], rx => [gpioa::PA1>, gpioc::PC11>], } } #[cfg(any( feature = "stm32f071", feature = "stm32f072", feature = "stm32f078", feature = "stm32f091", feature = "stm32f098", ))] usart_pins! { USART3 => { tx => [gpiod::PD8>], rx => [gpiod::PD9>], } } // TODO: The ST SVD files are missing the entire PE enable register. // Re-enable as soon as this gets fixed. // #[cfg(any(feature = "stm32f091", feature = "stm32f098"))] // usart_pins! { // USART4 => { // tx => [gpioe::PE8>], // rx => [gpioe::PE9>], // } // } #[cfg(any(feature = "stm32f030xc", feature = "stm32f091", feature = "stm32f098"))] usart_pins! { USART5 => { tx => [gpioc::PC12>], rx => [gpiod::PD2>], } USART6 => { tx => [gpioa::PA4>, gpioc::PC0>], rx => [gpioa::PA5>, gpioc::PC1>], } } #[cfg(any(feature = "stm32f030xc", feature = "stm32f091"))] usart_pins! { USART5 => { tx => [gpiob::PB3>], rx => [gpiob::PB4>], } } // TODO: The ST SVD files are missing the entire PE enable register. // Re-enable as soon as this gets fixed. #[cfg(any(feature = "stm32f091", feature = "stm32f098"))] usart_pins! { // USART5 => { // tx => [gpioe::PE10>], // rx => [gpioe::PE11>], // } USART6 => { tx => [gpiof::PF9>], rx => [gpiof::PF10>], } } /// Serial abstraction pub struct Serial { usart: USART, pins: (TXPIN, RXPIN), } // Common register type SerialRegisterBlock = crate::pac::usart1::RegisterBlock; /// Serial receiver pub struct Rx { usart: *const SerialRegisterBlock, _instance: PhantomData, } // NOTE(unsafe) Required to allow protected shared access in handlers unsafe impl Send for Rx {} /// Serial transmitter pub struct Tx { usart: *const SerialRegisterBlock, _instance: PhantomData, } // NOTE(unsafe) Required to allow protected shared access in handlers unsafe impl Send for Tx {} macro_rules! usart { ($($USART:ident: ($usart:ident, $usarttx:ident, $usartrx:ident, $usartXen:ident, $apbenr:ident),)+) => { $( use crate::pac::$USART; impl Serial<$USART, TXPIN, RXPIN> where TXPIN: TxPin<$USART>, RXPIN: RxPin<$USART>, { /// Creates a new serial instance pub fn $usart(usart: $USART, pins: (TXPIN, RXPIN), baud_rate: Bps, rcc: &mut Rcc) -> Self { let mut serial = Serial { usart, pins }; serial.configure(baud_rate, rcc); // Enable transmission and receiving serial.usart.cr1.modify(|_, w| w.te().set_bit().re().set_bit().ue().set_bit()); serial } } impl Serial<$USART, TXPIN, ()> where TXPIN: TxPin<$USART>, { /// Creates a new tx-only serial instance pub fn $usarttx(usart: $USART, txpin: TXPIN, baud_rate: Bps, rcc: &mut Rcc) -> Self { let rxpin = (); let mut serial = Serial { usart, pins: (txpin, rxpin) }; serial.configure(baud_rate, rcc); // Enable transmission serial.usart.cr1.modify(|_, w| w.te().set_bit().ue().set_bit()); serial } } impl Serial<$USART, (), RXPIN> where RXPIN: RxPin<$USART>, { /// Creates a new tx-only serial instance pub fn $usartrx(usart: $USART, rxpin: RXPIN, baud_rate: Bps, rcc: &mut Rcc) -> Self { let txpin = (); let mut serial = Serial { usart, pins: (txpin, rxpin) }; serial.configure(baud_rate, rcc); // Enable receiving serial.usart.cr1.modify(|_, w| w.re().set_bit().ue().set_bit()); serial } } impl Serial<$USART, TXPIN, RXPIN> { fn configure(&mut self, baud_rate: Bps, rcc: &mut Rcc) { // Enable clock for USART rcc.regs.$apbenr.modify(|_, w| w.$usartXen().set_bit()); // Calculate correct baudrate divisor on the fly let brr = rcc.clocks.pclk().0 / baud_rate.0; self.usart.brr.write(|w| unsafe { w.bits(brr) }); // Reset other registers to disable advanced USART features self.usart.cr2.reset(); self.usart.cr3.reset(); } /// Starts listening for an interrupt event pub fn listen(&mut self, event: Event) { match event { Event::Rxne => { self.usart.cr1.modify(|_, w| w.rxneie().set_bit()) }, Event::Txe => { self.usart.cr1.modify(|_, w| w.txeie().set_bit()) }, Event::Idle => { self.usart.cr1.modify(|_, w| w.idleie().set_bit()) }, } } /// Stop listening for an interrupt event pub fn unlisten(&mut self, event: Event) { match event { Event::Rxne => { self.usart.cr1.modify(|_, w| w.rxneie().clear_bit()) }, Event::Txe => { self.usart.cr1.modify(|_, w| w.txeie().clear_bit()) }, Event::Idle => { self.usart.cr1.modify(|_, w| w.idleie().clear_bit()) }, } } } )+ } } usart! { USART1: (usart1, usart1tx, usart1rx, usart1en, apb2enr), } #[cfg(any( feature = "stm32f030x8", feature = "stm32f030xc", feature = "stm32f042", feature = "stm32f048", feature = "stm32f051", feature = "stm32f058", feature = "stm32f070", feature = "stm32f071", feature = "stm32f072", feature = "stm32f078", feature = "stm32f091", feature = "stm32f098", ))] usart! { USART2: (usart2, usart2tx, usart2rx,usart2en, apb1enr), } #[cfg(any( feature = "stm32f030xc", feature = "stm32f070xb", feature = "stm32f071", feature = "stm32f072", feature = "stm32f078", feature = "stm32f091", feature = "stm32f098", ))] usart! { USART3: (usart3, usart3tx, usart3rx,usart3en, apb1enr), USART4: (usart4, usart4tx, usart4rx,usart4en, apb1enr), } #[cfg(any(feature = "stm32f030xc", feature = "stm32f091", feature = "stm32f098"))] usart! { USART5: (usart5, usart5tx, usart5rx,usart5en, apb1enr), USART6: (usart6, usart6tx, usart6rx,usart6en, apb2enr), } impl embedded_hal::serial::Read for Rx where USART: Deref, { type Error = Error; /// Tries to read a byte from the uart fn read(&mut self) -> nb::Result { read(self.usart) } } impl embedded_hal::serial::Read for Serial where USART: Deref, RXPIN: RxPin, { type Error = Error; /// Tries to read a byte from the uart fn read(&mut self) -> nb::Result { read(&*self.usart) } } impl embedded_hal::serial::Write for Tx where USART: Deref, { type Error = Infallible; /// Ensures that none of the previously written words are still buffered fn flush(&mut self) -> nb::Result<(), Self::Error> { flush(self.usart) } /// Tries to write a byte to the uart /// Fails if the transmit buffer is full fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { write(self.usart, byte) } } impl embedded_hal::serial::Write for Serial where USART: Deref, TXPIN: TxPin, { type Error = Infallible; /// Ensures that none of the previously written words are still buffered fn flush(&mut self) -> nb::Result<(), Self::Error> { flush(&*self.usart) } /// Tries to write a byte to the uart /// Fails if the transmit buffer is full fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { write(&*self.usart, byte) } } impl Serial where USART: Deref, { /// Splits the UART Peripheral in a Tx and an Rx part /// This is required for sending/receiving pub fn split(self) -> (Tx, Rx) where TXPIN: TxPin, RXPIN: RxPin, { ( Tx { usart: &*self.usart, _instance: PhantomData, }, Rx { usart: &*self.usart, _instance: PhantomData, }, ) } pub fn release(self) -> (USART, (TXPIN, RXPIN)) { (self.usart, self.pins) } } impl Write for Tx where Tx: embedded_hal::serial::Write, { fn write_str(&mut self, s: &str) -> Result { s.as_bytes() .iter() .try_for_each(|c| nb::block!(self.write(*c))) .map_err(|_| core::fmt::Error) } } impl Write for Serial where USART: Deref, TXPIN: TxPin, { fn write_str(&mut self, s: &str) -> Result { s.as_bytes() .iter() .try_for_each(|c| nb::block!(self.write(*c))) .map_err(|_| core::fmt::Error) } } /// Ensures that none of the previously written words are still buffered fn flush(usart: *const SerialRegisterBlock) -> nb::Result<(), Infallible> { // NOTE(unsafe) atomic read with no side effects let isr = unsafe { (*usart).isr.read() }; if isr.tc().bit_is_set() { Ok(()) } else { Err(nb::Error::WouldBlock) } } /// Tries to write a byte to the UART /// Returns `Err(WouldBlock)` if the transmit buffer is full fn write(usart: *const SerialRegisterBlock, byte: u8) -> nb::Result<(), Infallible> { // NOTE(unsafe) atomic read with no side effects let isr = unsafe { (*usart).isr.read() }; if isr.txe().bit_is_set() { // NOTE(unsafe) atomic write to stateless register unsafe { (*usart).tdr.write(|w| w.tdr().bits(byte as u16)) } Ok(()) } else { Err(nb::Error::WouldBlock) } } /// Tries to read a byte from the UART fn read(usart: *const SerialRegisterBlock) -> nb::Result { // NOTE(unsafe) atomic read with no side effects let isr = unsafe { (*usart).isr.read() }; // NOTE(unsafe) write accessor for atomic writes with no side effects let icr = unsafe { &(*usart).icr }; if isr.pe().bit_is_set() { icr.write(|w| w.pecf().set_bit()); Err(nb::Error::Other(Error::Parity)) } else if isr.fe().bit_is_set() { icr.write(|w| w.fecf().set_bit()); Err(nb::Error::Other(Error::Framing)) } else if isr.nf().bit_is_set() { icr.write(|w| w.ncf().set_bit()); Err(nb::Error::Other(Error::Noise)) } else if isr.ore().bit_is_set() { icr.write(|w| w.orecf().set_bit()); Err(nb::Error::Other(Error::Overrun)) } else if isr.rxne().bit_is_set() { Ok(unsafe { (*usart).rdr.read().rdr().bits() as u8 }) } else { Err(nb::Error::WouldBlock) } }