diff --git a/CHANGELOG.md b/CHANGELOG.md index d418458a..db6be3c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Unmacro `Adc` - Use `write` instead of `modify` to clear flags - Bump `stm32f4-staging` to 0.18, update other dependencies +- `serial` mod refactor ## [v0.22.1] - 2024-11-03 diff --git a/Cargo.toml b/Cargo.toml index ed41e401..454a8406 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ micromath = { version = "2.1.0", optional = true } [dependencies.stm32f4] package = "stm32f4-staging" -version = "0.18.0" +version = "0.19.0" features = ["atomics"] [dependencies.time] @@ -168,7 +168,7 @@ gpio-f401 = [ "tim9", "tim10", "tim11", - "rcc_shared_m" + "rcc_shared_m", ] gpio-f410 = [ "dac", @@ -317,7 +317,7 @@ gpio-f417 = [ "usart3", "uart4", "uart5", - "rcc_shared_m" + "rcc_shared_m", ] gpio-f427 = [ "gpiod", @@ -364,7 +364,7 @@ gpio-f427 = [ "uart5", "uart7", "uart8", - "rcc_shared_m" + "rcc_shared_m", ] gpio-f446 = [ "gpiod", @@ -457,7 +457,7 @@ gpio-f469 = [ "uart5", "uart7", "uart8", - "rcc_shared_m" + "rcc_shared_m", ] ## Support monotonic timers and other stuff that can be used by [RTICv1 framework](https://crates.io/crates/cortex-m-rtic) diff --git a/examples/serial-dma.rs b/examples/serial-dma.rs index 3d457033..711402da 100644 --- a/examples/serial-dma.rs +++ b/examples/serial-dma.rs @@ -18,7 +18,7 @@ use stm32f4xx_hal::{ self, dma::{RxDMA, SerialDma, TxDMA}, }, - uart::{config::StopBits, Config, Serial}, + serial::{config::StopBits, Config, Serial}, }; /// Global variable for USART2 DMA handle. diff --git a/examples/uart-dma.rs b/examples/uart-dma.rs index 73d577f2..24c0ed4a 100644 --- a/examples/uart-dma.rs +++ b/examples/uart-dma.rs @@ -11,8 +11,7 @@ use cortex_m_rt::entry; use stm32f4xx_hal::dma::config::DmaConfig; use stm32f4xx_hal::pac::Interrupt; use stm32f4xx_hal::pac::{interrupt, DMA1}; -use stm32f4xx_hal::uart::config::StopBits; -use stm32f4xx_hal::uart::{Config, Rx, Serial}; +use stm32f4xx_hal::serial::{config::StopBits, Config, Rx, Serial}; use stm32f4xx_hal::{ dma::{StreamsTuple, Transfer}, pac, diff --git a/src/fmpi2c.rs b/src/fmpi2c.rs index b5b0ca25..c8a48b23 100644 --- a/src/fmpi2c.rs +++ b/src/fmpi2c.rs @@ -206,7 +206,7 @@ impl I2c { if isr.nackf().bit_is_set() { self.i2c .icr() - .write(|w| w.stopcf().set_bit().nackcf().set_bit()); + .write(|w| w.stopcf().clear_bit_by_one().nackcf().clear_bit_by_one()); return Err(Error::NoAcknowledge(NoAcknowledgeSource::Unknown)); } diff --git a/src/gpio.rs b/src/gpio.rs index 079dee62..9e30fd25 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -127,7 +127,7 @@ pub enum Pull { Down = 2, } -impl From for pac::gpioa::pupdr::PUPDR0 { +impl From for pac::gpioa::pupdr::PULL { fn from(value: Pull) -> Self { match value { Pull::Down => Self::PullDown, @@ -206,7 +206,7 @@ pub enum Speed { VeryHigh = 3, } -impl From for pac::gpioa::ospeedr::OSPEEDR0 { +impl From for pac::gpioa::ospeedr::OUTPUT_SPEED { fn from(value: Speed) -> Self { match value { Speed::Low => Self::LowSpeed, diff --git a/src/gpio/convert.rs b/src/gpio/convert.rs index 5ef222bf..2ac350c0 100644 --- a/src/gpio/convert.rs +++ b/src/gpio/convert.rs @@ -1,5 +1,5 @@ use super::*; -use crate::pac::gpioa::{moder::MODER0 as Mode, otyper::OT0 as OutputType}; +use crate::pac::gpioa::{moder::MODE as Mode, otyper::OUTPUT_TYPE as OutputType}; impl Input { pub fn new( diff --git a/src/lib.rs b/src/lib.rs index c7503a80..75ddecb8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,8 +132,6 @@ pub mod spi; pub mod syscfg; pub mod time; pub mod timer; -#[cfg(feature = "uart4")] -pub mod uart; pub mod watchdog; mod sealed { diff --git a/src/serial.rs b/src/serial.rs index d4192bb2..0d8f62b0 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -14,13 +14,16 @@ //! the embedded-hal read and write traits with `u16` as the word type. You can use these //! implementations for 9-bit words. +use core::fmt; use core::marker::PhantomData; +use enumflags2::BitFlags; +pub mod ext; +use ext::UartExt; mod hal_02; mod hal_1; -pub(crate) mod uart_impls; -pub use uart_impls::Instance; +mod uart_impls; use uart_impls::RegisterBlockImpl; use crate::gpio::{self, PushPull}; @@ -28,9 +31,13 @@ use crate::gpio::{self, PushPull}; use crate::pac; use crate::gpio::NoPin; -use crate::rcc::Clocks; +use crate::rcc::{self, Clocks}; pub mod dma; +use crate::dma::{ + traits::{DMASet, PeriAddress}, + MemoryToPeripheral, PeripheralToMemory, +}; /// Serial error kind /// @@ -57,7 +64,7 @@ pub enum Error { #[enumflags2::bitflags] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Eq, PartialEq, Copy, Clone)] -#[repr(u32)] +#[repr(u16)] pub enum Event { /// IDLE interrupt enable Idle = 1 << 4, @@ -75,7 +82,7 @@ pub enum Event { #[enumflags2::bitflags] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Eq, PartialEq, Copy, Clone)] -#[repr(u32)] +#[repr(u16)] pub enum Flag { /// Parity error ParityError = 1 << 0, @@ -103,7 +110,7 @@ pub enum Flag { #[enumflags2::bitflags] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, Eq, PartialEq, Copy, Clone)] -#[repr(u32)] +#[repr(u16)] pub enum CFlag { /// Read data register not empty RxNotEmpty = 1 << 5, @@ -124,6 +131,24 @@ pub use gpio::NoPin as NoRx; pub use gpio::alt::SerialAsync as CommonPins; +// Implemented by all USART/UART instances +pub trait Instance: + crate::Sealed + + crate::Ptr + + crate::Steal + + core::ops::Deref + + rcc::Enable + + rcc::Reset + + rcc::BusClock + + CommonPins +{ + #[doc(hidden)] + #[inline(always)] + fn peri_address() -> u32 { + unsafe { &*Self::ptr() }.peri_address() + } +} + /// Trait for [`Rx`] interrupt handling. pub trait RxISR { /// Return true if the line idle status is set @@ -232,7 +257,7 @@ pub trait SerialExt: Sized + Instance { impl Serial { pub fn new( - usart: USART, + uart: USART, pins: ( impl Into>, impl Into>, @@ -240,7 +265,115 @@ impl Serial { config: impl Into, clocks: &Clocks, ) -> Result { - ::RB::new(usart, pins, config, clocks) + use self::config::*; + + let config = config.into(); + unsafe { + // Enable clock. + USART::enable_unchecked(); + USART::reset_unchecked(); + } + + let pclk_freq = USART::clock(clocks).raw(); + let baud = config.baudrate.0; + + if !USART::RB::IRDA && config.irda != IrdaMode::None { + return Err(config::InvalidConfig); + } + + let (over8, div) = if config.irda != IrdaMode::None { + let div = (pclk_freq + (baud / 2)) / baud; + (false, div) + } else { + calculate_brr(pclk_freq, baud)? + }; + + uart.brr().write(|w| unsafe { w.bits(div as u16) }); + + // Reset other registers to disable advanced USART features + uart.cr2().reset(); + uart.cr3().reset(); + // IrDA configuration - see STM32F411xC/E (RM0383) sections: + // 19.3.12 "IrDA SIR ENDEC block" + // 19.6.7 "Guard time and prescaler register (USART_GTPR)" + if config.irda != IrdaMode::None && config.stopbits != StopBits::STOP1 { + return Err(config::InvalidConfig); + } + + uart.configure_irda(config.irda, pclk_freq); + + // Enable transmission and receiving + // and configure frame + + uart.cr1().write(|w| { + w.ue().set_bit(); + w.over8().bit(over8); + w.te().set_bit(); + w.re().set_bit(); + w.m().bit(config.wordlength == WordLength::DataBits9); + w.pce().bit(config.parity != Parity::ParityNone); + w.ps().bit(config.parity == Parity::ParityOdd) + }); + + uart.enable_dma(config.dma); + + let serial = Serial { + tx: Tx::new(uart, pins.0.into()), + rx: Rx::new(unsafe { USART::steal() }, pins.1.into()), + }; + serial.tx.usart.set_stopbits(config.stopbits); + Ok(serial) + } +} + +fn calculate_brr(pclk_freq: u32, baud: u32) -> Result<(bool, u32), config::InvalidConfig> { + // The frequency to calculate USARTDIV is this: + // + // (Taken from STM32F411xC/E Reference Manual, + // Section 19.3.4, Equation 1) + // + // 16 bit oversample: OVER8 = 0 + // 8 bit oversample: OVER8 = 1 + // + // USARTDIV = (pclk) + // ------------------------ + // 8 x (2 - OVER8) x (baud) + // + // BUT, the USARTDIV has 4 "fractional" bits, which effectively + // means that we need to "correct" the equation as follows: + // + // USARTDIV = (pclk) * 16 + // ------------------------ + // 8 x (2 - OVER8) x (baud) + // + // When OVER8 is enabled, we can only use the lowest three + // fractional bits, so we'll need to shift those last four bits + // right one bit + + // Calculate correct baudrate divisor on the fly + if (pclk_freq / 16) >= baud { + // We have the ability to oversample to 16 bits, take + // advantage of it. + // + // We also add `baud / 2` to the `pclk_freq` to ensure + // rounding of values to the closest scale, rather than the + // floored behavior of normal integer division. + let div = (pclk_freq + (baud / 2)) / baud; + Ok((false, div)) + } else if (pclk_freq / 8) >= baud { + // We are close enough to pclk where we can only + // oversample 8. + // + // See note above regarding `baud` and rounding. + let div = ((pclk_freq * 2) + (baud / 2)) / baud; + + // Ensure the the fractional bits (only 3) are + // right-aligned. + let frac = div & 0xF; + let div = (div & !0xF) | (frac >> 1); + Ok((true, div)) + } else { + Err(config::InvalidConfig) } } @@ -261,24 +394,10 @@ macro_rules! halUsart { pub type $Tx = Tx<$USART, WORD>; pub type $Rx = Rx<$USART, WORD>; - impl Instance for $USART { - fn set_stopbits(&self, bits: config::StopBits) { - use crate::pac::usart1::cr2::STOP; - use config::StopBits; - - self.cr2().write(|w| { - w.stop().variant(match bits { - StopBits::STOP0P5 => STOP::Stop0p5, - StopBits::STOP1 => STOP::Stop1, - StopBits::STOP1P5 => STOP::Stop1p5, - StopBits::STOP2 => STOP::Stop2, - }) - }); - } - } + impl Instance for $USART {} impl crate::Ptr for $USART { - type RB = crate::serial::uart_impls::RegisterBlockUsart; + type RB = crate::pac::usart1::RegisterBlock; fn ptr() -> *const Self::RB { Self::ptr() @@ -301,6 +420,44 @@ halUsart! { pac::USART6, Serial6, Rx6, Tx6 } #[cfg(feature = "usart3")] halUsart! { pac::USART3, Serial3, Rx3, Tx3 } +#[cfg(feature = "uart4")] +macro_rules! halUart { + ($UART:ty, $Serial:ident, $Rx:ident, $Tx:ident) => { + pub type $Serial = Serial<$UART, WORD>; + pub type $Tx = Tx<$UART, WORD>; + pub type $Rx = Rx<$UART, WORD>; + + impl Instance for $UART {} + + impl crate::Ptr for $UART { + type RB = crate::pac::uart4::RegisterBlock; + + fn ptr() -> *const Self::RB { + Self::ptr() + } + } + + impl crate::Steal for $UART { + unsafe fn steal() -> Self { + Self::steal() + } + } + }; +} + +#[cfg(feature = "uart4")] +halUart! { pac::UART4, Serial4, Rx4, Tx4 } +#[cfg(feature = "uart5")] +halUart! { pac::UART5, Serial5, Rx5, Tx5 } +#[cfg(feature = "uart7")] +halUart! { pac::UART7, Serial7, Rx7, Tx7 } +#[cfg(feature = "uart8")] +halUart! { pac::UART8, Serial8, Rx8, Tx8 } +#[cfg(feature = "uart9")] +halUart! { pac::UART9, Serial9, Rx9, Tx9 } +#[cfg(feature = "uart10")] +halUart! { pac::UART10, Serial10, Rx10, Tx10 } + impl Rx { pub(crate) fn with_u16_data(self) -> Rx { Rx::new(self.usart, self.pin) @@ -404,3 +561,206 @@ impl Serial { } } } + +impl RxISR for Serial +where + Rx: RxISR, +{ + fn is_idle(&self) -> bool { + self.rx.is_idle() + } + + fn is_rx_not_empty(&self) -> bool { + self.rx.is_rx_not_empty() + } + + /// This clears `Idle`, `Overrun`, `Noise`, `FrameError` and `ParityError` flags + fn clear_idle_interrupt(&self) { + self.rx.clear_idle_interrupt(); + } +} + +impl RxISR for Rx { + fn is_idle(&self) -> bool { + self.usart.is_idle() + } + + fn is_rx_not_empty(&self) -> bool { + self.usart.is_rx_not_empty() + } + + /// This clears `Idle`, `Overrun`, `Noise`, `FrameError` and `ParityError` flags + fn clear_idle_interrupt(&self) { + self.usart.clear_idle_interrupt(); + } +} + +impl TxISR for Serial +where + Tx: TxISR, +{ + fn is_tx_empty(&self) -> bool { + self.tx.is_tx_empty() + } +} + +impl TxISR for Tx { + fn is_tx_empty(&self) -> bool { + self.usart.is_tx_empty() + } +} + +impl RxListen for Rx { + fn listen(&mut self) { + self.usart.listen_rxne() + } + + fn unlisten(&mut self) { + self.usart.unlisten_rxne() + } + + fn listen_idle(&mut self) { + self.usart.listen_idle() + } + + fn unlisten_idle(&mut self) { + self.usart.unlisten_idle() + } +} + +impl TxListen for Tx { + fn listen(&mut self) { + self.usart.listen_txe() + } + + fn unlisten(&mut self) { + self.usart.unlisten_txe() + } +} + +impl crate::ClearFlags for Serial { + type Flag = CFlag; + + #[inline(always)] + fn clear_flags(&mut self, flags: impl Into>) { + self.tx.usart.clear_flags(flags.into()) + } +} + +impl crate::ReadFlags for Serial { + type Flag = Flag; + + #[inline(always)] + fn flags(&self) -> BitFlags { + self.tx.usart.flags() + } +} + +impl crate::Listen for Serial { + type Event = Event; + + #[inline(always)] + fn listen(&mut self, event: impl Into>) { + self.tx.usart.listen_event(None, Some(event.into())); + } + + #[inline(always)] + fn listen_only(&mut self, event: impl Into>) { + self.tx + .usart + .listen_event(Some(BitFlags::ALL), Some(event.into())); + } + + #[inline(always)] + fn unlisten(&mut self, event: impl Into>) { + self.tx.usart.listen_event(Some(event.into()), None); + } +} + +impl fmt::Write for Serial +where + Tx: fmt::Write, +{ + fn write_str(&mut self, s: &str) -> fmt::Result { + self.tx.write_str(s) + } +} + +impl fmt::Write for Tx { + fn write_str(&mut self, s: &str) -> fmt::Result { + s.bytes() + .try_for_each(|c| nb::block!(self.usart.write_u8(c))) + .map_err(|_| fmt::Error) + } +} + +impl SerialExt for UART { + fn serial( + self, + pins: (impl Into>, impl Into>), + config: impl Into, + clocks: &Clocks, + ) -> Result, config::InvalidConfig> { + Serial::new(self, pins, config, clocks) + } +} + +impl Serial { + pub fn tx( + usart: UART, + tx_pin: impl Into>, + config: impl Into, + clocks: &Clocks, + ) -> Result, config::InvalidConfig> + where + NoPin: Into>, + { + Self::new(usart, (tx_pin, NoPin::new()), config, clocks).map(|s| s.split().0) + } +} + +impl Serial { + pub fn rx( + usart: UART, + rx_pin: impl Into>, + config: impl Into, + clocks: &Clocks, + ) -> Result, config::InvalidConfig> + where + NoPin: Into>, + { + Self::new(usart, (NoPin::new(), rx_pin), config, clocks).map(|s| s.split().1) + } +} + +unsafe impl PeriAddress for Rx { + #[inline(always)] + fn address(&self) -> u32 { + self.usart.peri_address() + } + + type MemSize = u8; +} + +unsafe impl DMASet + for Rx +where + UART: DMASet, +{ +} + +unsafe impl PeriAddress for Tx { + #[inline(always)] + fn address(&self) -> u32 { + self.usart.peri_address() + } + + type MemSize = u8; +} + +unsafe impl DMASet + for Tx +where + UART: DMASet, +{ +} diff --git a/src/serial/ext.rs b/src/serial/ext.rs new file mode 100644 index 00000000..848c1a68 --- /dev/null +++ b/src/serial/ext.rs @@ -0,0 +1,325 @@ +#![allow(unused)] + +use crate::{sealed, Sealed}; + +#[cfg(feature = "uart4")] +use crate::pac::uart4; +use crate::pac::usart1; +use stm32f4::{Readable, Reg, RegisterSpec, Resettable, Writable, R, W}; + +pub trait UartExt: Sealed { + fn cr1(&self) -> &usart1::CR1; + fn dr(&self) -> &usart1::DR; + fn brr(&self) -> &usart1::BRR; + type SRrs: reg::SrR + reg::SrW; + fn sr(&self) -> &Reg; + type CR2rs: reg::Cr2R + reg::Cr2W; + fn cr2(&self) -> &Reg; + type CR3rs: reg::Cr3R + reg::Cr3W; + fn cr3(&self) -> &Reg; + type GTPRrs: reg::GtprR + reg::GtprW; + fn gtpr(&self) -> &Reg; +} + +macro_rules! wrap_r { + (pub trait $TrR:ident { + $(fn $f:ident(&self $(, $n:ident: u8)?) -> $fr:path;)* + }) => { + pub trait $TrR { + $(fn $f(&self $(, $n: u8)?) -> $fr;)* + } + impl $TrR for R { + $( + #[inline(always)] + fn $f(&self $(, $n: u8)?) -> $fr { + REG::$f(self $(, $n)?) + } + )* + } + }; +} + +macro_rules! wrap_w { + (pub trait $TrR:ident { + $(fn $f:ident(&mut self $(, $n:ident: u8)?) -> $fr:path;)* + }) => { + pub trait $TrR { + $(fn $f(&mut self $(, $n: u8)?) -> $fr;)* + } + + impl $TrR for W { + $( + #[inline(always)] + fn $f(&mut self $(, $n: u8)?) -> $fr { + REG::$f(self $(, $n)?) + } + )* + } + }; +} + +wrap_r! { + pub trait SrR { + fn pe(&self) -> usart1::sr::PE_R; + fn fe(&self) -> usart1::sr::FE_R; + fn nf(&self) -> usart1::sr::NF_R; + fn ore(&self) -> usart1::sr::ORE_R; + fn idle(&self) -> usart1::sr::IDLE_R; + fn rxne(&self) -> usart1::sr::RXNE_R; + fn tc(&self) -> usart1::sr::TC_R; + fn txe(&self) -> usart1::sr::TXE_R; + fn lbd(&self) -> usart1::sr::LBD_R; + } +} +wrap_w! { + pub trait SrW { + fn rxne(&mut self) -> usart1::sr::RXNE_W; + fn tc(&mut self) -> usart1::sr::TC_W; + fn lbd(&mut self) -> usart1::sr::LBD_W; + } +} + +wrap_r! { + pub trait Cr2R { + fn add(&self) -> usart1::cr2::ADD_R; + fn lbdl(&self) -> usart1::cr2::LBDL_R; + fn lbdie(&self) -> usart1::cr2::LBDIE_R; + fn linen(&self) -> usart1::cr2::LINEN_R; + } +} +wrap_w! { + pub trait Cr2W { + fn add(&mut self) -> usart1::cr2::ADD_W; + fn lbdl(&mut self) -> usart1::cr2::LBDL_W; + fn lbdie(&mut self) -> usart1::cr2::LBDIE_W; + fn linen(&mut self) -> usart1::cr2::LINEN_W; + } +} + +wrap_r! { + pub trait Cr3R { + fn eie(&self) -> usart1::cr3::EIE_R; + fn iren(&self) -> usart1::cr3::IREN_R; + fn irlp(&self) -> usart1::cr3::IRLP_R; + fn hdsel(&self) -> usart1::cr3::HDSEL_R; + fn dmar(&self) -> usart1::cr3::DMAR_R; + fn dmat(&self) -> usart1::cr3::DMAT_R; + fn onebit(&self) -> usart1::cr3::ONEBIT_R; + } +} +wrap_w! { + pub trait Cr3W { + fn eie(&mut self) -> usart1::cr3::EIE_W; + fn iren(&mut self) -> usart1::cr3::IREN_W; + fn irlp(&mut self) -> usart1::cr3::IRLP_W; + fn hdsel(&mut self) -> usart1::cr3::HDSEL_W; + fn dmar(&mut self) -> usart1::cr3::DMAR_W; + fn dmat(&mut self) -> usart1::cr3::DMAT_W; + fn onebit(&mut self) -> usart1::cr3::ONEBIT_W; + } +} + +wrap_r! { + pub trait GtprR { + fn psc(&self) -> usart1::gtpr::PSC_R; + } +} +wrap_w! { + pub trait GtprW { + fn psc(&mut self) -> usart1::gtpr::PSC_W; + } +} + +mod reg { + use super::*; + + pub trait SrR: RegisterSpec + Readable + Sized { + fn pe(r: &R) -> usart1::sr::PE_R; + fn fe(r: &R) -> usart1::sr::FE_R; + fn nf(r: &R) -> usart1::sr::NF_R; + fn ore(r: &R) -> usart1::sr::ORE_R; + fn idle(r: &R) -> usart1::sr::IDLE_R; + fn rxne(r: &R) -> usart1::sr::RXNE_R; + fn tc(r: &R) -> usart1::sr::TC_R; + fn txe(r: &R) -> usart1::sr::TXE_R; + fn lbd(r: &R) -> usart1::sr::LBD_R; + } + pub trait SrW: RegisterSpec + Writable + Resettable + Sized { + fn rxne(w: &mut W) -> usart1::sr::RXNE_W; + fn tc(w: &mut W) -> usart1::sr::TC_W; + fn lbd(w: &mut W) -> usart1::sr::LBD_W; + } + + pub trait Cr2R: RegisterSpec + Readable + Sized { + fn add(r: &R) -> usart1::cr2::ADD_R; + fn lbdl(r: &R) -> usart1::cr2::LBDL_R; + fn lbdie(r: &R) -> usart1::cr2::LBDIE_R; + fn linen(r: &R) -> usart1::cr2::LINEN_R; + } + pub trait Cr2W: RegisterSpec + Writable + Resettable + Sized { + fn add(w: &mut W) -> usart1::cr2::ADD_W; + fn lbdl(w: &mut W) -> usart1::cr2::LBDL_W; + fn lbdie(w: &mut W) -> usart1::cr2::LBDIE_W; + fn linen(w: &mut W) -> usart1::cr2::LINEN_W; + } + + pub trait Cr3R: RegisterSpec + Readable + Sized { + fn eie(r: &R) -> usart1::cr3::EIE_R; + fn iren(r: &R) -> usart1::cr3::IREN_R; + fn irlp(r: &R) -> usart1::cr3::IRLP_R; + fn hdsel(r: &R) -> usart1::cr3::HDSEL_R; + fn dmar(r: &R) -> usart1::cr3::DMAR_R; + fn dmat(r: &R) -> usart1::cr3::DMAT_R; + fn onebit(r: &R) -> usart1::cr3::ONEBIT_R; + } + pub trait Cr3W: RegisterSpec + Writable + Resettable + Sized { + fn eie(w: &mut W) -> usart1::cr3::EIE_W; + fn iren(w: &mut W) -> usart1::cr3::IREN_W; + fn irlp(w: &mut W) -> usart1::cr3::IRLP_W; + fn hdsel(w: &mut W) -> usart1::cr3::HDSEL_W; + fn dmar(w: &mut W) -> usart1::cr3::DMAR_W; + fn dmat(w: &mut W) -> usart1::cr3::DMAT_W; + fn onebit(w: &mut W) -> usart1::cr3::ONEBIT_W; + } + + pub trait GtprR: RegisterSpec + Readable + Sized { + fn psc(r: &R) -> usart1::gtpr::PSC_R; + } + pub trait GtprW: RegisterSpec + Writable + Resettable + Sized { + fn psc(w: &mut W) -> usart1::gtpr::PSC_W; + } +} + +macro_rules! impl_reg { + ($($r:ident -> &$rty:path;)*) => { + $( + #[inline(always)] + fn $r(&self) -> &$rty { + self.$r() + } + )* + }; +} + +macro_rules! impl_read { + ($($f:ident $(: $n:ident)? -> $fty:path;)*) => { + $( + #[inline(always)] + fn $f(r: &R $(, $n: u8)?) -> $fty { + r.$f($($n)?) + } + )* + }; +} +macro_rules! impl_write { + ($($f:ident $(: $n:ident)? -> $fty:path;)*) => { + $( + #[inline(always)] + fn $f(w: &mut W $(, $n: u8)?) -> $fty { + w.$f($($n)?) + } + )* + }; +} + +macro_rules! impl_ext { + ($(#[$attr:meta])* $uart:ident) => { + impl Sealed for $uart::RegisterBlock {} + impl UartExt for $uart::RegisterBlock { + type SRrs = $uart::sr::SRrs; + type CR2rs = $uart::cr2::CR2rs; + type CR3rs = $uart::cr3::CR3rs; + type GTPRrs = $uart::gtpr::GTPRrs; + impl_reg! { + cr1 -> &usart1::CR1; + dr -> &usart1::DR; + brr -> &usart1::BRR; + sr -> &Reg; + cr2 -> &Reg; + cr3 -> &Reg; + gtpr -> &Reg; + } + } + + impl reg::SrR for $uart::sr::SRrs { + impl_read! { + pe -> usart1::sr::PE_R; + fe -> usart1::sr::FE_R; + nf -> usart1::sr::NF_R; + ore -> usart1::sr::ORE_R; + idle -> usart1::sr::IDLE_R; + rxne -> usart1::sr::RXNE_R; + tc -> usart1::sr::TC_R; + txe -> usart1::sr::TXE_R; + lbd -> usart1::sr::LBD_R; + } + } + impl reg::SrW for $uart::sr::SRrs { + impl_write! { + rxne -> usart1::sr::RXNE_W; + tc -> usart1::sr::TC_W; + lbd -> usart1::sr::LBD_W; + } + } + + impl reg::Cr2R for $uart::cr2::CR2rs { + impl_read! { + add -> usart1::cr2::ADD_R; + lbdl -> usart1::cr2::LBDL_R; + lbdie -> usart1::cr2::LBDIE_R; + linen -> usart1::cr2::LINEN_R; + } + } + impl reg::Cr2W for $uart::cr2::CR2rs { + impl_write! { + add -> usart1::cr2::ADD_W; + lbdl -> usart1::cr2::LBDL_W; + lbdie -> usart1::cr2::LBDIE_W; + linen -> usart1::cr2::LINEN_W; + } + } + + $(#[$attr])* + impl reg::Cr3R for $uart::cr3::CR3rs { + impl_read! { + eie -> usart1::cr3::EIE_R; + iren -> usart1::cr3::IREN_R; + irlp -> usart1::cr3::IRLP_R; + hdsel -> usart1::cr3::HDSEL_R; + dmar -> usart1::cr3::DMAR_R; + dmat -> usart1::cr3::DMAT_R; + onebit -> usart1::cr3::ONEBIT_R; + } + } + $(#[$attr])* + impl reg::Cr3W for $uart::cr3::CR3rs { + impl_write! { + eie -> usart1::cr3::EIE_W; + iren -> usart1::cr3::IREN_W; + irlp -> usart1::cr3::IRLP_W; + hdsel -> usart1::cr3::HDSEL_W; + dmar -> usart1::cr3::DMAR_W; + dmat -> usart1::cr3::DMAT_W; + onebit -> usart1::cr3::ONEBIT_W; + } + } + + impl reg::GtprR for $uart::gtpr::GTPRrs { + impl_read! { + psc -> usart1::gtpr::PSC_R; + } + } + impl reg::GtprW for $uart::gtpr::GTPRrs { + impl_write! { + psc -> usart1::gtpr::PSC_W; + } + } + }; +} + +impl_ext!(usart1); +#[cfg(feature = "uart4")] +impl_ext!( + #[cfg(not(feature = "gpio-f446"))] + uart4 +); diff --git a/src/serial/uart_impls.rs b/src/serial/uart_impls.rs index 1a7b2cff..9e7cc23e 100644 --- a/src/serial/uart_impls.rs +++ b/src/serial/uart_impls.rs @@ -1,69 +1,75 @@ -use core::fmt; - +use super::{config, config::IrdaMode, ext::*, CFlag, Error, Event, Flag}; use enumflags2::BitFlags; -use nb::block; - -use super::{ - config, CFlag, Error, Event, Flag, Rx, RxISR, RxListen, Serial, SerialExt, Tx, TxISR, TxListen, -}; -use crate::dma::{ - traits::{DMASet, PeriAddress}, - MemoryToPeripheral, PeripheralToMemory, -}; -use crate::gpio::{alt::SerialAsync as CommonPins, NoPin, PushPull}; -use crate::rcc::{self, Clocks}; -#[cfg(feature = "uart4")] -pub(crate) use crate::pac::uart4::RegisterBlock as RegisterBlockUart; -pub(crate) use crate::pac::usart1::RegisterBlock as RegisterBlockUsart; +pub trait RegisterBlockImpl: UartExt { + const IRDA: bool; + fn configure_irda(&self, irda: IrdaMode, pclk_freq: u32); + fn set_stopbits(&self, bits: config::StopBits); -#[cfg(feature = "uart4")] -impl crate::Sealed for RegisterBlockUart {} -impl crate::Sealed for RegisterBlockUsart {} + fn read_u16(&self) -> nb::Result { + // NOTE(unsafe) atomic read with no side effects + let sr = self.sr().read(); + + // Any error requires the dr to be read to clear + if sr.pe().bit_is_set() + || sr.fe().bit_is_set() + || sr.nf().bit_is_set() + || sr.ore().bit_is_set() + { + self.dr().read(); + } -// Implemented by all USART/UART instances -pub trait Instance: - crate::Sealed - + crate::Ptr - + crate::Steal - + core::ops::Deref - + rcc::Enable - + rcc::Reset - + rcc::BusClock - + CommonPins -{ - #[doc(hidden)] - fn set_stopbits(&self, bits: config::StopBits); - #[doc(hidden)] - #[inline(always)] - fn peri_address() -> u32 { - unsafe { &*Self::ptr() }.peri_address() + Err(if sr.pe().bit_is_set() { + Error::Parity.into() + } else if sr.fe().bit_is_set() { + Error::FrameFormat.into() + } else if sr.nf().bit_is_set() { + Error::Noise.into() + } else if sr.ore().bit_is_set() { + Error::Overrun.into() + } else if sr.rxne().bit_is_set() { + // NOTE(unsafe) atomic read from stateless register + return Ok(self.dr().read().dr().bits()); + } else { + nb::Error::WouldBlock + }) } -} -pub trait RegisterBlockImpl: crate::Sealed { - #[allow(clippy::new_ret_no_self)] - fn new, WORD>( - uart: UART, - pins: (impl Into>, impl Into>), - config: impl Into, - clocks: &Clocks, - ) -> Result, config::InvalidConfig>; + fn write_u16(&self, word: u16) -> nb::Result<(), Error> { + // NOTE(unsafe) atomic read with no side effects + let sr = self.sr().read(); - fn read_u16(&self) -> nb::Result; - fn write_u16(&self, word: u16) -> nb::Result<(), Error>; + if sr.txe().bit_is_set() { + // NOTE(unsafe) atomic write to stateless register + self.dr().write(|w| w.dr().set(word)); + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } + #[inline(always)] fn read_u8(&self) -> nb::Result { // Delegate to u16 version, then truncate to 8 bits self.read_u16().map(|word16| word16 as u8) } + #[inline(always)] fn write_u8(&self, word: u8) -> nb::Result<(), Error> { // Delegate to u16 version self.write_u16(u16::from(word)) } - fn flush(&self) -> nb::Result<(), Error>; + fn flush(&self) -> nb::Result<(), Error> { + // NOTE(unsafe) atomic read with no side effects + let sr = self.sr().read(); + + if sr.tc().bit_is_set() { + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } fn bread_all_u8(&self, buffer: &mut [u8]) -> Result<(), Error> { for b in buffer.iter_mut() { @@ -93,30 +99,76 @@ pub trait RegisterBlockImpl: crate::Sealed { Ok(()) } + #[inline(always)] fn bflush(&self) -> Result<(), Error> { nb::block!(self.flush()) } // ISR - fn flags(&self) -> BitFlags; + #[inline(always)] + fn flags(&self) -> BitFlags { + BitFlags::from_bits_truncate(self.sr().read().bits()) + } + #[inline(always)] fn is_idle(&self) -> bool { self.flags().contains(Flag::Idle) } + #[inline(always)] fn is_rx_not_empty(&self) -> bool { self.flags().contains(Flag::RxNotEmpty) } + #[inline(always)] fn is_tx_empty(&self) -> bool { self.flags().contains(Flag::TxEmpty) } - fn clear_flags(&self, flags: BitFlags); - fn clear_idle_interrupt(&self); - fn check_and_clear_error_flags(&self) -> Result<(), Error>; - fn enable_error_interrupt_generation(&self); - fn disable_error_interrupt_generation(&self); + #[inline(always)] + fn clear_flags(&self, flags: BitFlags) { + self.sr() + .write(|w| unsafe { w.bits(0xffff & !flags.bits()) }); + } + fn clear_idle_interrupt(&self) { + let _ = self.sr().read(); + let _ = self.dr().read(); + } + fn check_and_clear_error_flags(&self) -> Result<(), Error> { + let sr = self.sr().read(); + let _ = self.dr().read(); + + if sr.ore().bit_is_set() { + Err(Error::Overrun) + } else if sr.nf().bit_is_set() { + Err(Error::Noise) + } else if sr.fe().bit_is_set() { + Err(Error::FrameFormat) + } else if sr.pe().bit_is_set() { + Err(Error::Parity) + } else { + Ok(()) + } + } + fn enable_error_interrupt_generation(&self) { + self.cr3().modify(|_, w| w.eie().enabled()); + } + fn disable_error_interrupt_generation(&self) { + self.cr3().modify(|_, w| w.eie().disabled()); + } // Listen - fn listen_event(&self, disable: Option>, enable: Option>); + fn listen_event(&self, disable: Option>, enable: Option>) { + self.cr1().modify(|r, w| unsafe { + w.bits({ + let mut bits = r.bits(); + if let Some(d) = disable { + bits &= !(d.bits()); + } + if let Some(e) = enable { + bits |= e.bits(); + } + bits + }) + }); + } #[inline(always)] fn listen_rxne(&self) { @@ -144,529 +196,79 @@ pub trait RegisterBlockImpl: crate::Sealed { } // PeriAddress - fn peri_address(&self) -> u32; - - fn enable_dma(&self, dc: config::DmaConfig); - - fn calculate_brr(pclk_freq: u32, baud: u32) -> Result<(bool, u32), config::InvalidConfig>; -} - -macro_rules! uartCommon { - () => { - fn read_u16(&self) -> nb::Result { - // NOTE(unsafe) atomic read with no side effects - let sr = self.sr().read(); - - // Any error requires the dr to be read to clear - if sr.pe().bit_is_set() - || sr.fe().bit_is_set() - || sr.nf().bit_is_set() - || sr.ore().bit_is_set() - { - self.dr().read(); - } - - Err(if sr.pe().bit_is_set() { - Error::Parity.into() - } else if sr.fe().bit_is_set() { - Error::FrameFormat.into() - } else if sr.nf().bit_is_set() { - Error::Noise.into() - } else if sr.ore().bit_is_set() { - Error::Overrun.into() - } else if sr.rxne().bit_is_set() { - // NOTE(unsafe) atomic read from stateless register - return Ok(self.dr().read().dr().bits()); - } else { - nb::Error::WouldBlock - }) - } - - fn write_u16(&self, word: u16) -> nb::Result<(), Error> { - // NOTE(unsafe) atomic read with no side effects - let sr = self.sr().read(); - - if sr.txe().bit_is_set() { - // NOTE(unsafe) atomic write to stateless register - self.dr().write(|w| w.dr().set(word)); - Ok(()) - } else { - Err(nb::Error::WouldBlock) - } - } - - fn flush(&self) -> nb::Result<(), Error> { - // NOTE(unsafe) atomic read with no side effects - let sr = self.sr().read(); + fn peri_address(&self) -> u32 { + self.dr().as_ptr() as u32 + } - if sr.tc().bit_is_set() { - Ok(()) - } else { - Err(nb::Error::WouldBlock) + fn enable_dma(&self, dc: config::DmaConfig) { + use config::DmaConfig; + match dc { + DmaConfig::Tx => { + self.cr3().write(|w| w.dmat().enabled()); } - } - - fn flags(&self) -> BitFlags { - BitFlags::from_bits_truncate(self.sr().read().bits()) - } - - fn clear_flags(&self, flags: BitFlags) { - self.sr() - .write(|w| unsafe { w.bits(0xffff & !flags.bits()) }); - } - - fn clear_idle_interrupt(&self) { - let _ = self.sr().read(); - let _ = self.dr().read(); - } - - fn check_and_clear_error_flags(&self) -> Result<(), Error> { - let sr = self.sr().read(); - let _ = self.dr().read(); - - if sr.ore().bit_is_set() { - Err(Error::Overrun) - } else if sr.nf().bit_is_set() { - Err(Error::Noise) - } else if sr.fe().bit_is_set() { - Err(Error::FrameFormat) - } else if sr.pe().bit_is_set() { - Err(Error::Parity) - } else { - Ok(()) + DmaConfig::Rx => { + self.cr3().write(|w| w.dmar().enabled()); } - } - - fn enable_error_interrupt_generation(&self) { - self.cr3().modify(|_, w| w.eie().enabled()); - } - - fn disable_error_interrupt_generation(&self) { - self.cr3().modify(|_, w| w.eie().disabled()); - } - - fn listen_event(&self, disable: Option>, enable: Option>) { - self.cr1().modify(|r, w| unsafe { - w.bits({ - let mut bits = r.bits(); - if let Some(d) = disable { - bits &= !(d.bits() as u32); - } - if let Some(e) = enable { - bits |= e.bits() as u32; - } - bits - }) - }); - } - - fn peri_address(&self) -> u32 { - self.dr().as_ptr() as u32 - } - - fn enable_dma(&self, dc: config::DmaConfig) { - use config::DmaConfig; - match dc { - DmaConfig::Tx => { - self.cr3().write(|w| w.dmat().enabled()); - } - DmaConfig::Rx => { - self.cr3().write(|w| w.dmar().enabled()); - } - DmaConfig::TxRx => { - self.cr3().write(|w| w.dmar().enabled().dmat().enabled()); - } - DmaConfig::None => {} + DmaConfig::TxRx => { + self.cr3().write(|w| { + w.dmar().enabled(); + w.dmat().enabled() + }); } + DmaConfig::None => {} } - - fn calculate_brr(pclk_freq: u32, baud: u32) -> Result<(bool, u32), config::InvalidConfig> { - // The frequency to calculate USARTDIV is this: - // - // (Taken from STM32F411xC/E Reference Manual, - // Section 19.3.4, Equation 1) - // - // 16 bit oversample: OVER8 = 0 - // 8 bit oversample: OVER8 = 1 - // - // USARTDIV = (pclk) - // ------------------------ - // 8 x (2 - OVER8) x (baud) - // - // BUT, the USARTDIV has 4 "fractional" bits, which effectively - // means that we need to "correct" the equation as follows: - // - // USARTDIV = (pclk) * 16 - // ------------------------ - // 8 x (2 - OVER8) x (baud) - // - // When OVER8 is enabled, we can only use the lowest three - // fractional bits, so we'll need to shift those last four bits - // right one bit - - // Calculate correct baudrate divisor on the fly - if (pclk_freq / 16) >= baud { - // We have the ability to oversample to 16 bits, take - // advantage of it. - // - // We also add `baud / 2` to the `pclk_freq` to ensure - // rounding of values to the closest scale, rather than the - // floored behavior of normal integer division. - let div = (pclk_freq + (baud / 2)) / baud; - Ok((false, div)) - } else if (pclk_freq / 8) >= baud { - // We are close enough to pclk where we can only - // oversample 8. - // - // See note above regarding `baud` and rounding. - let div = ((pclk_freq * 2) + (baud / 2)) / baud; - - // Ensure the the fractional bits (only 3) are - // right-aligned. - let frac = div & 0xF; - let div = (div & !0xF) | (frac >> 1); - Ok((true, div)) - } else { - Err(config::InvalidConfig) - } - } - }; + } } -impl RegisterBlockImpl for RegisterBlockUsart { - fn new, WORD>( - uart: UART, - pins: (impl Into>, impl Into>), - config: impl Into, - clocks: &Clocks, - ) -> Result, config::InvalidConfig> -where { - use self::config::*; - - let config = config.into(); - unsafe { - // Enable clock. - UART::enable_unchecked(); - UART::reset_unchecked(); - } - - let pclk_freq = UART::clock(clocks).raw(); - let baud = config.baudrate.0; - - let (over8, div) = if config.irda != IrdaMode::None { - let div = (pclk_freq + (baud / 2)) / baud; - (false, div) - } else { - Self::calculate_brr(pclk_freq, baud)? - }; - - uart.brr().write(|w| unsafe { w.bits(div) }); - - // Reset other registers to disable advanced USART features - uart.cr2().reset(); - uart.cr3().reset(); // IrDA configuration - see STM32F411xC/E (RM0383) sections: - // 19.3.12 "IrDA SIR ENDEC block" - // 19.6.7 "Guard time and prescaler register (USART_GTPR)" - if config.irda != IrdaMode::None && config.stopbits != StopBits::STOP1 { - return Err(config::InvalidConfig); - } - - match config.irda { +impl RegisterBlockImpl for crate::pac::usart1::RegisterBlock { + const IRDA: bool = true; + fn set_stopbits(&self, bits: config::StopBits) { + use crate::pac::usart1::cr2::STOP; + use config::StopBits; + + self.cr2().write(|w| { + w.stop().variant(match bits { + StopBits::STOP0P5 => STOP::Stop0p5, + StopBits::STOP1 => STOP::Stop1, + StopBits::STOP1P5 => STOP::Stop1p5, + StopBits::STOP2 => STOP::Stop2, + }) + }); + } + fn configure_irda(&self, irda: IrdaMode, pclk_freq: u32) { + match irda { IrdaMode::Normal => unsafe { - uart.gtpr().reset(); - uart.cr3().write(|w| w.iren().enabled()); - uart.gtpr().write(|w| w.psc().bits(1u8)); + self.gtpr().reset(); + self.cr3().write(|w| w.iren().enabled()); + self.gtpr().write(|w| w.psc().bits(1u8)); }, IrdaMode::LowPower => unsafe { - uart.gtpr().reset(); - uart.cr3().write(|w| w.iren().enabled().irlp().low_power()); + self.gtpr().reset(); + self.cr3().write(|w| w.iren().enabled().irlp().low_power()); // FIXME - uart.gtpr() + self.gtpr() .write(|w| w.psc().bits((1843200u32 / pclk_freq) as u8)); }, IrdaMode::None => {} } - - // Enable transmission and receiving - // and configure frame - - uart.cr1().write(|w| { - w.ue().set_bit(); - w.over8().bit(over8); - w.te().set_bit(); - w.re().set_bit(); - w.m().bit(config.wordlength == WordLength::DataBits9); - w.pce().bit(config.parity != Parity::ParityNone); - w.ps().bit(config.parity == Parity::ParityOdd) - }); - - uart.enable_dma(config.dma); - - let serial = Serial { - tx: Tx::new(uart, pins.0.into()), - rx: Rx::new(unsafe { UART::steal() }, pins.1.into()), - }; - serial.tx.usart.set_stopbits(config.stopbits); - Ok(serial) } - - uartCommon! {} } #[cfg(feature = "uart4")] -impl RegisterBlockImpl for RegisterBlockUart { - fn new, WORD>( - uart: UART, - pins: (impl Into>, impl Into>), - config: impl Into, - clocks: &Clocks, - ) -> Result, config::InvalidConfig> -where { - use self::config::*; - - let config = config.into(); - unsafe { - // Enable clock. - UART::enable_unchecked(); - UART::reset_unchecked(); - } - - let pclk_freq = UART::clock(clocks).raw(); - let baud = config.baudrate.0; - - let (over8, div) = Self::calculate_brr(pclk_freq, baud)?; - - uart.brr().write(|w| unsafe { w.bits(div) }); - - // Reset other registers to disable advanced USART features - uart.cr2().reset(); - uart.cr3().reset(); - - // Enable transmission and receiving - // and configure frame - - uart.cr1().write(|w| { - w.ue().set_bit(); - w.over8().bit(over8); - w.te().set_bit(); - w.re().set_bit(); - w.m().bit(config.wordlength == WordLength::DataBits9); - w.pce().bit(config.parity != Parity::ParityNone); - w.ps().bit(config.parity == Parity::ParityOdd) +impl RegisterBlockImpl for crate::pac::uart4::RegisterBlock { + const IRDA: bool = false; + fn set_stopbits(&self, bits: config::StopBits) { + use crate::pac::uart4::cr2::STOP; + use config::StopBits; + + // StopBits::STOP0P5 and StopBits::STOP1P5 aren't supported when using UART + // STOP_A::STOP1 and STOP_A::STOP2 will be used, respectively + self.cr2().write(|w| { + w.stop().variant(match bits { + StopBits::STOP0P5 | StopBits::STOP1 => STOP::Stop1, + StopBits::STOP1P5 | StopBits::STOP2 => STOP::Stop2, + }) }); - - uart.enable_dma(config.dma); - - let serial = Serial { - tx: Tx::new(uart, pins.0.into()), - rx: Rx::new(unsafe { UART::steal() }, pins.1.into()), - }; - serial.tx.usart.set_stopbits(config.stopbits); - Ok(serial) - } - - uartCommon! {} -} - -impl RxISR for Serial -where - Rx: RxISR, -{ - fn is_idle(&self) -> bool { - self.rx.is_idle() - } - - fn is_rx_not_empty(&self) -> bool { - self.rx.is_rx_not_empty() - } - - /// This clears `Idle`, `Overrun`, `Noise`, `FrameError` and `ParityError` flags - fn clear_idle_interrupt(&self) { - self.rx.clear_idle_interrupt(); - } -} - -impl RxISR for Rx { - fn is_idle(&self) -> bool { - self.usart.is_idle() - } - - fn is_rx_not_empty(&self) -> bool { - self.usart.is_rx_not_empty() - } - - /// This clears `Idle`, `Overrun`, `Noise`, `FrameError` and `ParityError` flags - fn clear_idle_interrupt(&self) { - self.usart.clear_idle_interrupt(); - } -} - -impl TxISR for Serial -where - Tx: TxISR, -{ - fn is_tx_empty(&self) -> bool { - self.tx.is_tx_empty() - } -} - -impl TxISR for Tx { - fn is_tx_empty(&self) -> bool { - self.usart.is_tx_empty() - } -} - -impl RxListen for Rx { - fn listen(&mut self) { - self.usart.listen_rxne() - } - - fn unlisten(&mut self) { - self.usart.unlisten_rxne() - } - - fn listen_idle(&mut self) { - self.usart.listen_idle() - } - - fn unlisten_idle(&mut self) { - self.usart.unlisten_idle() - } -} - -impl TxListen for Tx { - fn listen(&mut self) { - self.usart.listen_txe() - } - - fn unlisten(&mut self) { - self.usart.unlisten_txe() } -} - -impl crate::ClearFlags for Serial { - type Flag = CFlag; - - #[inline(always)] - fn clear_flags(&mut self, flags: impl Into>) { - self.tx.usart.clear_flags(flags.into()) - } -} - -impl crate::ReadFlags for Serial { - type Flag = Flag; - - #[inline(always)] - fn flags(&self) -> BitFlags { - self.tx.usart.flags() - } -} - -impl crate::Listen for Serial { - type Event = Event; - - #[inline(always)] - fn listen(&mut self, event: impl Into>) { - self.tx.usart.listen_event(None, Some(event.into())); - } - - #[inline(always)] - fn listen_only(&mut self, event: impl Into>) { - self.tx - .usart - .listen_event(Some(BitFlags::ALL), Some(event.into())); - } - - #[inline(always)] - fn unlisten(&mut self, event: impl Into>) { - self.tx.usart.listen_event(Some(event.into()), None); - } -} - -impl fmt::Write for Serial -where - Tx: fmt::Write, -{ - fn write_str(&mut self, s: &str) -> fmt::Result { - self.tx.write_str(s) - } -} - -impl fmt::Write for Tx { - fn write_str(&mut self, s: &str) -> fmt::Result { - s.bytes() - .try_for_each(|c| block!(self.usart.write_u8(c))) - .map_err(|_| fmt::Error) - } -} - -impl SerialExt for UART { - fn serial( - self, - pins: (impl Into>, impl Into>), - config: impl Into, - clocks: &Clocks, - ) -> Result, config::InvalidConfig> { - Serial::new(self, pins, config, clocks) - } -} - -impl Serial { - pub fn tx( - usart: UART, - tx_pin: impl Into>, - config: impl Into, - clocks: &Clocks, - ) -> Result, config::InvalidConfig> - where - NoPin: Into>, - { - Self::new(usart, (tx_pin, NoPin::new()), config, clocks).map(|s| s.split().0) - } -} - -impl Serial { - pub fn rx( - usart: UART, - rx_pin: impl Into>, - config: impl Into, - clocks: &Clocks, - ) -> Result, config::InvalidConfig> - where - NoPin: Into>, - { - Self::new(usart, (NoPin::new(), rx_pin), config, clocks).map(|s| s.split().1) - } -} - -unsafe impl PeriAddress for Rx { - #[inline(always)] - fn address(&self) -> u32 { - self.usart.peri_address() - } - - type MemSize = u8; -} - -unsafe impl DMASet - for Rx -where - UART: DMASet, -{ -} - -unsafe impl PeriAddress for Tx { - #[inline(always)] - fn address(&self) -> u32 { - self.usart.peri_address() - } - - type MemSize = u8; -} - -unsafe impl DMASet - for Tx -where - UART: DMASet, -{ + fn configure_irda(&self, _irda: IrdaMode, _pclk_freq: u32) {} } diff --git a/src/uart.rs b/src/uart.rs deleted file mode 100644 index d33e2e7b..00000000 --- a/src/uart.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! -//! Asynchronous serial communication using UART peripherals -//! -//! # Word length -//! -//! By default, the UART/UART uses 8 data bits. The `Serial`, `Rx`, and `Tx` structs implement -//! the embedded-hal read and write traits with `u8` as the word type. -//! -//! You can also configure the hardware to use 9 data bits with the `Config` `wordlength_9()` -//! function. After creating a `Serial` with this option, use the `with_u16_data()` function to -//! convert the `Serial<_, u8>` object into a `Serial<_, u16>` that can send and receive `u16`s. -//! -//! In this mode, the `Serial<_, u16>`, `Rx<_, u16>`, and `Tx<_, u16>` structs instead implement -//! the embedded-hal read and write traits with `u16` as the word type. You can use these -//! implementations for 9-bit words. - -use crate::pac; - -use crate::serial::uart_impls::RegisterBlockUart; - -pub use crate::serial::{config, Error, Event, Instance, NoRx, NoTx, Rx, RxISR, Serial, Tx, TxISR}; -pub use config::Config; - -macro_rules! halUart { - ($UART:ty, $Serial:ident, $Rx:ident, $Tx:ident) => { - pub type $Serial = Serial<$UART, WORD>; - pub type $Tx = Tx<$UART, WORD>; - pub type $Rx = Rx<$UART, WORD>; - - impl Instance for $UART { - fn set_stopbits(&self, bits: config::StopBits) { - use crate::pac::uart4::cr2::STOP; - use config::StopBits; - - /* - StopBits::STOP0P5 and StopBits::STOP1P5 aren't supported when using UART - STOP_A::STOP1 and STOP_A::STOP2 will be used, respectively - */ - self.cr2().write(|w| { - w.stop().variant(match bits { - StopBits::STOP0P5 => STOP::Stop1, - StopBits::STOP1 => STOP::Stop1, - StopBits::STOP1P5 => STOP::Stop2, - StopBits::STOP2 => STOP::Stop2, - }) - }); - } - } - - impl crate::Ptr for $UART { - type RB = RegisterBlockUart; - - fn ptr() -> *const Self::RB { - Self::ptr() - } - } - - impl crate::Steal for $UART { - unsafe fn steal() -> Self { - Self::steal() - } - } - }; -} - -#[cfg(feature = "uart4")] -halUart! { pac::UART4, Serial4, Rx4, Tx4 } -#[cfg(feature = "uart5")] -halUart! { pac::UART5, Serial5, Rx5, Tx5 } -#[cfg(feature = "uart7")] -halUart! { pac::UART7, Serial7, Rx7, Tx7 } -#[cfg(feature = "uart8")] -halUart! { pac::UART8, Serial8, Rx8, Tx8 } -#[cfg(feature = "uart9")] -halUart! { pac::UART9, Serial9, Rx9, Tx9 } -#[cfg(feature = "uart10")] -halUart! { pac::UART10, Serial10, Rx10, Tx10 }