From 8328e1a9335f56368a9e5abbd0908fd2261d50a6 Mon Sep 17 00:00:00 2001 From: apeng2012 Date: Tue, 17 Aug 2021 15:49:02 +0800 Subject: [PATCH 1/3] add uart4 uart5 --- src/rcc/enable.rs | 2 +- src/serial.rs | 953 ++++++++++++++++++++++++---------------------- 2 files changed, 509 insertions(+), 446 deletions(-) diff --git a/src/rcc/enable.rs b/src/rcc/enable.rs index a0374e97..59910bc5 100644 --- a/src/rcc/enable.rs +++ b/src/rcc/enable.rs @@ -73,7 +73,7 @@ bus! { CAN1 => (APB1, 25), CAN2 => (APB1, 26), } -#[cfg(all(feature = "stm32f103", feature = "high"))] +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] bus! { ADC3 => (APB2, 15), DAC => (APB1, 29), diff --git a/src/serial.rs b/src/serial.rs index 4b5493e0..a27fa652 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -37,23 +37,26 @@ //! ``` use core::marker::PhantomData; -use core::ops::Deref; use core::ptr; use core::sync::atomic::{self, Ordering}; use crate::pac::{RCC, USART1, USART2, USART3}; +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +use crate::pac::{UART4, UART5}; use core::convert::Infallible; use embedded_dma::{StaticReadBuffer, StaticWriteBuffer}; use embedded_hal::serial::Write; use crate::afio::MAPR; +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +use crate::dma::dma2; use crate::dma::{dma1, CircBuffer, RxDma, Transfer, TxDma, R, W}; use crate::gpio::gpioa::{PA10, PA2, PA3, PA9}; use crate::gpio::gpiob::{PB10, PB11, PB6, PB7}; -use crate::gpio::gpioc::{PC10, PC11}; -use crate::gpio::gpiod::{PD5, PD6, PD8, PD9}; +use crate::gpio::gpioc::{PC10, PC11, PC12}; +use crate::gpio::gpiod::{PD2, PD5, PD6, PD8, PD9}; use crate::gpio::{Alternate, Floating, Input, PushPull}; -use crate::rcc::{Clocks, Enable, GetBusFreq, Reset}; +use crate::rcc::{Clocks, Enable, GetBusFreq, RccBus, Reset}; use crate::time::{Bps, U32Ext}; /// Interrupt event @@ -83,43 +86,64 @@ pub enum Error { // USART REMAPPING, see: https://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf // Section 9.3.8 pub trait Pins { - const REMAP: u8; + fn remap(&self, _mapr: &mut MAPR) {} } impl Pins for (PA9>, PA10>) { - const REMAP: u8 = 0; + fn remap(&self, mapr: &mut MAPR) { + mapr.modify_mapr(|_, w| w.usart1_remap().clear_bit()) + } } impl Pins for (PB6>, PB7>) { - const REMAP: u8 = 1; + fn remap(&self, mapr: &mut MAPR) { + mapr.modify_mapr(|_, w| w.usart1_remap().set_bit()) + } } impl Pins for (PA2>, PA3>) { - const REMAP: u8 = 0; + fn remap(&self, mapr: &mut MAPR) { + mapr.modify_mapr(|_, w| w.usart2_remap().clear_bit()) + } } impl Pins for (PD5>, PD6>) { - const REMAP: u8 = 1; + fn remap(&self, mapr: &mut MAPR) { + mapr.modify_mapr(|_, w| w.usart2_remap().set_bit()) + } } impl Pins for (PB10>, PB11>) { - const REMAP: u8 = 0; + fn remap(&self, mapr: &mut MAPR) { + mapr.modify_mapr(|_, w| unsafe { w.usart3_remap().bits(0) }) + } } impl Pins for (PC10>, PC11>) { - const REMAP: u8 = 1; + fn remap(&self, mapr: &mut MAPR) { + mapr.modify_mapr(|_, w| unsafe { w.usart3_remap().bits(1) }) + } } impl Pins for (PD8>, PD9>) { - const REMAP: u8 = 0b11; + fn remap(&self, mapr: &mut MAPR) { + mapr.modify_mapr(|_, w| unsafe { w.usart3_remap().bits(0b11) }) + } } +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +impl Pins for (PC10>, PC11>) {} + +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +impl Pins for (PC12>, PD2>) {} + pub enum Parity { ParityNone, ParityEven, ParityOdd, } +#[derive(PartialEq)] pub enum StopBits { #[doc = "1 stop bit"] STOP1, @@ -181,8 +205,6 @@ impl From for Config { } } -use crate::pac::usart1 as uart_base; - /// Serial abstraction pub struct Serial { usart: USART, @@ -191,13 +213,6 @@ pub struct Serial { rx: Rx, } -pub trait Instance: - crate::Sealed + Deref + Enable + Reset + GetBusFreq -{ - #[doc(hidden)] - fn ptr() -> *const uart_base::RegisterBlock; -} - /// Serial receiver pub struct Rx { _usart: PhantomData, @@ -224,137 +239,64 @@ impl Tx { } } -impl Serial -where - USART: Instance, -{ - fn init(self, config: Config, clocks: Clocks, remap: impl FnOnce()) -> Self { - // enable and reset $USARTX - let rcc = unsafe { &(*RCC::ptr()) }; - USART::enable(rcc); - USART::reset(rcc); - - remap(); - // Configure baud rate - let brr = USART::get_frequency(&clocks).0 / config.baudrate.0; - assert!(brr >= 16, "impossible baud rate"); - self.usart.brr.write(|w| unsafe { w.bits(brr) }); - - // Configure parity and word length - // Unlike most uart devices, the "word length" of this usart device refers to - // the size of the data plus the parity bit. I.e. "word length"=8, parity=even - // results in 7 bits of data. Therefore, in order to get 8 bits and one parity - // bit, we need to set the "word" length to 9 when using parity bits. - let (word_length, parity_control_enable, parity) = match config.parity { - Parity::ParityNone => (false, false, false), - Parity::ParityEven => (true, true, false), - Parity::ParityOdd => (true, true, true), - }; - self.usart.cr1.modify(|_r, w| { - w.m() - .bit(word_length) - .ps() - .bit(parity) - .pce() - .bit(parity_control_enable) - }); - - // Configure stop bits - let stop_bits = match config.stopbits { - StopBits::STOP1 => 0b00, - StopBits::STOP0P5 => 0b01, - StopBits::STOP2 => 0b10, - StopBits::STOP1P5 => 0b11, - }; - self.usart.cr2.modify(|_r, w| w.stop().bits(stop_bits)); - - // UE: enable USART - // RE: enable receiver - // TE: enable transceiver - self.usart - .cr1 - .modify(|_r, w| w.ue().set_bit().re().set_bit().te().set_bit()); - - self - } - - /// Starts listening to the USART by enabling the _Received data - /// ready to be read (RXNE)_ interrupt and _Transmit data - /// register empty (TXE)_ interrupt - 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()), - } - } +trait Stopbits { + fn config_stop_bits(stopbits: StopBits); +} - /// Stops listening to the USART by disabling the _Received data - /// ready to be read (RXNE)_ interrupt and _Transmit data - /// register empty (TXE)_ interrupt - 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()), +macro_rules! usart_stop_bits { + ($USARTX:ident) => { + impl Stopbits for $USARTX { + fn config_stop_bits(stopbits: StopBits) { + let stop_bits = match stopbits { + StopBits::STOP1 => 0b00, + StopBits::STOP0P5 => 0b01, + StopBits::STOP2 => 0b10, + StopBits::STOP1P5 => 0b11, + }; + let usart = unsafe { &(*$USARTX::ptr()) }; + usart.cr2.modify(|_r, w| w.stop().bits(stop_bits)); + } } - } - - /// Returns true if the line idle status is set - pub fn is_idle(&self) -> bool { - self.usart.sr.read().idle().bit_is_set() - } - - /// Returns true if the tx register is empty (and can accept data) - pub fn is_tx_empty(&self) -> bool { - self.usart.sr.read().txe().bit_is_set() - } - - /// Returns true if the rx register is not empty (and can be read) - pub fn is_rx_not_empty(&self) -> bool { - self.usart.sr.read().rxne().bit_is_set() - } + }; +} - /// Clear idle line interrupt flag - pub fn clear_idle_interrupt(&self) { - unsafe { - let _ = (*USART::ptr()).sr.read(); - let _ = (*USART::ptr()).dr.read(); +macro_rules! uart_stop_bits { + ($UARTX:ident) => { + impl Stopbits for $UARTX { + fn config_stop_bits(stopbits: StopBits) { + assert!( + (stopbits == StopBits::STOP0P5) || (stopbits == StopBits::STOP1P5), + "The 0.5 Stop bit and 1.5 Stop bit are not available for UART4 & UART5." + ); + let uart = unsafe { &(*$UARTX::ptr()) }; + if stopbits == StopBits::STOP1 { + uart.cr2.modify(|_r, w| w.stop().stop1()); + } else { + uart.cr2.modify(|_r, w| w.stop().stop2()); + } + } } - } - - /// Returns ownership of the borrowed register handles - pub fn release(self) -> (USART, PINS) { - (self.usart, self.pins) - } - - /// Separates the serial struct into separate channel objects for sending (Tx) and - /// receiving (Rx) - pub fn split(self) -> (Tx, Rx) { - (self.tx, self.rx) - } + }; } +usart_stop_bits! {USART1} +usart_stop_bits! {USART2} +usart_stop_bits! {USART3} +uart_stop_bits! {UART4} +uart_stop_bits! {UART5} + macro_rules! hal { ( $(#[$meta:meta])* $USARTX:ident: ( $usartX:ident, - $usartX_remap:ident, - $bit:ident, - $closure:expr, ), ) => { - impl Instance for $USARTX { - fn ptr() -> *const uart_base::RegisterBlock { - <$USARTX>::ptr() as *const _ - } - } - $(#[$meta])* /// The behaviour of the functions is equal for all three USARTs. /// Except that they are using the corresponding USART hardware and pins. - impl Serial<$USARTX, PINS> { + impl Serial<$USARTX, PINS> + { /// Configures the serial interface and creates the interface /// struct. /// @@ -374,188 +316,262 @@ macro_rules! hal { usart: $USARTX, pins: PINS, mapr: &mut MAPR, - config: impl Into, + config: Config, clocks: Clocks, ) -> Self where PINS: Pins<$USARTX>, { - #[allow(unused_unsafe)] - Serial { usart, pins, tx: Tx::new(), rx: Rx::new() }.init(config.into(), clocks, || { - mapr.modify_mapr(|_, w| unsafe { - #[allow(clippy::redundant_closure_call)] - w.$usartX_remap().$bit(($closure)(PINS::REMAP)) - }) - }) + // enable and reset $USARTX + let rcc = unsafe { &(*RCC::ptr()) }; + $USARTX::enable(rcc); + $USARTX::reset(rcc); + + pins.remap(mapr); + + // Configure baud rate + let brr = <$USARTX as RccBus>::Bus::get_frequency(&clocks).0 / config.baudrate.0; + assert!(brr >= 16, "impossible baud rate"); + usart.brr.write(|w| unsafe { w.bits(brr) }); + + // Configure parity and word length + // Unlike most uart devices, the "word length" of this usart device refers to + // the size of the data plus the parity bit. I.e. "word length"=8, parity=even + // results in 7 bits of data. Therefore, in order to get 8 bits and one parity + // bit, we need to set the "word" length to 9 when using parity bits. + let (word_length, parity_control_enable, parity) = match config.parity { + Parity::ParityNone => (false, false, false), + Parity::ParityEven => (true, true, false), + Parity::ParityOdd => (true, true, true), + }; + usart.cr1.modify(|_r, w| { + w.m() + .bit(word_length) + .ps() + .bit(parity) + .pce() + .bit(parity_control_enable) + }); + + // Configure stop bits + $USARTX::config_stop_bits(config.stopbits); + + // UE: enable USART + // RE: enable receiver + // TE: enable transceiver + usart.cr1 + .modify(|_r, w| w.ue().set_bit().re().set_bit().te().set_bit()); + + let tx = Tx::<$USARTX>::new(); + let rx = Rx::<$USARTX>::new(); + Serial { usart, pins, tx, rx } } - } - }; -} + /// Starts listening to the USART by enabling the _Received data + /// ready to be read (RXNE)_ interrupt and _Transmit data + /// register empty (TXE)_ interrupt + 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()), + } + } -impl Tx -where - USART: Instance, -{ - /// Start listening for transmit interrupt event - pub fn listen(&mut self) { - unsafe { (*USART::ptr()).cr1.modify(|_, w| w.txeie().set_bit()) }; - } + /// Stops listening to the USART by disabling the _Received data + /// ready to be read (RXNE)_ interrupt and _Transmit data + /// register empty (TXE)_ interrupt + 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()), + } + } - /// Stop listening for transmit interrupt event - pub fn unlisten(&mut self) { - unsafe { (*USART::ptr()).cr1.modify(|_, w| w.txeie().clear_bit()) }; - } + /// Returns true if the line idle status is set + pub fn is_idle(&self) -> bool { + self.usart.sr.read().idle().bit_is_set() + } - /// Returns true if the tx register is empty (and can accept data) - pub fn is_tx_empty(&self) -> bool { - unsafe { (*USART::ptr()).sr.read().txe().bit_is_set() } - } -} + /// Returns true if the tx register is empty (and can accept data) + pub fn is_tx_empty(&self) -> bool { + self.usart.sr.read().txe().bit_is_set() + } -impl Rx -where - USART: Instance, -{ - /// Start listening for receive interrupt event - pub fn listen(&mut self) { - unsafe { (*USART::ptr()).cr1.modify(|_, w| w.rxneie().set_bit()) }; - } + /// Returns true if the rx register is not empty (and can be read) + pub fn is_rx_not_empty(&self) -> bool { + self.usart.sr.read().rxne().bit_is_set() + } - /// Stop listening for receive interrupt event - pub fn unlisten(&mut self) { - unsafe { (*USART::ptr()).cr1.modify(|_, w| w.rxneie().clear_bit()) }; - } + /// Clear idle line interrupt flag + pub fn clear_idle_interrupt(&self) { + unsafe { + let _ = (*$USARTX::ptr()).sr.read(); + let _ = (*$USARTX::ptr()).dr.read(); + } + } - /// Start listening for idle interrupt event - pub fn listen_idle(&mut self) { - unsafe { (*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit()) }; - } + /// Returns ownership of the borrowed register handles + pub fn release(self) -> ($USARTX, PINS) { + (self.usart, self.pins) + } - /// Stop listening for idle interrupt event - pub fn unlisten_idle(&mut self) { - unsafe { (*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()) }; - } + /// Separates the serial struct into separate channel objects for sending (Tx) and + /// receiving (Rx) + pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>) { + (self.tx, self.rx) + } + } - /// Returns true if the line idle status is set - pub fn is_idle(&self) -> bool { - unsafe { (*USART::ptr()).sr.read().idle().bit_is_set() } - } + impl Tx<$USARTX> { + /// Start listening for transmit interrupt event + pub fn listen(&mut self) { + unsafe { (*$USARTX::ptr()).cr1.modify(|_, w| w.txeie().set_bit()) }; + } - /// Returns true if the rx register is not empty (and can be read) - pub fn is_rx_not_empty(&self) -> bool { - unsafe { (*USART::ptr()).sr.read().rxne().bit_is_set() } - } + /// Stop listening for transmit interrupt event + pub fn unlisten(&mut self) { + unsafe { (*$USARTX::ptr()).cr1.modify(|_, w| w.txeie().clear_bit()) }; + } - /// Clear idle line interrupt flag - pub fn clear_idle_interrupt(&self) { - unsafe { - let _ = (*USART::ptr()).sr.read(); - let _ = (*USART::ptr()).dr.read(); + /// Returns true if the tx register is empty (and can accept data) + pub fn is_tx_empty(&self) -> bool { + unsafe { (*$USARTX::ptr()).sr.read().txe().bit_is_set() } + } } - } -} -impl crate::hal::serial::Read for Rx -where - USART: Instance, -{ - type Error = Error; - - fn read(&mut self) -> nb::Result { - let usart = unsafe { &*USART::ptr() }; - let sr = usart.sr.read(); - - // Check for any errors - let err = if sr.pe().bit_is_set() { - Some(Error::Parity) - } else if sr.fe().bit_is_set() { - Some(Error::Framing) - } else if sr.ne().bit_is_set() { - Some(Error::Noise) - } else if sr.ore().bit_is_set() { - Some(Error::Overrun) - } else { - None - }; - - if let Some(err) = err { - // Some error occurred. In order to clear that error flag, you have to - // do a read from the sr register followed by a read from the dr - // register - // NOTE(read_volatile) see `write_volatile` below - unsafe { - ptr::read_volatile(&usart.sr as *const _ as *const _); - ptr::read_volatile(&usart.dr as *const _ as *const _); - } - Err(nb::Error::Other(err)) - } else { - // Check if a byte is available - if sr.rxne().bit_is_set() { - // Read the received byte - // NOTE(read_volatile) see `write_volatile` below - Ok(unsafe { ptr::read_volatile(&usart.dr as *const _ as *const _) }) - } else { - Err(nb::Error::WouldBlock) + impl Rx<$USARTX> { + /// Start listening for receive interrupt event + pub fn listen(&mut self) { + unsafe { (*$USARTX::ptr()).cr1.modify(|_, w| w.rxneie().set_bit()) }; } - } - } -} -impl crate::hal::serial::Write for Tx -where - USART: Instance, -{ - type Error = Infallible; + /// Stop listening for receive interrupt event + pub fn unlisten(&mut self) { + unsafe { (*$USARTX::ptr()).cr1.modify(|_, w| w.rxneie().clear_bit()) }; + } + + /// Start listening for idle interrupt event + pub fn listen_idle(&mut self) { + unsafe { (*$USARTX::ptr()).cr1.modify(|_, w| w.idleie().set_bit()) }; + } + + /// Stop listening for idle interrupt event + pub fn unlisten_idle(&mut self) { + unsafe { (*$USARTX::ptr()).cr1.modify(|_, w| w.idleie().clear_bit()) }; + } - fn flush(&mut self) -> nb::Result<(), Self::Error> { - let sr = unsafe { &*USART::ptr() }.sr.read(); + /// Returns true if the line idle status is set + pub fn is_idle(&self) -> bool { + unsafe { (*$USARTX::ptr()).sr.read().idle().bit_is_set() } + } + + /// Returns true if the rx register is not empty (and can be read) + pub fn is_rx_not_empty(&self) -> bool { + unsafe { (*$USARTX::ptr()).sr.read().rxne().bit_is_set() } + } - if sr.tc().bit_is_set() { - Ok(()) - } else { - Err(nb::Error::WouldBlock) + /// Clear idle line interrupt flag + pub fn clear_idle_interrupt(&self) { + unsafe { + let _ = (*$USARTX::ptr()).sr.read(); + let _ = (*$USARTX::ptr()).dr.read(); + } + } } - } - fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { - let usart = unsafe { &*USART::ptr() }; - let sr = usart.sr.read(); - - if sr.txe().bit_is_set() { - // NOTE(unsafe) atomic write to stateless register - // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API - unsafe { ptr::write_volatile(&usart.dr as *const _ as *mut _, byte) } - Ok(()) - } else { - Err(nb::Error::WouldBlock) + + impl crate::hal::serial::Read for Rx<$USARTX> { + type Error = Error; + + fn read(&mut self) -> nb::Result { + let usart = unsafe { &*$USARTX::ptr() }; + let sr = usart.sr.read(); + + // Check for any errors + let err = if sr.pe().bit_is_set() { + Some(Error::Parity) + } else if sr.fe().bit_is_set() { + Some(Error::Framing) + } else if sr.ne().bit_is_set() { + Some(Error::Noise) + } else if sr.ore().bit_is_set() { + Some(Error::Overrun) + } else { + None + }; + + if let Some(err) = err { + // Some error occurred. In order to clear that error flag, you have to + // do a read from the sr register followed by a read from the dr + // register + // NOTE(read_volatile) see `write_volatile` below + unsafe { + ptr::read_volatile(&usart.sr as *const _ as *const _); + ptr::read_volatile(&usart.dr as *const _ as *const _); + } + Err(nb::Error::Other(err)) + } else { + // Check if a byte is available + if sr.rxne().bit_is_set() { + // Read the received byte + // NOTE(read_volatile) see `write_volatile` below + Ok(unsafe { ptr::read_volatile(&usart.dr as *const _ as *const _) }) + } else { + Err(nb::Error::WouldBlock) + } + } + } } - } -} -impl crate::hal::serial::Read for Serial -where - USART: Instance, -{ - type Error = Error; + impl crate::hal::serial::Write for Tx<$USARTX> { + type Error = Infallible; - fn read(&mut self) -> nb::Result { - self.rx.read() - } -} + fn flush(&mut self) -> nb::Result<(), Self::Error> { + let sr = unsafe { &*$USARTX::ptr() }.sr.read(); -impl crate::hal::serial::Write for Serial -where - USART: Instance, -{ - type Error = Infallible; + if sr.tc().bit_is_set() { + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } + fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { + let usart = unsafe { &*$USARTX::ptr() }; + let sr = usart.sr.read(); + + if sr.txe().bit_is_set() { + // NOTE(unsafe) atomic write to stateless register + // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API + unsafe { ptr::write_volatile(&usart.dr as *const _ as *mut _, byte) } + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } + } - fn flush(&mut self) -> nb::Result<(), Self::Error> { - self.tx.flush() - } + impl crate::hal::serial::Read for Serial<$USARTX, PINS> { + type Error = Error; - fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { - self.tx.write(byte) - } + fn read(&mut self) -> nb::Result { + self.rx.read() + } + } + + impl crate::hal::serial::Write for Serial<$USARTX, PINS> { + type Error = Infallible; + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.tx.flush() + } + + fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { + self.tx.write(byte) + } + } + + }; } impl core::fmt::Write for Tx @@ -574,27 +590,32 @@ hal! { /// # USART1 functions USART1: ( usart1, - usart1_remap, - bit, - |remap| remap == 1, ), } hal! { /// # USART2 functions USART2: ( usart2, - usart2_remap, - bit, - |remap| remap == 1, ), } hal! { /// # USART3 functions USART3: ( usart3, - usart3_remap, - bits, - |remap| remap, + ), +} +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +hal! { + /// # UART4 functions + UART4: ( + uart4, + ), +} +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +hal! { + /// # UART5 functions + UART5: ( + uart5, ), } @@ -604,190 +625,219 @@ pub type Rx2 = Rx; pub type Tx2 = Tx; pub type Rx3 = Rx; pub type Tx3 = Tx; +pub type Rx4 = Rx; +pub type Tx4 = Tx; use crate::dma::{Receive, TransferPayload, Transmit}; macro_rules! serialdma { - ($( + ( $USARTX:ident: ( $rxdma:ident, $txdma:ident, $dmarxch:ty, $dmatxch:ty, ), - )+) => { - $( - pub type $rxdma = RxDma, $dmarxch>; - pub type $txdma = TxDma, $dmatxch>; + ) => { + pub type $rxdma = RxDma, $dmarxch>; + pub type $txdma = TxDma, $dmatxch>; - impl Receive for $rxdma { - type RxChannel = $dmarxch; - type TransmittedWord = u8; - } + impl Receive for $rxdma { + type RxChannel = $dmarxch; + type TransmittedWord = u8; + } - impl Transmit for $txdma { - type TxChannel = $dmatxch; - type ReceivedWord = u8; - } + impl Transmit for $txdma { + type TxChannel = $dmatxch; + type ReceivedWord = u8; + } - impl TransferPayload for $rxdma { - fn start(&mut self) { - self.channel.start(); - } - fn stop(&mut self) { - self.channel.stop(); - } + impl TransferPayload for $rxdma { + fn start(&mut self) { + self.channel.start(); } - - impl TransferPayload for $txdma { - fn start(&mut self) { - self.channel.start(); - } - fn stop(&mut self) { - self.channel.stop(); - } + fn stop(&mut self) { + self.channel.stop(); } + } - impl Rx<$USARTX> { - pub fn with_dma(self, channel: $dmarxch) -> $rxdma { - unsafe { (*$USARTX::ptr()).cr3.write(|w| w.dmar().set_bit()); } - RxDma { - payload: self, - channel, - } - } + impl TransferPayload for $txdma { + fn start(&mut self) { + self.channel.start(); } - - impl Tx<$USARTX> { - pub fn with_dma(self, channel: $dmatxch) -> $txdma { - unsafe { (*$USARTX::ptr()).cr3.write(|w| w.dmat().set_bit()); } - TxDma { - payload: self, - channel, - } - } + fn stop(&mut self) { + self.channel.stop(); } + } - impl $rxdma { - #[deprecated(since = "0.7.1", note = "Please use release instead")] - pub fn split(self) -> (Rx<$USARTX>, $dmarxch) { - self.release() + impl Rx<$USARTX> { + pub fn with_dma(self, channel: $dmarxch) -> $rxdma { + unsafe { + (*$USARTX::ptr()).cr3.write(|w| w.dmar().set_bit()); } - pub fn release(mut self) -> (Rx<$USARTX>, $dmarxch) { - self.stop(); - unsafe { (*$USARTX::ptr()).cr3.write(|w| w.dmar().clear_bit()); } - let RxDma {payload, channel} = self; - ( - payload, - channel - ) + RxDma { + payload: self, + channel, } } + } - impl $txdma { - #[deprecated(since = "0.7.1", note = "Please use release instead")] - pub fn split(self) -> (Tx<$USARTX>, $dmatxch) { - self.release() + impl Tx<$USARTX> { + pub fn with_dma(self, channel: $dmatxch) -> $txdma { + unsafe { + (*$USARTX::ptr()).cr3.write(|w| w.dmat().set_bit()); } - pub fn release(mut self) -> (Tx<$USARTX>, $dmatxch) { - self.stop(); - unsafe { (*$USARTX::ptr()).cr3.write(|w| w.dmat().clear_bit()); } - let TxDma {payload, channel} = self; - ( - payload, - channel, - ) + TxDma { + payload: self, + channel, } } + } - impl crate::dma::CircReadDma for $rxdma - where - &'static mut [B; 2]: StaticWriteBuffer, - B: 'static, - { - fn circ_read(mut self, mut buffer: &'static mut [B; 2]) -> CircBuffer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.static_write_buffer() }; - self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - - self.channel.ch().cr.modify(|_, w| { w - .mem2mem() .clear_bit() - .pl() .medium() - .msize() .bits8() - .psize() .bits8() - .circ() .set_bit() - .dir() .clear_bit() - }); - - self.start(); - - CircBuffer::new(buffer, self) + impl $rxdma { + #[deprecated(since = "0.7.1", note = "Please use release instead")] + pub fn split(self) -> (Rx<$USARTX>, $dmarxch) { + self.release() + } + pub fn release(mut self) -> (Rx<$USARTX>, $dmarxch) { + self.stop(); + unsafe { + (*$USARTX::ptr()).cr3.write(|w| w.dmar().clear_bit()); } + let RxDma { payload, channel } = self; + (payload, channel) } + } - impl crate::dma::ReadDma for $rxdma - where - B: StaticWriteBuffer, - { - fn read(mut self, mut buffer: B) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.static_write_buffer() }; - self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false); - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); - self.channel.ch().cr.modify(|_, w| { w - .mem2mem() .clear_bit() - .pl() .medium() - .msize() .bits8() - .psize() .bits8() - .circ() .clear_bit() - .dir() .clear_bit() - }); - self.start(); - - Transfer::w(buffer, self) + impl $txdma { + #[deprecated(since = "0.7.1", note = "Please use release instead")] + pub fn split(self) -> (Tx<$USARTX>, $dmatxch) { + self.release() + } + pub fn release(mut self) -> (Tx<$USARTX>, $dmatxch) { + self.stop(); + unsafe { + (*$USARTX::ptr()).cr3.write(|w| w.dmat().clear_bit()); } + let TxDma { payload, channel } = self; + (payload, channel) } + } - impl crate::dma::WriteDma for $txdma - where - B: StaticReadBuffer, - { - fn write(mut self, buffer: B) -> Transfer { - // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it - // until the end of the transfer. - let (ptr, len) = unsafe { buffer.static_read_buffer() }; - - self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false); - - self.channel.set_memory_address(ptr as u32, true); - self.channel.set_transfer_length(len); - - atomic::compiler_fence(Ordering::Release); + impl crate::dma::CircReadDma for $rxdma + where + &'static mut [B; 2]: StaticWriteBuffer, + B: 'static, + { + fn circ_read(mut self, mut buffer: &'static mut [B; 2]) -> CircBuffer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.static_write_buffer() }; + self.channel.set_peripheral_address( + unsafe { &(*$USARTX::ptr()).dr as *const _ as u32 }, + false, + ); + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + + self.channel.ch().cr.modify(|_, w| { + w.mem2mem() + .clear_bit() + .pl() + .medium() + .msize() + .bits8() + .psize() + .bits8() + .circ() + .set_bit() + .dir() + .clear_bit() + }); + + self.start(); + + CircBuffer::new(buffer, self) + } + } - self.channel.ch().cr.modify(|_, w| { w - .mem2mem() .clear_bit() - .pl() .medium() - .msize() .bits8() - .psize() .bits8() - .circ() .clear_bit() - .dir() .set_bit() - }); - self.start(); + impl crate::dma::ReadDma for $rxdma + where + B: StaticWriteBuffer, + { + fn read(mut self, mut buffer: B) -> Transfer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.static_write_buffer() }; + self.channel.set_peripheral_address( + unsafe { &(*$USARTX::ptr()).dr as *const _ as u32 }, + false, + ); + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + self.channel.ch().cr.modify(|_, w| { + w.mem2mem() + .clear_bit() + .pl() + .medium() + .msize() + .bits8() + .psize() + .bits8() + .circ() + .clear_bit() + .dir() + .clear_bit() + }); + self.start(); + + Transfer::w(buffer, self) + } + } - Transfer::r(buffer, self) - } + impl crate::dma::WriteDma for $txdma + where + B: StaticReadBuffer, + { + fn write(mut self, buffer: B) -> Transfer { + // NOTE(unsafe) We own the buffer now and we won't call other `&mut` on it + // until the end of the transfer. + let (ptr, len) = unsafe { buffer.static_read_buffer() }; + + self.channel.set_peripheral_address( + unsafe { &(*$USARTX::ptr()).dr as *const _ as u32 }, + false, + ); + + self.channel.set_memory_address(ptr as u32, true); + self.channel.set_transfer_length(len); + + atomic::compiler_fence(Ordering::Release); + + self.channel.ch().cr.modify(|_, w| { + w.mem2mem() + .clear_bit() + .pl() + .medium() + .msize() + .bits8() + .psize() + .bits8() + .circ() + .clear_bit() + .dir() + .set_bit() + }); + self.start(); + + Transfer::r(buffer, self) } - )+ - } + } + }; } serialdma! { @@ -797,12 +847,16 @@ serialdma! { dma1::C5, dma1::C4, ), +} +serialdma! { USART2: ( RxDma2, TxDma2, dma1::C6, dma1::C7, ), +} +serialdma! { USART3: ( RxDma3, TxDma3, @@ -810,3 +864,12 @@ serialdma! { dma1::C2, ), } +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +serialdma! { + UART4: ( + RxDma4, + TxDma4, + dma2::C3, + dma2::C5, + ), +} From 949b91df8064c288ad713ae2ae7c2a5384651e59 Mon Sep 17 00:00:00 2001 From: apeng2012 Date: Tue, 17 Aug 2021 16:21:31 +0800 Subject: [PATCH 2/3] fix cfg --- src/serial.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/serial.rs b/src/serial.rs index a27fa652..158d6071 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -53,8 +53,12 @@ use crate::dma::dma2; use crate::dma::{dma1, CircBuffer, RxDma, Transfer, TxDma, R, W}; use crate::gpio::gpioa::{PA10, PA2, PA3, PA9}; use crate::gpio::gpiob::{PB10, PB11, PB6, PB7}; -use crate::gpio::gpioc::{PC10, PC11, PC12}; -use crate::gpio::gpiod::{PD2, PD5, PD6, PD8, PD9}; +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +use crate::gpio::gpioc::PC12; +use crate::gpio::gpioc::{PC10, PC11}; +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] +use crate::gpio::gpiod::PD2; +use crate::gpio::gpiod::{PD5, PD6, PD8, PD9}; use crate::gpio::{Alternate, Floating, Input, PushPull}; use crate::rcc::{Clocks, Enable, GetBusFreq, RccBus, Reset}; use crate::time::{Bps, U32Ext}; @@ -260,6 +264,7 @@ macro_rules! usart_stop_bits { }; } +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] macro_rules! uart_stop_bits { ($UARTX:ident) => { impl Stopbits for $UARTX { @@ -282,7 +287,9 @@ macro_rules! uart_stop_bits { usart_stop_bits! {USART1} usart_stop_bits! {USART2} usart_stop_bits! {USART3} +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] uart_stop_bits! {UART4} +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] uart_stop_bits! {UART5} macro_rules! hal { @@ -625,7 +632,9 @@ pub type Rx2 = Rx; pub type Tx2 = Tx; pub type Rx3 = Rx; pub type Tx3 = Tx; +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] pub type Rx4 = Rx; +#[cfg(all(feature = "stm32f103", any(feature = "high", feature = "xl")))] pub type Tx4 = Tx; use crate::dma::{Receive, TransferPayload, Transmit}; From 4e5b905516550a79ef3c25a47b6452fe391c7459 Mon Sep 17 00:00:00 2001 From: apeng2012 Date: Wed, 18 Aug 2021 16:22:46 +0800 Subject: [PATCH 3/3] o --- src/serial.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serial.rs b/src/serial.rs index 158d6071..3def5a39 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -270,7 +270,7 @@ macro_rules! uart_stop_bits { impl Stopbits for $UARTX { fn config_stop_bits(stopbits: StopBits) { assert!( - (stopbits == StopBits::STOP0P5) || (stopbits == StopBits::STOP1P5), + (stopbits == StopBits::STOP1) || (stopbits == StopBits::STOP2), "The 0.5 Stop bit and 1.5 Stop bit are not available for UART4 & UART5." ); let uart = unsafe { &(*$UARTX::ptr()) };