From 497d3aa15383c627adf3873ac151bad8826ca7c8 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Wed, 30 Jun 2021 14:37:35 -0400 Subject: [PATCH] Add USARTv3 support. --- embassy-stm32/src/usart/mod.rs | 61 +++++++++++++++-- embassy-stm32/src/usart/v1.rs | 45 ------------- embassy-stm32/src/usart/v3.rs | 120 +++++++++++++++++++++++++++++++++ stm32-data | 2 +- stm32-metapac/gen/src/lib.rs | 1 + 5 files changed, 176 insertions(+), 53 deletions(-) create mode 100644 embassy-stm32/src/usart/v3.rs diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index a75793f8..b957a99c 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,7 +1,8 @@ #![macro_use] -#[cfg_attr(usart_v1, path = "v1.rs")] -#[cfg_attr(usart_v2, path = "v2.rs")] +//#[cfg_attr(usart_v1, path = "v1.rs")] +//#[cfg_attr(usart_v2, path = "v2.rs")] +#[cfg_attr(usart_v3, path = "v3.rs")] mod _version; use crate::peripherals; pub use _version::*; @@ -10,6 +11,51 @@ use crate::gpio::Pin; use crate::pac::usart::Usart; use crate::rcc::RccPeripheral; +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum DataBits { + DataBits8, + DataBits9, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Parity { + ParityNone, + ParityEven, + ParityOdd, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum StopBits { + #[doc = "1 stop bit"] + STOP1, + #[doc = "0.5 stop bits"] + STOP0P5, + #[doc = "2 stop bits"] + STOP2, + #[doc = "1.5 stop bits"] + STOP1P5, +} + +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Config { + pub baudrate: u32, + pub data_bits: DataBits, + pub stop_bits: StopBits, + pub parity: Parity, +} + +impl Default for Config { + fn default() -> Self { + Self { + baudrate: 115200, + data_bits: DataBits::DataBits8, + stop_bits: StopBits::STOP1, + parity: Parity::ParityNone, + } + } +} + /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[non_exhaustive] @@ -27,7 +73,7 @@ pub enum Error { pub(crate) mod sealed { use super::*; - #[cfg(dma)] + #[cfg(any(dma, dmamux))] use crate::dma::WriteDma; pub trait Instance { @@ -49,10 +95,10 @@ pub(crate) mod sealed { fn af_num(&self) -> u8; } - #[cfg(dma)] + #[cfg(any(dma, dmamux))] pub trait RxDma {} - #[cfg(dma)] + #[cfg(any(dma, dmamux))] pub trait TxDma: WriteDma {} } @@ -63,9 +109,10 @@ pub trait CtsPin: sealed::CtsPin {} pub trait RtsPin: sealed::RtsPin {} pub trait CkPin: sealed::CkPin {} -#[cfg(dma)] +#[cfg(any(dma, dmamux))] pub trait RxDma: sealed::RxDma {} -#[cfg(dma)] + +#[cfg(any(dma, dmamux))] pub trait TxDma: sealed::TxDma {} crate::pac::peripherals!( diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs index 6c5a1244..16993895 100644 --- a/embassy-stm32/src/usart/v1.rs +++ b/embassy-stm32/src/usart/v1.rs @@ -7,51 +7,6 @@ use crate::pac::usart::{regs, vals}; use super::*; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum DataBits { - DataBits8, - DataBits9, -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum Parity { - ParityNone, - ParityEven, - ParityOdd, -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum StopBits { - #[doc = "1 stop bit"] - STOP1, - #[doc = "0.5 stop bits"] - STOP0P5, - #[doc = "2 stop bits"] - STOP2, - #[doc = "1.5 stop bits"] - STOP1P5, -} - -#[non_exhaustive] -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Config { - pub baudrate: u32, - pub data_bits: DataBits, - pub stop_bits: StopBits, - pub parity: Parity, -} - -impl Default for Config { - fn default() -> Self { - Self { - baudrate: 115200, - data_bits: DataBits::DataBits8, - stop_bits: StopBits::STOP1, - parity: Parity::ParityNone, - } - } -} - pub struct Uart<'d, T: Instance> { inner: T, phantom: PhantomData<&'d mut T>, diff --git a/embassy-stm32/src/usart/v3.rs b/embassy-stm32/src/usart/v3.rs new file mode 100644 index 00000000..32850c9c --- /dev/null +++ b/embassy-stm32/src/usart/v3.rs @@ -0,0 +1,120 @@ +use core::marker::PhantomData; + +use embassy::util::Unborrow; +use embassy_extras::unborrow; + +use crate::pac::usart::{regs, vals}; + +use super::*; + +pub struct Uart<'d, T: Instance> { + inner: T, + phantom: PhantomData<&'d mut T>, +} + +impl<'d, T: Instance> Uart<'d, T> { + pub fn new( + inner: impl Unborrow, + rx: impl Unborrow>, + tx: impl Unborrow>, + config: Config, + ) -> Self { + unborrow!(inner, rx, tx); + + T::enable(); + let pclk_freq = T::frequency(); + + // TODO: better calculation, including error checking and OVER8 if possible. + let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; + + let r = inner.regs(); + + unsafe { + rx.set_as_af(rx.af_num()); + tx.set_as_af(tx.af_num()); + + r.brr().write_value(regs::Brr(div)); + r.cr1().write(|w| { + w.set_ue(true); + w.set_te(true); + w.set_re(true); + w.set_m(0, 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, + }); + }); + r.cr2().write(|_w| {}); + r.cr3().write(|_w| {}); + } + + Self { + inner, + phantom: PhantomData, + } + } + + #[cfg(dma)] + pub async fn write_dma(&mut self, ch: &mut impl TxDma, buffer: &[u8]) -> Result<(), Error> { + unsafe { + self.inner.regs().cr3().modify(|reg| { + reg.set_dmat(true); + }); + } + let r = self.inner.regs(); + let dst = r.dr().ptr() as *mut u8; + ch.transfer(buffer, dst).await; + Ok(()) + } + + pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + unsafe { + let r = self.inner.regs(); + for b in buffer { + loop { + let sr = r.isr().read(); + if sr.pe() { + r.rdr().read(); + return Err(Error::Parity); + } else if sr.fe() { + r.rdr().read(); + return Err(Error::Framing); + } else if sr.ne() { + r.rdr().read(); + return Err(Error::Noise); + } else if sr.ore() { + r.rdr().read(); + return Err(Error::Overrun); + } else if sr.rxne() { + break; + } + } + *b = r.rdr().read().0 as u8; + } + } + Ok(()) + } +} + +impl<'d, T: Instance> embedded_hal::blocking::serial::Write for Uart<'d, T> { + type Error = Error; + fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { + unsafe { + let r = self.inner.regs(); + for &b in buffer { + while !r.isr().read().txe() {} + r.tdr().write_value(regs::Tdr(b as u32)) + } + } + Ok(()) + } + fn bflush(&mut self) -> Result<(), Self::Error> { + unsafe { + let r = self.inner.regs(); + while !r.isr().read().tc() {} + } + Ok(()) + } +} diff --git a/stm32-data b/stm32-data index f0a6585b..424f96ea 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit f0a6585b4806b1f7c6836126d063eaaf970cc5a4 +Subproject commit 424f96eae80015536c4df5ed62c1caad85bb531f diff --git a/stm32-metapac/gen/src/lib.rs b/stm32-metapac/gen/src/lib.rs index a552c8ce..8eae4911 100644 --- a/stm32-metapac/gen/src/lib.rs +++ b/stm32-metapac/gen/src/lib.rs @@ -311,6 +311,7 @@ pub fn gen(options: Options) { for dma_request in &p.dma_requests { let mut row = Vec::new(); + row.push(bi.module.clone()); row.push(name.clone()); row.push(dma_request.0.clone()); row.push(dma_request.1.to_string());