From 9423987ac52b0e4f7a176e70114016acd3752592 Mon Sep 17 00:00:00 2001 From: Guillaume MICHEL Date: Thu, 27 Oct 2022 10:52:21 +0200 Subject: [PATCH 1/3] embassy-stm32: Add hardware flow control constructor for UartRx and UartTx --- embassy-stm32/src/usart/mod.rs | 117 +++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index dee466b21..dde0799bb 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -102,7 +102,80 @@ pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { } impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { - fn new(tx_dma: PeripheralRef<'d, TxDma>) -> Self { + /// usefull if you only want Uart Tx. It saves 1 pin and consumes a little less power + pub fn new( + peri: impl Peripheral

+ 'd, + tx: impl Peripheral

> + 'd, + tx_dma: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + T::enable(); + T::reset(); + + Self::new_inner(peri, tx, tx_dma, config) + } + + pub fn new_with_cts( + peri: impl Peripheral

+ 'd, + tx: impl Peripheral

> + 'd, + cts: impl Peripheral

> + 'd, + tx_dma: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(cts); + + T::enable(); + T::reset(); + + unsafe { + cts.set_as_af(cts.af_num(), AFType::Input); + T::regs().cr3().write(|w| { + w.set_ctse(true); + }); + } + Self::new_inner(peri, tx, tx_dma, config) + } + + fn new_inner( + _peri: impl Peripheral

+ 'd, + tx: impl Peripheral

> + 'd, + tx_dma: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(_peri, tx, tx_dma); + + let r = T::regs(); + + configure(r, &config, T::frequency(), T::MULTIPLIER); + + unsafe { + tx.set_as_af(tx.af_num(), AFType::OutputPushPull); + + r.cr2().write(|_w| {}); + r.cr1().write(|w| { + // enable uart + w.set_ue(true); + // enable transceiver + w.set_te(true); + // configure word size + w.set_m0(if config.parity != Parity::ParityNone { + vals::M0::BIT9 + } else { + vals::M0::BIT8 + }); + // configure parity + w.set_pce(config.parity != Parity::ParityNone); + w.set_ps(match config.parity { + Parity::ParityOdd => vals::Ps::ODD, + Parity::ParityEven => vals::Ps::EVEN, + _ => vals::Ps::EVEN, + }); + }); + } + + // create state once! + let _s = T::state(); + Self { tx_dma, phantom: PhantomData, @@ -156,11 +229,44 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { rx_dma: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(peri, irq, rx, rx_dma); + T::enable(); + T::reset(); + + Self::new_inner(peri, irq, rx, rx_dma, config) + } + + pub fn new_with_rts( + peri: impl Peripheral

+ 'd, + irq: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + rts: impl Peripheral

> + 'd, + rx_dma: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(rts); T::enable(); T::reset(); + unsafe { + rts.set_as_af(rts.af_num(), AFType::OutputPushPull); + T::regs().cr3().write(|w| { + w.set_rtse(true); + }); + } + + Self::new_inner(peri, irq, rx, rx_dma, config) + } + + fn new_inner( + peri: impl Peripheral

+ 'd, + irq: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + rx_dma: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(peri, irq, rx, rx_dma); + let r = T::regs(); configure(r, &config, T::frequency(), T::MULTIPLIER); @@ -169,7 +275,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { rx.set_as_af(rx.af_num(), AFType::Input); r.cr2().write(|_w| {}); - r.cr3().write(|w| { + r.cr3().modify(|w| { // enable Error Interrupt: (Frame error, Noise error, Overrun error) w.set_eie(true); }); @@ -596,7 +702,10 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { let _s = T::state(); Self { - tx: UartTx::new(tx_dma), + tx: UartTx { + tx_dma, + phantom: PhantomData, + }, rx: UartRx { _peri: peri, rx_dma, From f053bf742c2e6e5e5e18e36bb773bc1e84010a2a Mon Sep 17 00:00:00 2001 From: Guillaume MICHEL Date: Thu, 27 Oct 2022 11:03:37 +0200 Subject: [PATCH 2/3] embassy-stm32: Add support for hardware flow control for BufferedUart --- embassy-stm32/src/usart/buffered.rs | 49 ++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 3be0677bd..59c7a8cca 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -45,6 +45,51 @@ impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {} impl<'d, T: BasicInstance> BufferedUart<'d, T> { pub fn new( + state: &'d mut State<'d, T>, + peri: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + tx: impl Peripheral

> + 'd, + irq: impl Peripheral

+ 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + config: Config, + ) -> BufferedUart<'d, T> { + T::enable(); + T::reset(); + + Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config) + } + + pub fn new_with_rtscts( + state: &'d mut State<'d, T>, + peri: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + tx: impl Peripheral

> + 'd, + irq: impl Peripheral

+ 'd, + rts: impl Peripheral

> + 'd, + cts: impl Peripheral

> + 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + config: Config, + ) -> BufferedUart<'d, T> { + into_ref!(cts, rts); + + T::enable(); + T::reset(); + + unsafe { + rts.set_as_af(rts.af_num(), AFType::OutputPushPull); + cts.set_as_af(cts.af_num(), AFType::Input); + T::regs().cr3().write(|w| { + w.set_rtse(true); + w.set_ctse(true); + }); + } + + Self::new_inner(state, peri, rx, tx, irq, tx_buffer, rx_buffer, config) + } + + fn new_inner( state: &'d mut State<'d, T>, _peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, @@ -56,9 +101,6 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { ) -> BufferedUart<'d, T> { into_ref!(_peri, rx, tx, irq); - T::enable(); - T::reset(); - let r = T::regs(); configure(r, &config, T::frequency(), T::MULTIPLIER); @@ -68,7 +110,6 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { tx.set_as_af(tx.af_num(), AFType::OutputPushPull); r.cr2().write(|_w| {}); - r.cr3().write(|_w| {}); r.cr1().write(|w| { w.set_ue(true); w.set_te(true); From 79b49c6fae7b4f7df2c03ae0be970d154f4faac8 Mon Sep 17 00:00:00 2001 From: Guillaume MICHEL Date: Fri, 28 Oct 2022 09:32:05 +0200 Subject: [PATCH 3/3] embassy-stm32: remove duplicated code for USART general configuration --- embassy-stm32/src/usart/buffered.rs | 23 ++---- embassy-stm32/src/usart/mod.rs | 104 +++++++++------------------- 2 files changed, 38 insertions(+), 89 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 59c7a8cca..0a6d6e149 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -103,28 +103,15 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { let r = T::regs(); - configure(r, &config, T::frequency(), T::MULTIPLIER); - unsafe { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); + } - r.cr2().write(|_w| {}); - r.cr1().write(|w| { - w.set_ue(true); - w.set_te(true); - w.set_re(true); - w.set_m0(if config.parity != Parity::ParityNone { - vals::M0::BIT9 - } else { - vals::M0::BIT8 - }); - w.set_pce(config.parity != Parity::ParityNone); - w.set_ps(match config.parity { - Parity::ParityOdd => vals::Ps::ODD, - Parity::ParityEven => vals::Ps::EVEN, - _ => vals::Ps::EVEN, - }); + configure(r, &config, T::frequency(), T::MULTIPLIER, true, true); + + unsafe { + r.cr1().modify(|w| { w.set_rxneie(true); w.set_idleie(true); }); diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index dde0799bb..716247d9e 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -146,33 +146,12 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { let r = T::regs(); - configure(r, &config, T::frequency(), T::MULTIPLIER); - unsafe { tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - - r.cr2().write(|_w| {}); - r.cr1().write(|w| { - // enable uart - w.set_ue(true); - // enable transceiver - w.set_te(true); - // configure word size - w.set_m0(if config.parity != Parity::ParityNone { - vals::M0::BIT9 - } else { - vals::M0::BIT8 - }); - // configure parity - w.set_pce(config.parity != Parity::ParityNone); - w.set_ps(match config.parity { - Parity::ParityOdd => vals::Ps::ODD, - Parity::ParityEven => vals::Ps::EVEN, - _ => vals::Ps::EVEN, - }); - }); } + configure(r, &config, T::frequency(), T::MULTIPLIER, false, true); + // create state once! let _s = T::state(); @@ -269,37 +248,12 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { let r = T::regs(); - configure(r, &config, T::frequency(), T::MULTIPLIER); - unsafe { rx.set_as_af(rx.af_num(), AFType::Input); - - r.cr2().write(|_w| {}); - r.cr3().modify(|w| { - // enable Error Interrupt: (Frame error, Noise error, Overrun error) - w.set_eie(true); - }); - r.cr1().write(|w| { - // enable uart - w.set_ue(true); - // enable receiver - w.set_re(true); - // configure word size - w.set_m0(if config.parity != Parity::ParityNone { - vals::M0::BIT9 - } else { - vals::M0::BIT8 - }); - // configure parity - w.set_pce(config.parity != Parity::ParityNone); - w.set_ps(match config.parity { - Parity::ParityOdd => vals::Ps::ODD, - Parity::ParityEven => vals::Ps::EVEN, - _ => vals::Ps::EVEN, - }); - }); } + configure(r, &config, T::frequency(), T::MULTIPLIER, true, false); + irq.set_handler(Self::on_interrupt); irq.unpend(); irq.enable(); @@ -669,31 +623,13 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { let r = T::regs(); - configure(r, &config, T::frequency(), T::MULTIPLIER); - unsafe { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - - r.cr2().write(|_w| {}); - r.cr1().write(|w| { - w.set_ue(true); - w.set_te(true); - w.set_re(true); - w.set_m0(if config.parity != Parity::ParityNone { - vals::M0::BIT9 - } else { - vals::M0::BIT8 - }); - w.set_pce(config.parity != Parity::ParityNone); - w.set_ps(match config.parity { - Parity::ParityOdd => vals::Ps::ODD, - Parity::ParityEven => vals::Ps::EVEN, - _ => vals::Ps::EVEN, - }); - }); } + configure(r, &config, T::frequency(), T::MULTIPLIER, true, true); + irq.set_handler(UartRx::::on_interrupt); irq.unpend(); irq.enable(); @@ -759,12 +695,38 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } } -fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32) { +fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable_rx: bool, enable_tx: bool) { + if !enable_rx && !enable_tx { + panic!("USART: At least one of RX or TX should be enabled"); + } + // TODO: better calculation, including error checking and OVER8 if possible. let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier; unsafe { r.brr().write_value(regs::Brr(div)); + r.cr2().write(|_w| {}); + r.cr1().write(|w| { + // enable uart + w.set_ue(true); + // enable transceiver + w.set_te(enable_tx); + // enable receiver + w.set_re(enable_rx); + // configure word size + w.set_m0(if config.parity != Parity::ParityNone { + vals::M0::BIT9 + } else { + vals::M0::BIT8 + }); + // configure parity + w.set_pce(config.parity != Parity::ParityNone); + w.set_ps(match config.parity { + Parity::ParityOdd => vals::Ps::ODD, + Parity::ParityEven => vals::Ps::EVEN, + _ => vals::Ps::EVEN, + }); + }); } }