diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index 1a49f4e1..ae7e9d23 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -6,25 +6,3 @@ mod _version; #[allow(unused)] pub use _version::*; - -use core::future::Future; - -pub trait WriteDma { - type WriteDmaFuture<'a>: Future + 'a - where - Self: 'a; - - fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> - where - T: 'a; -} - -pub trait ReadDma { - type ReadDmaFuture<'a>: Future + 'a - where - Self: 'a; - - fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> - where - T: 'a; -} diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs index f81a0876..fd3bf699 100644 --- a/embassy-stm32/src/bdma/v1.rs +++ b/embassy-stm32/src/bdma/v1.rs @@ -6,10 +6,11 @@ use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::util::{AtomicWaker, OnDrop}; use futures::future::poll_fn; -use super::{ReadDma, WriteDma}; +use crate::dma_traits::{ReadDma, WriteDma}; use crate::interrupt; use crate::pac; use crate::pac::bdma::vals; +use crate::rcc::sealed::RccPeripheral; const CH_COUNT: usize = pac::peripheral_count!(DMA) * 8; const CH_STATUS_NONE: u8 = 0; @@ -57,6 +58,9 @@ pub(crate) async unsafe fn transfer_p2m( while regs.cr().read().en() {} }); + #[cfg(dmamux)] + crate::dmamux::configure_channel(1, 2); + regs.par().write_value(src as u32); regs.mar().write_value(dst.as_mut_ptr() as u32); regs.ndtr().write(|w| w.set_ndt(dst.len() as u16)); @@ -88,6 +92,9 @@ pub(crate) async unsafe fn transfer_m2p( state_number: usize, src: &[u8], dst: *mut u8, + #[cfg(dmamux)] dmamux_regs: &'static pac::dmamux::Dmamux, + #[cfg(dmamux)] dmamux_ch_num: u8, + #[cfg(dmamux)] request: u8, ) { // ndtr is max 16 bits. assert!(src.len() <= 0xFFFF); @@ -105,6 +112,9 @@ pub(crate) async unsafe fn transfer_m2p( while regs.cr().read().en() {} }); + #[cfg(dmamux)] + crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); + regs.par().write_value(dst as u32); regs.mar().write_value(src.as_ptr() as u32); regs.ndtr().write(|w| w.set_ndt(src.len() as u16)); @@ -161,9 +171,10 @@ pub(crate) unsafe fn init() { } pac::peripherals! { (bdma, DMA1) => { - critical_section::with(|_| { - pac::RCC.ahbenr().modify(|w| w.set_dmaen(true)); - }); + //critical_section::with(|_| { + //pac::RCC.ahbenr().modify(|w| w.set_dmaen(true)); + //}); + crate::peripherals::DMA1::enable(); }; } } @@ -220,8 +231,10 @@ macro_rules! impl_dma_channel { } } + #[cfg(not(dmamux))] impl WriteDma for crate::peripherals::$channel_peri where + Self: crate::dmamux::sealed::PeripheralChannel, T: 'static, { type WriteDmaFuture<'a> = impl Future; @@ -234,10 +247,47 @@ macro_rules! impl_dma_channel { let state_num = self.state_num(); let regs = self.regs(); + unsafe { transfer_m2p(regs, state_num, buf, dst) } } } + #[cfg(dmamux)] + impl WriteDma for crate::peripherals::$channel_peri + where + Self: crate::dmamux::sealed::PeripheralChannel, + T: 'static, + { + type WriteDmaFuture<'a> = impl Future; + + fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> + where + T: 'a, + { + use sealed::Channel as _Channel; + + let state_num = self.state_num(); + let regs = self.regs(); + + use crate::dmamux::sealed::Channel as _MuxChannel; + use crate::dmamux::sealed::PeripheralChannel; + let dmamux_regs = self.dmamux_regs(); + let dmamux_ch_num = self.dma_ch_num(); + let request = PeripheralChannel::::request(self); + unsafe { + transfer_m2p( + regs, + state_num, + buf, + dst, + dmamux_regs, + dmamux_ch_num, + request, + ) + } + } + } + impl ReadDma for crate::peripherals::$channel_peri where T: 'static, @@ -292,6 +342,8 @@ pac::interrupts! { #[cfg(usart)] use crate::usart; + +#[cfg(not(dmamux))] pac::peripheral_dma_channels! { ($peri:ident, usart, $kind:ident, RX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { impl usart::RxDma for crate::peripherals::$channel_peri { } @@ -302,4 +354,34 @@ pac::peripheral_dma_channels! { impl usart::TxDma for crate::peripherals::$channel_peri { } impl usart::sealed::TxDma for crate::peripherals::$channel_peri { } }; + + ($peri:ident, uart, $kind:ident, RX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl usart::RxDma for crate::peripherals::$channel_peri { } + impl usart::sealed::RxDma for crate::peripherals::$channel_peri { } + }; + + ($peri:ident, uart, $kind:ident, TX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl usart::TxDma for crate::peripherals::$channel_peri { } + impl usart::sealed::TxDma for crate::peripherals::$channel_peri { } + }; +} + +#[cfg(dmamux)] +pac::peripherals! { + (usart, $peri:ident) => { + pac::dma_channels! { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl usart::TxDma for crate::peripherals::$channel_peri { } + impl usart::sealed::TxDma for crate::peripherals::$channel_peri { } + }; + } + }; + (uart, $peri:ident) => { + pac::dma_channels! { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl usart::TxDma for crate::peripherals::$channel_peri { } + impl usart::sealed::TxDma for crate::peripherals::$channel_peri { } + }; + } + }; } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 466cfa03..ed080cd1 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -1,6 +1,5 @@ #![macro_use] -#[cfg(dma)] #[cfg_attr(dma_v1, path = "v1.rs")] #[cfg_attr(dma_v2, path = "v2.rs")] mod _version; @@ -8,25 +7,3 @@ mod _version; #[cfg(dma)] #[allow(unused)] pub use _version::*; - -use core::future::Future; - -pub trait WriteDma { - type WriteDmaFuture<'a>: Future + 'a - where - Self: 'a; - - fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> - where - T: 'a; -} - -pub trait ReadDma { - type ReadDmaFuture<'a>: Future + 'a - where - Self: 'a; - - fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> - where - T: 'a; -} diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs index e7cd2471..5080776f 100644 --- a/embassy-stm32/src/dma/v2.rs +++ b/embassy-stm32/src/dma/v2.rs @@ -1,5 +1,6 @@ use core::task::Poll; +use crate::dma_traits::{ReadDma, WriteDma}; use atomic_polyfill::{AtomicU8, Ordering}; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::util::AtomicWaker; diff --git a/embassy-stm32/src/dma_traits.rs b/embassy-stm32/src/dma_traits.rs new file mode 100644 index 00000000..8f1a9f40 --- /dev/null +++ b/embassy-stm32/src/dma_traits.rs @@ -0,0 +1,21 @@ +use core::future::Future; + +pub trait WriteDma { + type WriteDmaFuture<'a>: Future + 'a + where + Self: 'a; + + fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> + where + T: 'a; +} + +pub trait ReadDma { + type ReadDmaFuture<'a>: Future + 'a + where + Self: 'a; + + fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> + where + T: 'a; +} diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index b4d5b983..745906cd 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -20,41 +20,11 @@ use crate::peripherals; use core::future::Future; -use crate::dma::{ReadDma, WriteDma}; +use crate::dma_traits::{ReadDma, WriteDma}; -const CH_COUNT: usize = peripheral_count!(DMA) * 8; -const CH_STATUS_NONE: u8 = 0; -const CH_STATUS_COMPLETED: u8 = 1; -const CH_STATUS_ERROR: u8 = 2; - -struct State { - ch_wakers: [AtomicWaker; CH_COUNT], - ch_status: [AtomicU8; CH_COUNT], -} - -impl State { - const fn new() -> Self { - const AW: AtomicWaker = AtomicWaker::new(); - const AU: AtomicU8 = AtomicU8::new(CH_STATUS_NONE); - Self { - ch_wakers: [AW; CH_COUNT], - ch_status: [AU; CH_COUNT], - } - } -} - -static STATE: State = State::new(); - -#[allow(unused)] -pub(crate) async unsafe fn transfer_p2m( - ch: &mut impl Channel, - ch_func: u8, - src: *const u8, - dst: &mut [u8], -) { - unimplemented!() -} +pub(crate) fn configure_channel(ch_num: u8, request_num: u8) {} +/* #[allow(unused)] pub(crate) async unsafe fn transfer_m2p( ch: &mut impl Channel, @@ -128,22 +98,36 @@ pub(crate) async unsafe fn transfer_m2p( // TODO handle error assert!(res == CH_STATUS_COMPLETED); } + */ + +pub(crate) unsafe fn configure_dmamux( + dmamux_regs: &pac::dmamux::Dmamux, + dmamux_ch_num: u8, + request: u8, +) { + let ch_mux_regs = dmamux_regs.ccr(dmamux_ch_num as _); + ch_mux_regs.write(|reg| { + // one request? + reg.set_nbreq(0); + reg.set_dmareq_id(request); + }); + + ch_mux_regs.modify(|reg| { + reg.set_ege(true); + //reg.set_se(true); + //reg.set_soie(true); + }); +} pub(crate) mod sealed { use super::*; - pub trait Bdma { - fn regs() -> &'static pac::bdma::Dma; - fn num() -> u8; - } - pub trait DmaMux { fn regs() -> &'static pac::dmamux::Dmamux; } pub trait Channel { fn num(&self) -> usize; - fn regs(&self) -> pac::bdma::Ch; fn dma_regs() -> &'static pac::bdma::Dma; fn dma_ch_num(&self) -> u8; @@ -156,7 +140,6 @@ pub(crate) mod sealed { } } -pub trait Bdma: sealed::Bdma {} pub trait DmaMux: sealed::DmaMux {} pub trait Channel: sealed::Channel {} pub trait PeripheralChannel: sealed::Channel {} @@ -172,10 +155,6 @@ macro_rules! impl_dma_channel { ($dma_num * 8) + $channel_num } - fn regs(&self) -> pac::bdma::Ch { - Self::dma_regs().ch(self.dma_ch_num() as _) - } - fn dma_regs() -> &'static pac::bdma::Dma { &crate::pac::$dma_peri } @@ -192,42 +171,6 @@ macro_rules! impl_dma_channel { ($dma_num * 8) + $channel_num } } - - impl WriteDma for peripherals::$channel_peri - where - Self: sealed::PeripheralChannel, - T: 'static, - { - type WriteDmaFuture<'a> = impl Future; - - fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> - where - T: 'a, - { - let request = sealed::PeripheralChannel::::request(self); - unsafe { transfer_m2p(self, request, buf, dst) } - } - } - - impl ReadDma for peripherals::$channel_peri - where - Self: sealed::PeripheralChannel, - T: 'static, - { - type ReadDmaFuture<'a> = impl Future; - - fn transfer<'a>( - &'a mut self, - src: *const u8, - buf: &'a mut [u8], - ) -> Self::ReadDmaFuture<'a> - where - T: 'a, - { - let request = sealed::PeripheralChannel::::request(self); - unsafe { transfer_p2m(self, request, src, buf) } - } - } }; } @@ -242,25 +185,8 @@ macro_rules! impl_dmamux { }; } -macro_rules! impl_bdma { - ($peri:ident, $dma_num:expr) => { - impl sealed::Bdma for peripherals::$peri { - fn num() -> u8 { - $dma_num - } - - fn regs() -> &'static pac::bdma::Dma { - &pac::$peri - } - } - - impl Bdma for peripherals::$peri {} - }; -} - peripherals! { (bdma, DMA1) => { - impl_bdma!(DMA1, 0); dma_channels! { ($channel_peri:ident, DMA1, $channel_num:expr) => { impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA1, 0); @@ -268,7 +194,6 @@ peripherals! { } }; (bdma, DMA2) => { - impl_bdma!(DMA2, 1); dma_channels! { ($channel_peri:ident, DMA2, $channel_num:expr) => { impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA2, 1); @@ -285,9 +210,6 @@ macro_rules! impl_usart_dma_requests { dma_requests! { // TODO: DRY this up. (usart, $peri:ident, RX, $request:expr) => { - impl usart::RxDma for peripherals::$channel_peri { } - impl usart::sealed::RxDma for peripherals::$channel_peri { } - impl sealed::PeripheralChannel for peripherals::$channel_peri { fn request(&self) -> u8 { $request @@ -299,9 +221,6 @@ macro_rules! impl_usart_dma_requests { }; (usart, $peri:ident, TX, $request:expr) => { - impl usart::TxDma for peripherals::$channel_peri { } - impl usart::sealed::TxDma for peripherals::$channel_peri { } - impl sealed::PeripheralChannel for peripherals::$channel_peri { fn request(&self) -> u8 { $request @@ -313,9 +232,6 @@ macro_rules! impl_usart_dma_requests { }; (uart, $peri:ident, TX, $request:expr) => { - impl usart::RxDma for peripherals::$channel_peri { } - impl usart::sealed::RxDma for peripherals::$channel_peri { } - impl sealed::PeripheralChannel for peripherals::$channel_peri { fn request(&self) -> u8 { $request @@ -326,9 +242,6 @@ macro_rules! impl_usart_dma_requests { }; (uart, $peri:ident, RX, $request:expr) => { - impl usart::TxDma for peripherals::$channel_peri { } - impl usart::sealed::TxDma for peripherals::$channel_peri { } - impl sealed::PeripheralChannel for peripherals::$channel_peri { fn request(&self) -> u8 { $request @@ -351,86 +264,5 @@ dma_channels! { }; } -unsafe fn on_irq() { - defmt::info!("irq fire"); - peripherals! { - //(bdma, $dma:ident) => { - (bdma, DMA1) => { - defmt::info!("---> dma DMA1"); - //for isrn in 0..2 { - //let isr = pac::$dma.isr(isrn).read(); - let isr = pac::DMA1.isr().read(); - pac::DMA1.ifcr().write_value(isr); - let dman = ::num() as usize; - - for chn in 0..8 { - let n = dman * 8 + chn; - defmt::info!("n={}", n); - if isr.teif(chn) { - defmt::info!("transfer error"); - STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Release); - STATE.ch_wakers[n].wake(); - } else if isr.tcif(chn) { - defmt::info!("transfer complete"); - STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Release); - STATE.ch_wakers[n].wake(); - } else if isr.htif(chn) { - defmt::info!("half transfer"); - } else if isr.gif(chn) { - defmt::info!("half transfer"); - } - } - //} - }; - - (bdma, DMA2) => { - defmt::info!("---> dma DMA2"); - //for isrn in 0..2 { - //let isr = pac::$dma.isr(isrn).read(); - let isr = pac::DMA2.isr().read(); - pac::DMA2.ifcr().write_value(isr); - let dman = ::num() as usize; - - for chn in 0..8 { - let n = dman * 8 + chn; - defmt::info!("n={}", n); - if isr.teif(chn) { - defmt::info!("transfer error"); - STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Release); - STATE.ch_wakers[n].wake(); - } else if isr.tcif(chn) { - defmt::info!("transfer complete"); - STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Release); - STATE.ch_wakers[n].wake(); - } else if isr.htif(chn) { - defmt::info!("half transfer"); - } else if isr.gif(chn) { - defmt::info!("half transfer"); - } - } - //} - }; - - } - defmt::info!("irq fire complete"); -} - /// safety: must be called only once -pub(crate) unsafe fn init() { - interrupts! { - (DMA, $irq:ident) => { - defmt::info!("enable irq {}", stringify!($irq)); - interrupt::$irq::steal().enable(); - }; - } -} - -interrupts! { - (DMA, $irq:ident) => { - #[crate::interrupt] - unsafe fn $irq () { - defmt::info!("irq firing {}", stringify!($irq)); - on_irq() - } - }; -} +pub(crate) unsafe fn init() {} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index f750c989..4b2826ae 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -20,6 +20,9 @@ pub mod gpio; pub mod rcc; // Sometimes-present hardware +#[cfg(any(dma, bdma, dmamux))] +pub mod dma_traits; + #[cfg(adc)] pub mod adc; #[cfg(bdma)] @@ -28,7 +31,7 @@ pub mod bdma; pub mod clock; #[cfg(dac)] pub mod dac; -#[cfg(any(dma, dmamux))] +#[cfg(dma)] pub mod dma; #[cfg(dmamux)] pub mod dmamux; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 2bab4016..ddaed5bb 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -73,11 +73,8 @@ pub enum Error { pub(crate) mod sealed { use super::*; - #[cfg(any(dma, dmamux))] - use crate::dma::WriteDma; - - #[cfg(bdma)] - use crate::bdma::WriteDma; + #[cfg(any(dma, bdma, dmamux))] + use crate::dma_traits::WriteDma; pub trait Instance { fn regs(&self) -> crate::pac::usart::Usart; diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs new file mode 100644 index 00000000..cc630e0d --- /dev/null +++ b/examples/stm32l4/src/bin/usart_dma.rs @@ -0,0 +1,96 @@ +#![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 core::fmt::Write; +use cortex_m_rt::entry; +use embassy::executor::Executor; +use embassy::time::Clock; +use embassy::util::Forever; +use embassy_stm32::usart::{Config, Uart}; +use example_common::*; +use heapless::String; +use stm32l4::stm32l4x5 as pac; + +#[embassy::task] +async fn main_task() { + let mut p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, config); + + for n in 0u32.. { + let mut s: String<128> = String::new(); + core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); + + usart + .write_dma(&mut p.DMA1_3, s.as_bytes()) + .await + .unwrap(); + info!("wrote DMA"); + } +} + +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| { + unsafe { + w.bits( 0x07 ); + } + w + //w.dmamuxen().set_bit(); + //w.dma1en().set_bit(); + //w.dma2en().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.apb2enr.modify(|_, w| { + w.syscfgen().set_bit(); + w + }); + + + unsafe { embassy::time::set_clock(&ZeroClock) }; + + let executor = EXECUTOR.put(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} diff --git a/stm32-data b/stm32-data index 409ed550..a2167373 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 409ed5502c254e462f3e31b0ea5ddee95f818a70 +Subproject commit a2167373ee8fd0e75dce003bfdbadda8b32ff77c diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 978f70b9..3f6a03fc 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -421,14 +421,16 @@ pub fn gen(options: Options) { clock.to_ascii_lowercase() }; - peripheral_rcc_table.push(vec![ - name.clone(), - clock, - enable_reg.to_ascii_lowercase(), - reset_reg.to_ascii_lowercase(), - format!("set_{}", enable_field.to_ascii_lowercase()), - format!("set_{}", reset_field.to_ascii_lowercase()), - ]); + if !name.starts_with("GPIO") { + peripheral_rcc_table.push(vec![ + name.clone(), + clock, + enable_reg.to_ascii_lowercase(), + reset_reg.to_ascii_lowercase(), + format!("set_{}", enable_field.to_ascii_lowercase()), + format!("set_{}", reset_field.to_ascii_lowercase()), + ]); + } } (None, Some(_)) => { print!("Unable to find enable register for {}", name)