diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 371741ff..466cfa03 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -1,9 +1,11 @@ #![macro_use] +#[cfg(dma)] #[cfg_attr(dma_v1, path = "v1.rs")] #[cfg_attr(dma_v2, path = "v2.rs")] mod _version; +#[cfg(dma)] #[allow(unused)] pub use _version::*; diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 9ba7bbe4..76a6ecd8 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -26,7 +26,7 @@ pub mod adc; pub mod clock; #[cfg(dac)] pub mod dac; -#[cfg(dma)] +#[cfg(any(dma, dmamux))] pub mod dma; #[cfg(all(eth, feature = "net"))] pub mod eth; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index a75793f8..2fa758ec 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -2,6 +2,7 @@ #[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!( @@ -93,6 +140,9 @@ macro_rules! impl_pin { } crate::pac::peripheral_pins!( + + // USART + ($inst:ident, usart, USART, $pin:ident, TX, $af:expr) => { impl_pin!($inst, $pin, TxPin, $af); }; @@ -112,4 +162,26 @@ crate::pac::peripheral_pins!( ($inst:ident, usart, USART, $pin:ident, CK, $af:expr) => { impl_pin!($inst, $pin, CkPin, $af); }; + + // UART + + ($inst:ident, uart, UART, $pin:ident, TX, $af:expr) => { + impl_pin!($inst, $pin, TxPin, $af); + }; + + ($inst:ident, uart, UART, $pin:ident, RX, $af:expr) => { + impl_pin!($inst, $pin, RxPin, $af); + }; + + ($inst:ident, uart, UART, $pin:ident, CTS, $af:expr) => { + impl_pin!($inst, $pin, CtsPin, $af); + }; + + ($inst:ident, uart, UART, $pin:ident, RTS, $af:expr) => { + impl_pin!($inst, $pin, RtsPin, $af); + }; + + ($inst:ident, uart, UART, $pin:ident, CK, $af:expr) => { + impl_pin!($inst, $pin, CkPin, $af); + }; ); 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..1e905144 --- /dev/null +++ b/embassy-stm32/src/usart/v3.rs @@ -0,0 +1,121 @@ +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); + + // Uncomment once we find all of the H7's UART clocks. + 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.tdr().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/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs new file mode 100644 index 00000000..b8524f2c --- /dev/null +++ b/examples/stm32h7/src/bin/usart.rs @@ -0,0 +1,99 @@ + +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use cortex_m::prelude::_embedded_hal_blocking_serial_Write; +use embassy::executor::Executor; +use embassy::time::Clock; +use embassy::util::Forever; +use embassy_stm32::usart::{Config, Uart}; +use example_common::*; + +use stm32h7xx_hal as hal; +use hal::prelude::*; + +use cortex_m_rt::entry; +use stm32h7::stm32h743 as pac; + +#[embassy::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, config); + + usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap(); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + loop { + usart.read(&mut buf).unwrap(); + usart.bwrite_all(&buf).unwrap(); + } +} + +struct ZeroClock; + +impl Clock for ZeroClock { + fn now(&self) -> u64 { + 0 + } +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let pp = pac::Peripherals::take().unwrap(); + + let pwrcfg = pp.PWR.constrain().freeze(); + + let rcc = pp.RCC.constrain(); + + let ccdr = rcc + .sys_ck(96.mhz()) + .pclk1(48.mhz()) + .pclk2(48.mhz()) + .pclk3(48.mhz()) + .pclk4(48.mhz()) + .pll1_q_ck(48.mhz()) + .freeze(pwrcfg, &pp.SYSCFG); + + let pp = unsafe { pac::Peripherals::steal() }; + + pp.DBGMCU.cr.modify(|_, w| { + w.dbgsleep_d1().set_bit(); + w.dbgstby_d1().set_bit(); + w.dbgstop_d1().set_bit(); + w.d1dbgcken().set_bit(); + w + }); + + pp.RCC.ahb4enr.modify(|_, w| { + w.gpioaen().set_bit(); + w.gpioben().set_bit(); + w.gpiocen().set_bit(); + w.gpioden().set_bit(); + w.gpioeen().set_bit(); + w.gpiofen().set_bit(); + w + }); + + + unsafe { embassy::time::set_clock(&ZeroClock) }; + + let executor = EXECUTOR.put(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} \ No newline at end of file diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs new file mode 100644 index 00000000..5b6d9eaa --- /dev/null +++ b/examples/stm32l4/src/bin/usart.rs @@ -0,0 +1,97 @@ + +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use cortex_m::prelude::_embedded_hal_blocking_serial_Write; +use embassy::executor::Executor; +use embassy::time::Clock; +use embassy::util::Forever; +use embassy_stm32::usart::{Config, Uart}; +use example_common::*; + +use cortex_m_rt::entry; +use stm32l4::stm32l4x5 as pac; + +#[embassy::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, config); + + usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap(); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + loop { + usart.read(&mut buf).unwrap(); + usart.bwrite_all(&buf).unwrap(); + } +} + +struct ZeroClock; + +impl Clock for ZeroClock { + fn now(&self) -> u64 { + 0 + } +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let pp = pac::Peripherals::take().unwrap(); + + pp.DBGMCU.cr.modify(|_, w| { + w.dbg_sleep().set_bit(); + w.dbg_standby().set_bit(); + w.dbg_stop().set_bit() + }); + + pp.RCC.ahb1enr.modify(|_, w| { + w.dma1en().set_bit(); + w + }); + + pp.RCC.ahb2enr.modify(|_, w| { + w.gpioaen().set_bit(); + w.gpioben().set_bit(); + w.gpiocen().set_bit(); + w.gpioden().set_bit(); + w.gpioeen().set_bit(); + w.gpiofen().set_bit(); + w + }); + + pp.RCC.apb1enr1.modify(|_, w| { + w.uart4en().set_bit(); + w + }); + + pp.RCC.apb2enr.modify(|_, w| { + w.syscfgen().set_bit(); + w + }); + //pp.RCC.apb1enr.modify(|_, w| { + //w.usart3en().enabled(); + //w + //}); + + unsafe { embassy::time::set_clock(&ZeroClock) }; + + let executor = EXECUTOR.put(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} \ No newline at end of file diff --git a/stm32-data b/stm32-data index f0a6585b..0877c27c 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit f0a6585b4806b1f7c6836126d063eaaf970cc5a4 +Subproject commit 0877c27cb1332237e65d74700b7bfb768996ca66 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());