From f32caaeaafd77b15005612b6d8d039b101b36975 Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Sat, 3 Jul 2021 17:58:59 -0300 Subject: [PATCH 01/32] STM: Start working on bdma-v1 --- embassy-stm32/src/bdma/mod.rs | 69 ++------- embassy-stm32/src/bdma/v1.rs | 275 ++++++++++++++++++++++++++++++++++ embassy-stm32/src/bdma/v2.rs | 1 + embassy-stm32/src/lib.rs | 4 + 4 files changed, 295 insertions(+), 54 deletions(-) create mode 100644 embassy-stm32/src/bdma/v1.rs create mode 100644 embassy-stm32/src/bdma/v2.rs diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index e85ade5d..1a49f4e1 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -7,63 +7,24 @@ mod _version; #[allow(unused)] pub use _version::*; -use crate::pac; -use crate::peripherals; +use core::future::Future; -pub(crate) mod sealed { - use super::*; +pub trait WriteDma { + type WriteDmaFuture<'a>: Future + 'a + where + Self: 'a; - pub trait Channel { - fn num(&self) -> u8; - - fn dma_num(&self) -> u8 { - self.num() / 8 - } - fn ch_num(&self) -> u8 { - self.num() % 8 - } - fn regs(&self) -> pac::dma::Dma { - pac::DMA(self.num() as _) - } - } + fn transfer<'a>(&'a mut self, buf: &'a [u8], dst: *mut u8) -> Self::WriteDmaFuture<'a> + where + T: 'a; } -pub trait Channel: sealed::Channel + Sized {} +pub trait ReadDma { + type ReadDmaFuture<'a>: Future + 'a + where + Self: 'a; -macro_rules! impl_dma_channel { - ($channel_peri:ident, $dma_num:expr, $ch_num:expr) => { - impl Channel for peripherals::$channel_peri {} - impl sealed::Channel for peripherals::$channel_peri { - #[inline] - fn num(&self) -> u8 { - $dma_num * 8 + $ch_num - } - } - }; + fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> + where + T: 'a; } - -/* -crate::pac::peripherals!( - (dma,DMA1) => { - impl_dma_channel!(DMA1_CH0, 0, 0); - impl_dma_channel!(DMA1_CH1, 0, 1); - impl_dma_channel!(DMA1_CH2, 0, 2); - impl_dma_channel!(DMA1_CH3, 0, 3); - impl_dma_channel!(DMA1_CH4, 0, 4); - impl_dma_channel!(DMA1_CH5, 0, 5); - impl_dma_channel!(DMA1_CH6, 0, 6); - impl_dma_channel!(DMA1_CH7, 0, 7); - }; - - (dma,DMA2) => { - impl_dma_channel!(DMA2_CH0, 1, 0); - impl_dma_channel!(DMA2_CH1, 1, 1); - impl_dma_channel!(DMA2_CH2, 1, 2); - impl_dma_channel!(DMA2_CH3, 1, 3); - impl_dma_channel!(DMA2_CH4, 1, 4); - impl_dma_channel!(DMA2_CH5, 1, 5); - impl_dma_channel!(DMA2_CH6, 1, 6); - impl_dma_channel!(DMA2_CH7, 1, 7); - }; -); - */ diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs new file mode 100644 index 00000000..584d531f --- /dev/null +++ b/embassy-stm32/src/bdma/v1.rs @@ -0,0 +1,275 @@ +use core::future::Future; +use core::task::Poll; + +use atomic_polyfill::{AtomicU8, Ordering}; +use embassy::interrupt::{Interrupt, InterruptExt}; +use embassy::util::{AtomicWaker, OnDrop}; +use futures::future::poll_fn; + +use super::{ReadDma, WriteDma}; +use crate::interrupt; +use crate::pac; +use crate::pac::bdma::vals; + +const CH_COUNT: usize = pac::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, src: *const u8, dst: &mut [u8]) { + // ndtr is max 16 bits. + assert!(dst.len() <= 0xFFFF); + + let regs: pac::bdma::Ch = ch.regs(); + let state_number = ch.state_num(); + + // Reset status + // Generate a DMB here to flush the store buffer (M7) before enabling the DMA + STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); + + let on_drop = OnDrop::new(|| unsafe { + regs.cr().modify(|w| { + w.set_tcie(false); + w.set_teie(false); + w.set_en(false); + }); + while regs.cr().read().en() {} + }); + + 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)); + regs.cr().write(|w| { + w.set_psize(vals::Size::BITS8); + w.set_msize(vals::Size::BITS8); + w.set_minc(vals::Inc::ENABLED); + w.set_teie(true); + w.set_tcie(true); + w.set_en(true); + }); + + let res = poll_fn(|cx| { + STATE.ch_wakers[state_number].register(cx.waker()); + match STATE.ch_status[state_number].load(Ordering::Acquire) { + CH_STATUS_NONE => Poll::Pending, + x => Poll::Ready(x), + } + }) + .await; + + on_drop.defuse(); + // TODO handle error + assert!(res == CH_STATUS_COMPLETED); +} + +#[allow(unused)] +pub(crate) async unsafe fn transfer_m2p(ch: &mut impl Channel, src: &[u8], dst: *mut u8) { + // ndtr is max 16 bits. + assert!(src.len() <= 0xFFFF); + + let regs: pac::bdma::Ch = ch.regs(); + let state_number = ch.state_num(); + + // Reset status + // Generate a DMB here to flush the store buffer (M7) before enabling the DMA + STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); + + let on_drop = OnDrop::new(|| unsafe { + regs.cr().modify(|w| { + w.set_tcie(false); + w.set_teie(false); + w.set_en(false); + }); + while regs.cr().read().en() {} + }); + + 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)); + regs.cr().write(|w| { + w.set_psize(vals::Size::BITS8); + w.set_msize(vals::Size::BITS8); + w.set_minc(vals::Inc::ENABLED); + w.set_dir(vals::Dir::FROMMEMORY); + w.set_teie(true); + w.set_tcie(true); + w.set_en(true); + }); + + let res = poll_fn(|cx| { + STATE.ch_wakers[state_number].register(cx.waker()); + match STATE.ch_status[state_number].load(Ordering::Acquire) { + CH_STATUS_NONE => Poll::Pending, + x => Poll::Ready(x), + } + }) + .await; + + on_drop.defuse(); + // TODO handle error + assert!(res == CH_STATUS_COMPLETED); +} + +unsafe fn on_irq() { + pac::peripherals! { + (bdma, $dma:ident) => { + let isr = pac::$dma.isr().read(); + pac::$dma.ifcr().write_value(isr); + let dman = ::num() as usize; + + for chn in 0..7 { + let n = dman * 8 + chn; + if isr.teif(chn) { + STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed); + STATE.ch_wakers[n].wake(); + } else if isr.tcif(chn) { + STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed); + STATE.ch_wakers[n].wake(); + } + } + + }; + } +} + +/// safety: must be called only once +pub(crate) unsafe fn init() { + pac::interrupts! { + (DMA, $irq:ident) => { + crate::interrupt::$irq::steal().enable(); + }; + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Dma { + fn num() -> u8; + } + + pub trait Channel { + fn dma_regs() -> &'static pac::bdma::Dma; + + fn state_num(&self) -> usize; + + fn ch_num(&self) -> u8; + + fn regs(&self) -> pac::bdma::Ch { + Self::dma_regs().ch(self.ch_num() as usize) + } + } +} + +pub trait Dma: sealed::Dma + Sized {} +pub trait Channel: sealed::Channel + Sized {} + +macro_rules! impl_dma { + ($peri:ident, $num:expr) => { + impl Dma for crate::peripherals::$peri {} + impl sealed::Dma for crate::peripherals::$peri { + fn num() -> u8 { + $num + } + } + }; +} + +macro_rules! impl_dma_channel { + ($channel_peri:ident, $dma_peri:ident, $dma_num:expr, $ch_num:expr) => { + impl Channel for crate::peripherals::$channel_peri {} + impl sealed::Channel for crate::peripherals::$channel_peri { + #[inline] + fn dma_regs() -> &'static pac::bdma::Dma { + &crate::pac::$dma_peri + } + + fn state_num(&self) -> usize { + ($dma_num * 8) + $ch_num + } + + fn ch_num(&self) -> u8 { + $ch_num + } + } + + impl WriteDma for crate::peripherals::$channel_peri + where + 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, + { + unsafe { transfer_m2p(self, buf, dst) } + } + } + + impl ReadDma for crate::peripherals::$channel_peri + where + 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, + { + unsafe { transfer_p2m(self, src, buf) } + } + } + }; +} + +pac::peripherals! { + (bdma, DMA1) => { + impl_dma!(DMA1, 0); + pac::dma_channels! { + ($channel_peri:ident, DMA1, $channel_num:expr) => { + impl_dma_channel!($channel_peri, DMA1, 0, $channel_num); + }; + } + }; + (bdma, DMA2) => { + impl_dma!(DMA2, 1); + pac::dma_channels! { + ($channel_peri:ident, DMA2, $channel_num:expr) => { + impl_dma_channel!($channel_peri, DMA2, 1, $channel_num); + }; + } + }; +} + +pac::interrupts! { + (DMA, $irq:ident) => { + #[crate::interrupt] + unsafe fn $irq () { + on_irq() + } + }; +} diff --git a/embassy-stm32/src/bdma/v2.rs b/embassy-stm32/src/bdma/v2.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/embassy-stm32/src/bdma/v2.rs @@ -0,0 +1 @@ + diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 76a6ecd8..35a8d3ba 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -22,6 +22,8 @@ pub mod rcc; // Sometimes-present hardware #[cfg(adc)] pub mod adc; +#[cfg(bdma)] +pub mod bdma; #[cfg(timer)] pub mod clock; #[cfg(dac)] @@ -86,6 +88,8 @@ pub fn init(config: Config) -> Peripherals { unsafe { #[cfg(dma)] dma::init(); + #[cfg(bdma)] + bdma::init(); #[cfg(exti)] exti::init(); rcc::init(config.rcc); From a56ddfdc04a02d9de2dc474f5cc9dbae8cff1ab1 Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Sun, 4 Jul 2021 15:40:33 -0300 Subject: [PATCH 02/32] STM: Add usart v2 --- embassy-stm32/src/bdma/v1.rs | 38 +++++++---- embassy-stm32/src/usart/v2.rs | 118 ++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 13 deletions(-) diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs index 584d531f..13caf329 100644 --- a/embassy-stm32/src/bdma/v1.rs +++ b/embassy-stm32/src/bdma/v1.rs @@ -35,13 +35,15 @@ impl State { static STATE: State = State::new(); #[allow(unused)] -pub(crate) async unsafe fn transfer_p2m(ch: &mut impl Channel, src: *const u8, dst: &mut [u8]) { +pub(crate) async unsafe fn transfer_p2m( + regs: pac::bdma::Ch, + state_number: usize, + src: *const u8, + dst: &mut [u8], +) { // ndtr is max 16 bits. assert!(dst.len() <= 0xFFFF); - let regs: pac::bdma::Ch = ch.regs(); - let state_number = ch.state_num(); - // Reset status // Generate a DMB here to flush the store buffer (M7) before enabling the DMA STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); @@ -82,13 +84,15 @@ pub(crate) async unsafe fn transfer_p2m(ch: &mut impl Channel, src: *const u8, d } #[allow(unused)] -pub(crate) async unsafe fn transfer_m2p(ch: &mut impl Channel, src: &[u8], dst: *mut u8) { +pub(crate) async unsafe fn transfer_m2p( + regs: pac::bdma::Ch, + state_number: usize, + src: &[u8], + dst: *mut u8, +) { // ndtr is max 16 bits. assert!(src.len() <= 0xFFFF); - let regs: pac::bdma::Ch = ch.regs(); - let state_number = ch.state_num(); - // Reset status // Generate a DMB here to flush the store buffer (M7) before enabling the DMA STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); @@ -168,7 +172,7 @@ pub(crate) mod sealed { } pub trait Channel { - fn dma_regs() -> &'static pac::bdma::Dma; + fn dma_regs() -> pac::bdma::Dma; fn state_num(&self) -> usize; @@ -199,8 +203,8 @@ macro_rules! impl_dma_channel { impl Channel for crate::peripherals::$channel_peri {} impl sealed::Channel for crate::peripherals::$channel_peri { #[inline] - fn dma_regs() -> &'static pac::bdma::Dma { - &crate::pac::$dma_peri + fn dma_regs() -> pac::bdma::Dma { + crate::pac::$dma_peri } fn state_num(&self) -> usize { @@ -222,7 +226,11 @@ macro_rules! impl_dma_channel { where T: 'a, { - unsafe { transfer_m2p(self, buf, dst) } + use sealed::Channel as _Channel; + + let state_num = self.state_num(); + let regs = self.regs(); + unsafe { transfer_m2p(regs, state_num, buf, dst) } } } @@ -240,7 +248,11 @@ macro_rules! impl_dma_channel { where T: 'a, { - unsafe { transfer_p2m(self, src, buf) } + use sealed::Channel as _Channel; + + let state_num = self.state_num(); + let regs = self.regs(); + unsafe { transfer_p2m(regs, state_num, src, buf) } } } }; diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index 8b137891..271eff85 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs @@ -1 +1,119 @@ +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; + + 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_m0(vals::M0::BIT8); + w.set_m1(vals::M1::M0); + 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.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(|w| w.set_dr(b as u16)); + } + } + Ok(()) + } + fn bflush(&mut self) -> Result<(), Self::Error> { + unsafe { + let r = self.inner.regs(); + while !r.isr().read().tc() {} + } + Ok(()) + } +} From 91521a86a0b273a8f375eff205963df14fa93f4f Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Sun, 4 Jul 2021 18:34:37 -0300 Subject: [PATCH 03/32] F0: usart + DMA working --- embassy-stm32/src/bdma/v1.rs | 24 +++++++++++++++++++++--- embassy-stm32/src/usart/mod.rs | 15 +++++++++------ embassy-stm32/src/usart/v2.rs | 12 ++++++------ 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs index 13caf329..f81a0876 100644 --- a/embassy-stm32/src/bdma/v1.rs +++ b/embassy-stm32/src/bdma/v1.rs @@ -78,7 +78,6 @@ pub(crate) async unsafe fn transfer_p2m( }) .await; - on_drop.defuse(); // TODO handle error assert!(res == CH_STATUS_COMPLETED); } @@ -128,7 +127,6 @@ pub(crate) async unsafe fn transfer_m2p( }) .await; - on_drop.defuse(); // TODO handle error assert!(res == CH_STATUS_COMPLETED); } @@ -150,7 +148,6 @@ unsafe fn on_irq() { STATE.ch_wakers[n].wake(); } } - }; } } @@ -162,6 +159,13 @@ pub(crate) unsafe fn init() { crate::interrupt::$irq::steal().enable(); }; } + pac::peripherals! { + (bdma, DMA1) => { + critical_section::with(|_| { + pac::RCC.ahbenr().modify(|w| w.set_dmaen(true)); + }); + }; + } } pub(crate) mod sealed { @@ -285,3 +289,17 @@ pac::interrupts! { } }; } + +#[cfg(usart)] +use crate::usart; +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 { } + impl usart::sealed::RxDma for crate::peripherals::$channel_peri { } + }; + + ($peri:ident, usart, $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 { } + }; +} diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 2fa758ec..2bab4016 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -8,7 +8,6 @@ use crate::peripherals; pub use _version::*; use crate::gpio::Pin; -use crate::pac::usart::Usart; use crate::rcc::RccPeripheral; #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -58,6 +57,7 @@ impl Default for Config { /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { /// Framing error @@ -76,8 +76,11 @@ pub(crate) mod sealed { #[cfg(any(dma, dmamux))] use crate::dma::WriteDma; + #[cfg(bdma)] + use crate::bdma::WriteDma; + pub trait Instance { - fn regs(&self) -> Usart; + fn regs(&self) -> crate::pac::usart::Usart; } pub trait RxPin: Pin { fn af_num(&self) -> u8; @@ -95,10 +98,10 @@ pub(crate) mod sealed { fn af_num(&self) -> u8; } - #[cfg(any(dma, dmamux))] + #[cfg(any(bdma, dma, dmamux))] pub trait RxDma {} - #[cfg(any(dma, dmamux))] + #[cfg(any(bdma, dma, dmamux))] pub trait TxDma: WriteDma {} } @@ -109,10 +112,10 @@ pub trait CtsPin: sealed::CtsPin {} pub trait RtsPin: sealed::RtsPin {} pub trait CkPin: sealed::CkPin {} -#[cfg(any(dma, dmamux))] +#[cfg(any(bdma, dma, dmamux))] pub trait RxDma: sealed::RxDma {} -#[cfg(any(dma, dmamux))] +#[cfg(any(bdma, dma, dmamux))] pub trait TxDma: sealed::TxDma {} crate::pac::peripherals!( diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index 271eff85..22041b4a 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_extras::unborrow; -use crate::pac::usart::{regs, vals}; +use crate::pac::usart::vals; use super::*; @@ -21,7 +21,6 @@ impl<'d, T: Instance> Uart<'d, T> { ) -> Self { unborrow!(inner, rx, tx); - // Uncomment once we find all of the H7's UART clocks. T::enable(); let pclk_freq = T::frequency(); @@ -34,7 +33,10 @@ impl<'d, T: Instance> Uart<'d, T> { rx.set_as_af(rx.af_num()); tx.set_as_af(tx.af_num()); - r.brr().write_value(regs::Brr(div)); + r.cr2().write(|_w| {}); + r.cr3().write(|_w| {}); + + r.brr().write(|w| w.set_brr(div as u16)); r.cr1().write(|w| { w.set_ue(true); w.set_te(true); @@ -48,8 +50,6 @@ impl<'d, T: Instance> Uart<'d, T> { _ => vals::Ps::EVEN, }); }); - r.cr2().write(|_w| {}); - r.cr3().write(|_w| {}); } Self { @@ -58,7 +58,7 @@ impl<'d, T: Instance> Uart<'d, T> { } } - #[cfg(dma)] + #[cfg(bdma)] pub async fn write_dma(&mut self, ch: &mut impl TxDma, buffer: &[u8]) -> Result<(), Error> { unsafe { self.inner.regs().cr3().modify(|reg| { From 043f0ea5088e02f509b3e1f013192c44c7854540 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Fri, 2 Jul 2021 09:54:31 -0400 Subject: [PATCH 04/32] Checkpoint DMAMUX channel setup. --- embassy-stm32/src/dmamux/mod.rs | 187 ++++++++++++++++++++++++++++++ embassy-stm32/src/lib.rs | 2 + embassy-stm32/src/usart/v3.rs | 2 +- examples/stm32l4/src/bin/usart.rs | 4 - 4 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 embassy-stm32/src/dmamux/mod.rs diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs new file mode 100644 index 00000000..4939d26a --- /dev/null +++ b/embassy-stm32/src/dmamux/mod.rs @@ -0,0 +1,187 @@ +#![macro_use] + +use crate::pac::dma_channels; +use crate::pac::dma_requests; +use crate::pac::peripherals; +use crate::peripherals; + +use core::future::Future; + +use crate::dma::{ReadDma, WriteDma}; + +#[allow(unused)] +pub(crate) async unsafe fn transfer_p2m( + ch: &mut impl Channel, + ch_func: u8, + src: *const u8, + dst: &mut [u8], +) { + unimplemented!() +} + +#[allow(unused)] +pub(crate) async unsafe fn transfer_m2p( + ch: &mut impl Channel, + ch_func: u8, + src: &[u8], + dst: *mut u8, +) { + unimplemented!() +} + +pub(crate) mod sealed { + use super::*; + + pub trait DmaMux {} + + pub trait Channel { + fn dmamux_ch_num(&self) -> u8; + } + + pub trait PeripheralChannel: Channel { + fn request(&self) -> u8; + } +} + +pub trait DmaMux: sealed::DmaMux {} +pub trait Channel: sealed::Channel {} +pub trait PeripheralChannel: sealed::Channel {} + +pub struct P2M; +pub struct M2P; + +macro_rules! impl_dma_channel { + ($channel_peri:ident, $dmamux_peri:ident, $channel_num:expr, $dma_num:expr) => { + impl Channel for peripherals::$channel_peri {} + impl sealed::Channel for peripherals::$channel_peri { + fn dmamux_ch_num(&self) -> u8 { + ($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) } + } + } + }; +} + +peripherals! { + (bdma, DMA1) => { + //impl_dma!(DMA1, 0); + dma_channels! { + ($channel_peri:ident, DMA1, $channel_num:expr) => { + impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, 0); + }; + } + }; + (bdma, DMA2) => { + //impl_dma!(DMA2, 1); + dma_channels! { + ($channel_peri:ident, DMA2, $channel_num:expr) => { + impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, 1); + }; + } + }; +} + +macro_rules! impl_usart_dma_requests { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + dma_requests! { + (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 + } + } + + impl PeripheralChannel for peripherals::$channel_peri { } + + }; + + (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 + } + } + + impl PeripheralChannel for peripherals::$channel_peri { } + + }; + + (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 + } + } + + impl PeripheralChannel for peripherals::$channel_peri { } + }; + + (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 + } + } + + impl PeripheralChannel for peripherals::$channel_peri { } + }; + } + + }; +} + +#[cfg(usart)] +use crate::usart; + +dma_channels! { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl_usart_dma_requests!($channel_peri, $dma_peri, $channel_num); + }; +} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 35a8d3ba..67962fdd 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -30,6 +30,8 @@ pub mod clock; pub mod dac; #[cfg(any(dma, dmamux))] pub mod dma; +#[cfg(dmamux)] +pub mod dmamux; #[cfg(all(eth, feature = "net"))] pub mod eth; #[cfg(exti)] diff --git a/embassy-stm32/src/usart/v3.rs b/embassy-stm32/src/usart/v3.rs index 1e905144..0071c597 100644 --- a/embassy-stm32/src/usart/v3.rs +++ b/embassy-stm32/src/usart/v3.rs @@ -57,7 +57,7 @@ impl<'d, T: Instance> Uart<'d, T> { } } - #[cfg(dma)] + #[cfg(any(dma, dmamux))] pub async fn write_dma(&mut self, ch: &mut impl TxDma, buffer: &[u8]) -> Result<(), Error> { unsafe { self.inner.regs().cr3().modify(|reg| { diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index 5b6d9eaa..0b14eeb5 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs @@ -82,10 +82,6 @@ fn main() -> ! { w.syscfgen().set_bit(); w }); - //pp.RCC.apb1enr.modify(|_, w| { - //w.usart3en().enabled(); - //w - //}); unsafe { embassy::time::set_clock(&ZeroClock) }; From 31325a25475f124e55c88477c4ee39f013f8beff Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Fri, 2 Jul 2021 10:25:24 -0400 Subject: [PATCH 05/32] Another checkpoint. --- embassy-stm32/src/dmamux/mod.rs | 57 +++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index 4939d26a..fc043a3f 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -1,7 +1,15 @@ #![macro_use] +use core::task::Poll; +use atomic_polyfill::{AtomicU8, Ordering}; +use embassy::interrupt::{Interrupt, InterruptExt}; +use embassy::util::AtomicWaker; +use futures::future::poll_fn; + +use crate::pac; use crate::pac::dma_channels; use crate::pac::dma_requests; +use crate::pac::peripheral_count; use crate::pac::peripherals; use crate::peripherals; @@ -9,6 +17,29 @@ use core::future::Future; use crate::dma::{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, @@ -32,9 +63,12 @@ pub(crate) async unsafe fn transfer_m2p( pub(crate) mod sealed { use super::*; - pub trait DmaMux {} + pub trait DmaMux { + fn regs() -> &'static pac::dmamux::Dmamux; + } pub trait Channel { + fn dmamux_regs() -> &'static pac::dmamux::Dmamux; fn dmamux_ch_num(&self) -> u8; } @@ -54,6 +88,10 @@ macro_rules! impl_dma_channel { ($channel_peri:ident, $dmamux_peri:ident, $channel_num:expr, $dma_num:expr) => { impl Channel for peripherals::$channel_peri {} impl sealed::Channel for peripherals::$channel_peri { + fn dmamux_regs() -> &'static pac::dmamux::Dmamux { + &crate::pac::$dmamux_peri + } + fn dmamux_ch_num(&self) -> u8 { ($dma_num * 8) + $channel_num } @@ -97,9 +135,19 @@ macro_rules! impl_dma_channel { }; } +macro_rules! impl_dmamux { + ($peri:ident) => { + impl sealed::DmaMux for peripherals::$peri { + fn regs() -> &'static pac::dmamux::Dmamux { + &pac::$peri + } + } + impl DmaMux for peripherals::$peri {} + }; +} + peripherals! { (bdma, DMA1) => { - //impl_dma!(DMA1, 0); dma_channels! { ($channel_peri:ident, DMA1, $channel_num:expr) => { impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, 0); @@ -107,18 +155,21 @@ peripherals! { } }; (bdma, DMA2) => { - //impl_dma!(DMA2, 1); dma_channels! { ($channel_peri:ident, DMA2, $channel_num:expr) => { impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, 1); }; } }; + (dmamux, DMAMUX1) => { + impl_dmamux!(DMAMUX1); + }; } macro_rules! impl_usart_dma_requests { ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { 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 { } From acdf7f4f1380672a07045226df8fe74dffcb21dd Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Fri, 2 Jul 2021 13:46:52 -0400 Subject: [PATCH 06/32] Another checkpoint. --- embassy-stm32/src/dmamux/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index fc043a3f..bbc4bfb1 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -57,6 +57,8 @@ pub(crate) async unsafe fn transfer_m2p( src: &[u8], dst: *mut u8, ) { + let dmamux_regs = ch.dmamux_regs(); + let ch_mux_regs = dmamux_regs.ccr(ch.dmamux_ch_num() as _); unimplemented!() } @@ -68,7 +70,7 @@ pub(crate) mod sealed { } pub trait Channel { - fn dmamux_regs() -> &'static pac::dmamux::Dmamux; + fn dmamux_regs(&self) -> &'static pac::dmamux::Dmamux; fn dmamux_ch_num(&self) -> u8; } @@ -88,7 +90,7 @@ macro_rules! impl_dma_channel { ($channel_peri:ident, $dmamux_peri:ident, $channel_num:expr, $dma_num:expr) => { impl Channel for peripherals::$channel_peri {} impl sealed::Channel for peripherals::$channel_peri { - fn dmamux_regs() -> &'static pac::dmamux::Dmamux { + fn dmamux_regs(&self) -> &'static pac::dmamux::Dmamux { &crate::pac::$dmamux_peri } From 6ec725309580b86889cf3d10070a1f18046182a0 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Tue, 6 Jul 2021 09:54:55 -0400 Subject: [PATCH 07/32] Checkpoint my DMA for thales. --- embassy-stm32/src/dmamux/mod.rs | 204 +++++++++++++++++++++++++++++++- embassy-stm32/src/lib.rs | 3 + 2 files changed, 203 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index bbc4bfb1..b4d5b983 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -6,9 +6,14 @@ use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::util::AtomicWaker; use futures::future::poll_fn; +use crate::interrupt; + +use crate::pac::bdma::{regs, vals}; + use crate::pac; use crate::pac::dma_channels; use crate::pac::dma_requests; +use crate::pac::interrupts; use crate::pac::peripheral_count; use crate::pac::peripherals; use crate::peripherals; @@ -57,19 +62,91 @@ pub(crate) async unsafe fn transfer_m2p( src: &[u8], dst: *mut u8, ) { + defmt::info!( + "m2p {} func {} {}-{}", + src.len(), + ch_func, + ch.num(), + ch.dma_ch_num() + ); + let n = ch.num(); + + STATE.ch_status[n].store(CH_STATUS_NONE, Ordering::Release); + + let ch_regs = ch.regs(); let dmamux_regs = ch.dmamux_regs(); let ch_mux_regs = dmamux_regs.ccr(ch.dmamux_ch_num() as _); - unimplemented!() + + ch_mux_regs.write(|reg| { + // one request? + reg.set_nbreq(0); + reg.set_dmareq_id(ch_func); + }); + + ch_mux_regs.modify(|reg| { + reg.set_ege(true); + //reg.set_se(true); + //reg.set_soie(true); + }); + + ch_regs.par().write_value(dst as _); + ch_regs.mar().write_value(src.as_ptr() as _); + ch_regs.ndtr().write_value(regs::Ndtr(src.len() as _)); + + ch_regs.cr().write(|reg| { + reg.set_dir(vals::Dir::FROMMEMORY); + reg.set_msize(vals::Size::BITS8); + reg.set_minc(vals::Inc::ENABLED); + reg.set_pinc(vals::Inc::DISABLED); + reg.set_teie(true); + reg.set_tcie(true); + reg.set_en(true); + }); + + let res = poll_fn(|cx| { + defmt::info!("poll"); + STATE.ch_wakers[n].register(cx.waker()); + match STATE.ch_status[n].load(Ordering::Acquire) { + CH_STATUS_NONE => Poll::Pending, + x => Poll::Ready(x), + } + }) + .await; + + defmt::info!("cr {:b}", ch_regs.cr().read().0); + + ch_regs.cr().modify(|reg| { + reg.set_en(false); + }); + + ch_mux_regs.modify(|reg| { + reg.set_ege(false); + //reg.set_se(true); + //reg.set_soie(true); + }); + + // TODO handle error + assert!(res == CH_STATUS_COMPLETED); } 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; + fn dmamux_regs(&self) -> &'static pac::dmamux::Dmamux; fn dmamux_ch_num(&self) -> u8; } @@ -79,6 +156,7 @@ pub(crate) mod sealed { } } +pub trait Bdma: sealed::Bdma {} pub trait DmaMux: sealed::DmaMux {} pub trait Channel: sealed::Channel {} pub trait PeripheralChannel: sealed::Channel {} @@ -87,9 +165,25 @@ pub struct P2M; pub struct M2P; macro_rules! impl_dma_channel { - ($channel_peri:ident, $dmamux_peri:ident, $channel_num:expr, $dma_num:expr) => { + ($channel_peri:ident, $dmamux_peri:ident, $channel_num:expr, $dma_peri: ident, $dma_num:expr) => { impl Channel for peripherals::$channel_peri {} impl sealed::Channel for peripherals::$channel_peri { + fn num(&self) -> usize { + ($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 + } + + fn dma_ch_num(&self) -> u8 { + $channel_num + } + fn dmamux_regs(&self) -> &'static pac::dmamux::Dmamux { &crate::pac::$dmamux_peri } @@ -148,18 +242,36 @@ 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, 0); + impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA1, 0); }; } }; (bdma, DMA2) => { + impl_bdma!(DMA2, 1); dma_channels! { ($channel_peri:ident, DMA2, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, 1); + impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA2, 1); }; } }; @@ -238,3 +350,87 @@ dma_channels! { impl_usart_dma_requests!($channel_peri, $dma_peri, $channel_num); }; } + +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() + } + }; +} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 67962fdd..f750c989 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -92,8 +92,11 @@ pub fn init(config: Config) -> Peripherals { dma::init(); #[cfg(bdma)] bdma::init(); + #[cfg(dmamux)] + dmamux::init(); #[cfg(exti)] exti::init(); + rcc::init(config.rcc); } From f01ddd5f5c2ec9505037663db8b1d54d7c153b0f Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Thu, 8 Jul 2021 14:55:27 -0400 Subject: [PATCH 08/32] Mix dmamux into bdma_v1. --- embassy-stm32/src/bdma/mod.rs | 22 --- embassy-stm32/src/bdma/v1.rs | 90 ++++++++++- embassy-stm32/src/dma/mod.rs | 23 --- embassy-stm32/src/dma/v2.rs | 1 + embassy-stm32/src/dma_traits.rs | 21 +++ embassy-stm32/src/dmamux/mod.rs | 216 +++----------------------- embassy-stm32/src/lib.rs | 5 +- embassy-stm32/src/usart/mod.rs | 7 +- examples/stm32l4/src/bin/usart_dma.rs | 96 ++++++++++++ stm32-data | 2 +- stm32-metapac-gen/src/lib.rs | 18 ++- 11 files changed, 245 insertions(+), 256 deletions(-) create mode 100644 embassy-stm32/src/dma_traits.rs create mode 100644 examples/stm32l4/src/bin/usart_dma.rs 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) From 30a1d9bf933831cc310e1d1eb719d0ec7f431099 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Thu, 8 Jul 2021 15:59:39 -0400 Subject: [PATCH 09/32] Move to copying regs instead of &'static referencing. Remove unneeded stuff from the DMAMUX end of the stick. --- embassy-stm32/src/bdma/v1.rs | 4 ++-- embassy-stm32/src/dmamux/mod.rs | 30 +++++++----------------------- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs index fd3bf699..5d612367 100644 --- a/embassy-stm32/src/bdma/v1.rs +++ b/embassy-stm32/src/bdma/v1.rs @@ -92,7 +92,7 @@ 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_regs: pac::dmamux::Dmamux, #[cfg(dmamux)] dmamux_ch_num: u8, #[cfg(dmamux)] request: u8, ) { @@ -272,7 +272,7 @@ macro_rules! impl_dma_channel { 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 dmamux_ch_num = self.dmamux_ch_num(); let request = PeripheralChannel::::request(self); unsafe { transfer_m2p( diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index 745906cd..79dea296 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -101,7 +101,7 @@ pub(crate) async unsafe fn transfer_m2p( */ pub(crate) unsafe fn configure_dmamux( - dmamux_regs: &pac::dmamux::Dmamux, + dmamux_regs: pac::dmamux::Dmamux, dmamux_ch_num: u8, request: u8, ) { @@ -123,15 +123,11 @@ pub(crate) mod sealed { use super::*; pub trait DmaMux { - fn regs() -> &'static pac::dmamux::Dmamux; + fn regs() -> pac::dmamux::Dmamux; } pub trait Channel { - fn num(&self) -> usize; - fn dma_regs() -> &'static pac::bdma::Dma; - fn dma_ch_num(&self) -> u8; - - fn dmamux_regs(&self) -> &'static pac::dmamux::Dmamux; + fn dmamux_regs(&self) -> pac::dmamux::Dmamux; fn dmamux_ch_num(&self) -> u8; } @@ -151,20 +147,8 @@ macro_rules! impl_dma_channel { ($channel_peri:ident, $dmamux_peri:ident, $channel_num:expr, $dma_peri: ident, $dma_num:expr) => { impl Channel for peripherals::$channel_peri {} impl sealed::Channel for peripherals::$channel_peri { - fn num(&self) -> usize { - ($dma_num * 8) + $channel_num - } - - fn dma_regs() -> &'static pac::bdma::Dma { - &crate::pac::$dma_peri - } - - fn dma_ch_num(&self) -> u8 { - $channel_num - } - - fn dmamux_regs(&self) -> &'static pac::dmamux::Dmamux { - &crate::pac::$dmamux_peri + fn dmamux_regs(&self) -> pac::dmamux::Dmamux { + crate::pac::$dmamux_peri } fn dmamux_ch_num(&self) -> u8 { @@ -177,8 +161,8 @@ macro_rules! impl_dma_channel { macro_rules! impl_dmamux { ($peri:ident) => { impl sealed::DmaMux for peripherals::$peri { - fn regs() -> &'static pac::dmamux::Dmamux { - &pac::$peri + fn regs() -> pac::dmamux::Dmamux { + pac::$peri } } impl DmaMux for peripherals::$peri {} From 811ed18922104f36580ab5d9d32555578a5fb9c6 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Thu, 8 Jul 2021 16:06:43 -0400 Subject: [PATCH 10/32] Add a missing 'use' for dma_v2. --- embassy-stm32/src/dma/v2.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs index 5080776f..cec8fe87 100644 --- a/embassy-stm32/src/dma/v2.rs +++ b/embassy-stm32/src/dma/v2.rs @@ -2,6 +2,7 @@ use core::task::Poll; use crate::dma_traits::{ReadDma, WriteDma}; use atomic_polyfill::{AtomicU8, Ordering}; +use core::future::Future; use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::util::AtomicWaker; use futures::future::poll_fn; From 6e699922173a8c85477c887690cc7d268187d380 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Thu, 8 Jul 2021 16:14:09 -0400 Subject: [PATCH 11/32] Add a no-op bdma for bdma v2 for CI. --- embassy-stm32/src/bdma/v2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/bdma/v2.rs b/embassy-stm32/src/bdma/v2.rs index 8b137891..956b83cd 100644 --- a/embassy-stm32/src/bdma/v2.rs +++ b/embassy-stm32/src/bdma/v2.rs @@ -1 +1 @@ - +pub(crate) unsafe fn init() {} From 6552af8f0b6d652d59b9ba17b31759c5b0a9ffa2 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Thu, 8 Jul 2021 16:17:05 -0400 Subject: [PATCH 12/32] Fix warning for unused import. --- embassy-stm32/src/dma/v2.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs index cec8fe87..df3b922f 100644 --- a/embassy-stm32/src/dma/v2.rs +++ b/embassy-stm32/src/dma/v2.rs @@ -7,7 +7,6 @@ use embassy::interrupt::{Interrupt, InterruptExt}; use embassy::util::AtomicWaker; use futures::future::poll_fn; -use super::*; use crate::interrupt; use crate::pac; use crate::pac::dma::{regs, vals}; From 696a3b855255dd8c91ab782f5956b4c7ef492c9c Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Fri, 9 Jul 2021 09:12:11 -0400 Subject: [PATCH 13/32] Try to figure out h7cm's problem. --- embassy-stm32/src/bdma/v1.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs index 5d612367..4488e2e9 100644 --- a/embassy-stm32/src/bdma/v1.rs +++ b/embassy-stm32/src/bdma/v1.rs @@ -329,6 +329,15 @@ pac::peripherals! { }; } }; + // Because H7cm changes the naming + (bdma, BDMA) => { + impl_dma!(BDMA, 0); + pac::dma_channels! { + ($channel_peri:ident, DMA1, $channel_num:expr) => { + impl_dma_channel!($channel_peri, BDMA, 0, $channel_num); + }; + } + }; } pac::interrupts! { From 13975a08184b51b91edcb67b96694129389717f2 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Fri, 9 Jul 2021 09:33:17 -0400 Subject: [PATCH 14/32] Try to improve H7 clockstuff. --- embassy-stm32/src/rcc/h7/mod.rs | 1 + embassy-stm32/src/rcc/mod.rs | 3 +++ stm32-data | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h7/mod.rs b/embassy-stm32/src/rcc/h7/mod.rs index 30990233..5ec53182 100644 --- a/embassy-stm32/src/rcc/h7/mod.rs +++ b/embassy-stm32/src/rcc/h7/mod.rs @@ -532,6 +532,7 @@ pub unsafe fn init(config: Config) { ahb1: core_clocks.hclk, ahb2: core_clocks.hclk, ahb3: core_clocks.hclk, + ahb4: core_clocks.hclk, apb1: core_clocks.pclk1, apb2: core_clocks.pclk2, apb4: core_clocks.pclk4, diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index c7d1ae61..b7b692f1 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -26,6 +26,9 @@ pub struct Clocks { #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb55, rcc_wl5x))] pub ahb3: Hertz, + #[cfg(any(rcc_h7))] + pub ahb4: Hertz, + #[cfg(any(rcc_h7))] pub apb4: Hertz, } diff --git a/stm32-data b/stm32-data index a2167373..3d0489cd 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit a2167373ee8fd0e75dce003bfdbadda8b32ff77c +Subproject commit 3d0489cd17a4ea1d8da289bd5854346fdfbf5f61 From a24a7e9fece1768e359621780c0dfdf56ee46805 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Fri, 9 Jul 2021 11:07:53 -0400 Subject: [PATCH 15/32] Allow some unused lints given that H7 is still in flight with its multitude of DMA. --- embassy-stm32/src/bdma/v1.rs | 47 +++++++++++++++++++++++++++++++-- embassy-stm32/src/dmamux/mod.rs | 5 ++-- stm32-data | 2 +- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs index 4488e2e9..9a7cfae1 100644 --- a/embassy-stm32/src/bdma/v1.rs +++ b/embassy-stm32/src/bdma/v1.rs @@ -10,7 +10,6 @@ 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; @@ -41,6 +40,9 @@ pub(crate) async unsafe fn transfer_p2m( state_number: usize, src: *const u8, dst: &mut [u8], + #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, + #[cfg(dmamux)] dmamux_ch_num: u8, + #[cfg(dmamux)] request: u8, ) { // ndtr is max 16 bits. assert!(dst.len() <= 0xFFFF); @@ -59,7 +61,7 @@ pub(crate) async unsafe fn transfer_p2m( }); #[cfg(dmamux)] - crate::dmamux::configure_channel(1, 2); + crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); regs.par().write_value(src as u32); regs.mar().write_value(dst.as_mut_ptr() as u32); @@ -288,6 +290,7 @@ macro_rules! impl_dma_channel { } } + #[cfg(not(dmamux))] impl ReadDma for crate::peripherals::$channel_peri where T: 'static, @@ -309,6 +312,46 @@ macro_rules! impl_dma_channel { unsafe { transfer_p2m(regs, state_num, src, buf) } } } + + #[cfg(dmamux)] + impl ReadDma for crate::peripherals::$channel_peri + where + Self: crate::dmamux::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, + { + 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.dmamux_ch_num(); + let request = PeripheralChannel::::request(self); + unsafe { + transfer_p2m( + regs, + state_num, + src, + buf, + dmamux_regs, + dmamux_ch_num, + request, + ) + } + } + } }; } diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index 79dea296..93653b51 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -22,8 +22,6 @@ use core::future::Future; use crate::dma_traits::{ReadDma, WriteDma}; -pub(crate) fn configure_channel(ch_num: u8, request_num: u8) {} - /* #[allow(unused)] pub(crate) async unsafe fn transfer_m2p( @@ -143,6 +141,7 @@ pub trait PeripheralChannel: sealed::Channel {} pub struct P2M; pub struct M2P; +#[allow(unused)] macro_rules! impl_dma_channel { ($channel_peri:ident, $dmamux_peri:ident, $channel_num:expr, $dma_peri: ident, $dma_num:expr) => { impl Channel for peripherals::$channel_peri {} @@ -189,6 +188,7 @@ peripherals! { }; } +#[allow(unused)] macro_rules! impl_usart_dma_requests { ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { dma_requests! { @@ -239,6 +239,7 @@ macro_rules! impl_usart_dma_requests { }; } +#[allow(unused)] #[cfg(usart)] use crate::usart; diff --git a/stm32-data b/stm32-data index 3d0489cd..df872630 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 3d0489cd17a4ea1d8da289bd5854346fdfbf5f61 +Subproject commit df8726306bacfad53ebcf760d3a4ca9cb0138dc9 From 97ad434d387b1f893aa3091a76d3b350d0dddf2e Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 10:32:57 -0400 Subject: [PATCH 16/32] Twizzle our DMA vs BDMA channels. --- embassy-stm32/src/bdma/v1.rs | 13 ++++++------- embassy-stm32/src/dmamux/mod.rs | 15 +++++++++++---- stm32-metapac-gen/src/lib.rs | 28 +++++++++++++++++++++------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs index 9a7cfae1..597cb013 100644 --- a/embassy-stm32/src/bdma/v1.rs +++ b/embassy-stm32/src/bdma/v1.rs @@ -236,7 +236,6 @@ 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; @@ -358,7 +357,7 @@ macro_rules! impl_dma_channel { pac::peripherals! { (bdma, DMA1) => { impl_dma!(DMA1, 0); - pac::dma_channels! { + pac::bdma_channels! { ($channel_peri:ident, DMA1, $channel_num:expr) => { impl_dma_channel!($channel_peri, DMA1, 0, $channel_num); }; @@ -366,7 +365,7 @@ pac::peripherals! { }; (bdma, DMA2) => { impl_dma!(DMA2, 1); - pac::dma_channels! { + pac::bdma_channels! { ($channel_peri:ident, DMA2, $channel_num:expr) => { impl_dma_channel!($channel_peri, DMA2, 1, $channel_num); }; @@ -375,8 +374,8 @@ pac::peripherals! { // Because H7cm changes the naming (bdma, BDMA) => { impl_dma!(BDMA, 0); - pac::dma_channels! { - ($channel_peri:ident, DMA1, $channel_num:expr) => { + pac::bdma_channels! { + ($channel_peri:ident, BDMA, $channel_num:expr) => { impl_dma_channel!($channel_peri, BDMA, 0, $channel_num); }; } @@ -421,7 +420,7 @@ pac::peripheral_dma_channels! { #[cfg(dmamux)] pac::peripherals! { (usart, $peri:ident) => { - pac::dma_channels! { + pac::bdma_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 { } @@ -429,7 +428,7 @@ pac::peripherals! { } }; (uart, $peri:ident) => { - pac::dma_channels! { + pac::bdma_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/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index 93653b51..4ef04081 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -11,7 +11,7 @@ use crate::interrupt; use crate::pac::bdma::{regs, vals}; use crate::pac; -use crate::pac::dma_channels; +use crate::pac::bdma_channels; use crate::pac::dma_requests; use crate::pac::interrupts; use crate::pac::peripheral_count; @@ -170,19 +170,26 @@ macro_rules! impl_dmamux { peripherals! { (bdma, DMA1) => { - dma_channels! { + bdma_channels! { ($channel_peri:ident, DMA1, $channel_num:expr) => { impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA1, 0); }; } }; (bdma, DMA2) => { - dma_channels! { + bdma_channels! { ($channel_peri:ident, DMA2, $channel_num:expr) => { impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA2, 1); }; } }; + (bdma, BDMA) => { + bdma_channels! { + ($channel_peri:ident, BDMA, $channel_num:expr) => { + impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA2, 1); + }; + } + }; (dmamux, DMAMUX1) => { impl_dmamux!(DMAMUX1); }; @@ -243,7 +250,7 @@ macro_rules! impl_usart_dma_requests { #[cfg(usart)] use crate::usart; -dma_channels! { +bdma_channels! { ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { impl_usart_dma_requests!($channel_peri, $dma_peri, $channel_num); }; diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 3f6a03fc..640d746e 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -252,6 +252,7 @@ pub fn gen(options: Options) { let mut peripheral_pins_table: Vec> = Vec::new(); let mut peripheral_rcc_table: Vec> = Vec::new(); let mut dma_channels_table: Vec> = Vec::new(); + let mut bdma_channels_table: Vec> = Vec::new(); let mut dma_requests_table: Vec> = Vec::new(); let mut peripheral_dma_channels_table: Vec> = Vec::new(); let mut peripheral_counts: HashMap = HashMap::new(); @@ -266,13 +267,7 @@ pub fn gen(options: Options) { let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; let gpio_stride = 0x400; - for (id, channel_info) in &core.dma_channels { - let mut row = Vec::new(); - row.push(id.clone()); - row.push(channel_info.dma.clone()); - row.push(channel_info.channel.to_string()); - dma_channels_table.push(row); - } + let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); @@ -449,6 +444,24 @@ pub fn gen(options: Options) { dev.peripherals.push(ir_peri); } + for (id, channel_info) in &core.dma_channels { + let mut row = Vec::new(); + let dma_peri = core.peripherals.get(&channel_info.dma); + row.push(id.clone()); + row.push(channel_info.dma.clone()); + row.push(channel_info.channel.to_string()); + if let Some(dma_peri) = dma_peri { + if let Some(ref block) = dma_peri.block { + let bi = BlockInfo::parse(block); + if bi.module == "bdma" { + bdma_channels_table.push(row); + } else { + dma_channels_table.push(row); + } + } + } + } + for (name, &num) in &core.interrupts { dev.interrupts.push(ir::Interrupt { name: name.clone(), @@ -495,6 +508,7 @@ pub fn gen(options: Options) { ); make_table(&mut extra, "peripheral_rcc", &peripheral_rcc_table); make_table(&mut extra, "dma_channels", &dma_channels_table); + make_table(&mut extra, "bdma_channels", &bdma_channels_table); make_table(&mut extra, "dma_requests", &dma_requests_table); make_peripheral_counts(&mut extra, &peripheral_counts); From 509c7f6835875ef7029ca644fb09366f530615ae Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 10:45:57 -0400 Subject: [PATCH 17/32] Update stm32-data. --- stm32-data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stm32-data b/stm32-data index df872630..f5eb7fbb 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit df8726306bacfad53ebcf760d3a4ca9cb0138dc9 +Subproject commit f5eb7fbb53e46f7b2995d5f4f0b295a68476f1a3 From ff1cb9ac74644e652dd8b5edd378eaec5cc27557 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 10:55:23 -0400 Subject: [PATCH 18/32] Remove warnings. --- embassy-stm32/src/dmamux/mod.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index 4ef04081..ebb1748d 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -1,27 +1,11 @@ #![macro_use] -use core::task::Poll; - -use atomic_polyfill::{AtomicU8, Ordering}; -use embassy::interrupt::{Interrupt, InterruptExt}; -use embassy::util::AtomicWaker; -use futures::future::poll_fn; - -use crate::interrupt; - -use crate::pac::bdma::{regs, vals}; use crate::pac; use crate::pac::bdma_channels; use crate::pac::dma_requests; -use crate::pac::interrupts; -use crate::pac::peripheral_count; use crate::pac::peripherals; use crate::peripherals; -use core::future::Future; - -use crate::dma_traits::{ReadDma, WriteDma}; - /* #[allow(unused)] pub(crate) async unsafe fn transfer_m2p( From 45964c658c2abd4bf063f386fed815b91dc49a1f Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 11:41:46 -0400 Subject: [PATCH 19/32] Generalize RCC enabling for BDMA peris. --- embassy-stm32/src/bdma/v1.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs index 597cb013..e5b0b18b 100644 --- a/embassy-stm32/src/bdma/v1.rs +++ b/embassy-stm32/src/bdma/v1.rs @@ -164,6 +164,8 @@ unsafe fn on_irq() { } } +use crate::rcc::sealed::RccPeripheral; + /// safety: must be called only once pub(crate) unsafe fn init() { pac::interrupts! { @@ -172,11 +174,8 @@ pub(crate) unsafe fn init() { }; } pac::peripherals! { - (bdma, DMA1) => { - //critical_section::with(|_| { - //pac::RCC.ahbenr().modify(|w| w.set_dmaen(true)); - //}); - crate::peripherals::DMA1::enable(); + (bdma, $peri:ident) => { + crate::peripherals::$peri::enable(); }; } } From a9b2ed52ee34cbd5b94ab9fabdbe1af3ba27fd7b Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 13:34:47 -0400 Subject: [PATCH 20/32] Remove deadcode from dmamux. Smoosh bdma down to a single version. --- embassy-stm32/src/bdma/mod.rs | 439 +++++++++++++++++++++++++++++++- embassy-stm32/src/bdma/v1.rs | 437 ------------------------------- embassy-stm32/src/bdma/v2.rs | 1 - embassy-stm32/src/dmamux/mod.rs | 80 +----- 4 files changed, 436 insertions(+), 521 deletions(-) delete mode 100644 embassy-stm32/src/bdma/v1.rs delete mode 100644 embassy-stm32/src/bdma/v2.rs diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index ae7e9d23..523dc254 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -1,8 +1,439 @@ #![macro_use] -#[cfg_attr(bdma_v1, path = "v1.rs")] -#[cfg_attr(bdma_v2, path = "v2.rs")] -mod _version; +use core::future::Future; +use core::task::Poll; + +use atomic_polyfill::{AtomicU8, Ordering}; +use embassy::interrupt::{Interrupt, InterruptExt}; +use embassy::util::{AtomicWaker, OnDrop}; +use futures::future::poll_fn; + +use crate::dma_traits::{ReadDma, WriteDma}; +use crate::interrupt; +use crate::pac; +use crate::pac::bdma::vals; + +const CH_COUNT: usize = pac::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 use _version::*; +pub(crate) async unsafe fn transfer_p2m( + regs: pac::bdma::Ch, + state_number: usize, + src: *const u8, + dst: &mut [u8], + #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, + #[cfg(dmamux)] dmamux_ch_num: u8, + #[cfg(dmamux)] request: u8, +) { + // ndtr is max 16 bits. + assert!(dst.len() <= 0xFFFF); + + // Reset status + // Generate a DMB here to flush the store buffer (M7) before enabling the DMA + STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); + + let on_drop = OnDrop::new(|| unsafe { + regs.cr().modify(|w| { + w.set_tcie(false); + w.set_teie(false); + w.set_en(false); + }); + while regs.cr().read().en() {} + }); + + #[cfg(dmamux)] + crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); + + 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)); + regs.cr().write(|w| { + w.set_psize(vals::Size::BITS8); + w.set_msize(vals::Size::BITS8); + w.set_minc(vals::Inc::ENABLED); + w.set_teie(true); + w.set_tcie(true); + w.set_en(true); + }); + + let res = poll_fn(|cx| { + STATE.ch_wakers[state_number].register(cx.waker()); + match STATE.ch_status[state_number].load(Ordering::Acquire) { + CH_STATUS_NONE => Poll::Pending, + x => Poll::Ready(x), + } + }) + .await; + + // TODO handle error + assert!(res == CH_STATUS_COMPLETED); +} + +#[allow(unused)] +pub(crate) async unsafe fn transfer_m2p( + regs: pac::bdma::Ch, + state_number: usize, + src: &[u8], + dst: *mut u8, + #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, + #[cfg(dmamux)] dmamux_ch_num: u8, + #[cfg(dmamux)] request: u8, +) { + // ndtr is max 16 bits. + assert!(src.len() <= 0xFFFF); + + // Reset status + // Generate a DMB here to flush the store buffer (M7) before enabling the DMA + STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); + + let on_drop = OnDrop::new(|| unsafe { + regs.cr().modify(|w| { + w.set_tcie(false); + w.set_teie(false); + w.set_en(false); + }); + 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)); + regs.cr().write(|w| { + w.set_psize(vals::Size::BITS8); + w.set_msize(vals::Size::BITS8); + w.set_minc(vals::Inc::ENABLED); + w.set_dir(vals::Dir::FROMMEMORY); + w.set_teie(true); + w.set_tcie(true); + w.set_en(true); + }); + + let res = poll_fn(|cx| { + STATE.ch_wakers[state_number].register(cx.waker()); + match STATE.ch_status[state_number].load(Ordering::Acquire) { + CH_STATUS_NONE => Poll::Pending, + x => Poll::Ready(x), + } + }) + .await; + + // TODO handle error + assert!(res == CH_STATUS_COMPLETED); +} + +unsafe fn on_irq() { + pac::peripherals! { + (bdma, $dma:ident) => { + let isr = pac::$dma.isr().read(); + pac::$dma.ifcr().write_value(isr); + let dman = ::num() as usize; + + for chn in 0..7 { + let n = dman * 8 + chn; + if isr.teif(chn) { + STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed); + STATE.ch_wakers[n].wake(); + } else if isr.tcif(chn) { + STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed); + STATE.ch_wakers[n].wake(); + } + } + }; + } +} + +use crate::rcc::sealed::RccPeripheral; + +/// safety: must be called only once +pub(crate) unsafe fn init() { + pac::interrupts! { + (DMA, $irq:ident) => { + crate::interrupt::$irq::steal().enable(); + }; + } + pac::peripherals! { + (bdma, $peri:ident) => { + crate::peripherals::$peri::enable(); + }; + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait Dma { + fn num() -> u8; + } + + pub trait Channel { + fn dma_regs() -> pac::bdma::Dma; + + fn state_num(&self) -> usize; + + fn ch_num(&self) -> u8; + + fn regs(&self) -> pac::bdma::Ch { + Self::dma_regs().ch(self.ch_num() as usize) + } + } +} + +pub trait Dma: sealed::Dma + Sized {} +pub trait Channel: sealed::Channel + Sized {} + +macro_rules! impl_dma { + ($peri:ident, $num:expr) => { + impl Dma for crate::peripherals::$peri {} + impl sealed::Dma for crate::peripherals::$peri { + fn num() -> u8 { + $num + } + } + }; +} + +macro_rules! impl_dma_channel { + ($channel_peri:ident, $dma_peri:ident, $dma_num:expr, $ch_num:expr) => { + impl Channel for crate::peripherals::$channel_peri {} + impl sealed::Channel for crate::peripherals::$channel_peri { + #[inline] + fn dma_regs() -> pac::bdma::Dma { + crate::pac::$dma_peri + } + + fn state_num(&self) -> usize { + ($dma_num * 8) + $ch_num + } + + fn ch_num(&self) -> u8 { + $ch_num + } + } + + #[cfg(not(dmamux))] + impl WriteDma for crate::peripherals::$channel_peri + where + 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(); + + 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.dmamux_ch_num(); + let request = PeripheralChannel::::request(self); + unsafe { + transfer_m2p( + regs, + state_num, + buf, + dst, + dmamux_regs, + dmamux_ch_num, + request, + ) + } + } + } + + #[cfg(not(dmamux))] + impl ReadDma for crate::peripherals::$channel_peri + where + 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, + { + use sealed::Channel as _Channel; + + let state_num = self.state_num(); + let regs = self.regs(); + unsafe { transfer_p2m(regs, state_num, src, buf) } + } + } + + #[cfg(dmamux)] + impl ReadDma for crate::peripherals::$channel_peri + where + Self: crate::dmamux::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, + { + 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.dmamux_ch_num(); + let request = PeripheralChannel::::request(self); + unsafe { + transfer_p2m( + regs, + state_num, + src, + buf, + dmamux_regs, + dmamux_ch_num, + request, + ) + } + } + } + }; +} + +pac::peripherals! { + (bdma, DMA1) => { + impl_dma!(DMA1, 0); + pac::bdma_channels! { + ($channel_peri:ident, DMA1, $channel_num:expr) => { + impl_dma_channel!($channel_peri, DMA1, 0, $channel_num); + }; + } + }; + (bdma, DMA2) => { + impl_dma!(DMA2, 1); + pac::bdma_channels! { + ($channel_peri:ident, DMA2, $channel_num:expr) => { + impl_dma_channel!($channel_peri, DMA2, 1, $channel_num); + }; + } + }; + // Because H7cm changes the naming + (bdma, BDMA) => { + impl_dma!(BDMA, 0); + pac::bdma_channels! { + ($channel_peri:ident, BDMA, $channel_num:expr) => { + impl_dma_channel!($channel_peri, BDMA, 0, $channel_num); + }; + } + }; +} + +pac::interrupts! { + (DMA, $irq:ident) => { + #[crate::interrupt] + unsafe fn $irq () { + on_irq() + } + }; +} + +#[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 { } + impl usart::sealed::RxDma for crate::peripherals::$channel_peri { } + }; + + ($peri:ident, usart, $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 { } + }; + + ($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::bdma_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::bdma_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/bdma/v1.rs b/embassy-stm32/src/bdma/v1.rs deleted file mode 100644 index e5b0b18b..00000000 --- a/embassy-stm32/src/bdma/v1.rs +++ /dev/null @@ -1,437 +0,0 @@ -use core::future::Future; -use core::task::Poll; - -use atomic_polyfill::{AtomicU8, Ordering}; -use embassy::interrupt::{Interrupt, InterruptExt}; -use embassy::util::{AtomicWaker, OnDrop}; -use futures::future::poll_fn; - -use crate::dma_traits::{ReadDma, WriteDma}; -use crate::interrupt; -use crate::pac; -use crate::pac::bdma::vals; - -const CH_COUNT: usize = pac::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( - regs: pac::bdma::Ch, - state_number: usize, - src: *const u8, - dst: &mut [u8], - #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, - #[cfg(dmamux)] dmamux_ch_num: u8, - #[cfg(dmamux)] request: u8, -) { - // ndtr is max 16 bits. - assert!(dst.len() <= 0xFFFF); - - // Reset status - // Generate a DMB here to flush the store buffer (M7) before enabling the DMA - STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); - - let on_drop = OnDrop::new(|| unsafe { - regs.cr().modify(|w| { - w.set_tcie(false); - w.set_teie(false); - w.set_en(false); - }); - while regs.cr().read().en() {} - }); - - #[cfg(dmamux)] - crate::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); - - 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)); - regs.cr().write(|w| { - w.set_psize(vals::Size::BITS8); - w.set_msize(vals::Size::BITS8); - w.set_minc(vals::Inc::ENABLED); - w.set_teie(true); - w.set_tcie(true); - w.set_en(true); - }); - - let res = poll_fn(|cx| { - STATE.ch_wakers[state_number].register(cx.waker()); - match STATE.ch_status[state_number].load(Ordering::Acquire) { - CH_STATUS_NONE => Poll::Pending, - x => Poll::Ready(x), - } - }) - .await; - - // TODO handle error - assert!(res == CH_STATUS_COMPLETED); -} - -#[allow(unused)] -pub(crate) async unsafe fn transfer_m2p( - regs: pac::bdma::Ch, - state_number: usize, - src: &[u8], - dst: *mut u8, - #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, - #[cfg(dmamux)] dmamux_ch_num: u8, - #[cfg(dmamux)] request: u8, -) { - // ndtr is max 16 bits. - assert!(src.len() <= 0xFFFF); - - // Reset status - // Generate a DMB here to flush the store buffer (M7) before enabling the DMA - STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); - - let on_drop = OnDrop::new(|| unsafe { - regs.cr().modify(|w| { - w.set_tcie(false); - w.set_teie(false); - w.set_en(false); - }); - 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)); - regs.cr().write(|w| { - w.set_psize(vals::Size::BITS8); - w.set_msize(vals::Size::BITS8); - w.set_minc(vals::Inc::ENABLED); - w.set_dir(vals::Dir::FROMMEMORY); - w.set_teie(true); - w.set_tcie(true); - w.set_en(true); - }); - - let res = poll_fn(|cx| { - STATE.ch_wakers[state_number].register(cx.waker()); - match STATE.ch_status[state_number].load(Ordering::Acquire) { - CH_STATUS_NONE => Poll::Pending, - x => Poll::Ready(x), - } - }) - .await; - - // TODO handle error - assert!(res == CH_STATUS_COMPLETED); -} - -unsafe fn on_irq() { - pac::peripherals! { - (bdma, $dma:ident) => { - let isr = pac::$dma.isr().read(); - pac::$dma.ifcr().write_value(isr); - let dman = ::num() as usize; - - for chn in 0..7 { - let n = dman * 8 + chn; - if isr.teif(chn) { - STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed); - STATE.ch_wakers[n].wake(); - } else if isr.tcif(chn) { - STATE.ch_status[n].store(CH_STATUS_COMPLETED, Ordering::Relaxed); - STATE.ch_wakers[n].wake(); - } - } - }; - } -} - -use crate::rcc::sealed::RccPeripheral; - -/// safety: must be called only once -pub(crate) unsafe fn init() { - pac::interrupts! { - (DMA, $irq:ident) => { - crate::interrupt::$irq::steal().enable(); - }; - } - pac::peripherals! { - (bdma, $peri:ident) => { - crate::peripherals::$peri::enable(); - }; - } -} - -pub(crate) mod sealed { - use super::*; - - pub trait Dma { - fn num() -> u8; - } - - pub trait Channel { - fn dma_regs() -> pac::bdma::Dma; - - fn state_num(&self) -> usize; - - fn ch_num(&self) -> u8; - - fn regs(&self) -> pac::bdma::Ch { - Self::dma_regs().ch(self.ch_num() as usize) - } - } -} - -pub trait Dma: sealed::Dma + Sized {} -pub trait Channel: sealed::Channel + Sized {} - -macro_rules! impl_dma { - ($peri:ident, $num:expr) => { - impl Dma for crate::peripherals::$peri {} - impl sealed::Dma for crate::peripherals::$peri { - fn num() -> u8 { - $num - } - } - }; -} - -macro_rules! impl_dma_channel { - ($channel_peri:ident, $dma_peri:ident, $dma_num:expr, $ch_num:expr) => { - impl Channel for crate::peripherals::$channel_peri {} - impl sealed::Channel for crate::peripherals::$channel_peri { - #[inline] - fn dma_regs() -> pac::bdma::Dma { - crate::pac::$dma_peri - } - - fn state_num(&self) -> usize { - ($dma_num * 8) + $ch_num - } - - fn ch_num(&self) -> u8 { - $ch_num - } - } - - #[cfg(not(dmamux))] - impl WriteDma for crate::peripherals::$channel_peri - where - 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(); - - 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.dmamux_ch_num(); - let request = PeripheralChannel::::request(self); - unsafe { - transfer_m2p( - regs, - state_num, - buf, - dst, - dmamux_regs, - dmamux_ch_num, - request, - ) - } - } - } - - #[cfg(not(dmamux))] - impl ReadDma for crate::peripherals::$channel_peri - where - 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, - { - use sealed::Channel as _Channel; - - let state_num = self.state_num(); - let regs = self.regs(); - unsafe { transfer_p2m(regs, state_num, src, buf) } - } - } - - #[cfg(dmamux)] - impl ReadDma for crate::peripherals::$channel_peri - where - Self: crate::dmamux::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, - { - 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.dmamux_ch_num(); - let request = PeripheralChannel::::request(self); - unsafe { - transfer_p2m( - regs, - state_num, - src, - buf, - dmamux_regs, - dmamux_ch_num, - request, - ) - } - } - } - }; -} - -pac::peripherals! { - (bdma, DMA1) => { - impl_dma!(DMA1, 0); - pac::bdma_channels! { - ($channel_peri:ident, DMA1, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMA1, 0, $channel_num); - }; - } - }; - (bdma, DMA2) => { - impl_dma!(DMA2, 1); - pac::bdma_channels! { - ($channel_peri:ident, DMA2, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMA2, 1, $channel_num); - }; - } - }; - // Because H7cm changes the naming - (bdma, BDMA) => { - impl_dma!(BDMA, 0); - pac::bdma_channels! { - ($channel_peri:ident, BDMA, $channel_num:expr) => { - impl_dma_channel!($channel_peri, BDMA, 0, $channel_num); - }; - } - }; -} - -pac::interrupts! { - (DMA, $irq:ident) => { - #[crate::interrupt] - unsafe fn $irq () { - on_irq() - } - }; -} - -#[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 { } - impl usart::sealed::RxDma for crate::peripherals::$channel_peri { } - }; - - ($peri:ident, usart, $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 { } - }; - - ($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::bdma_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::bdma_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/bdma/v2.rs b/embassy-stm32/src/bdma/v2.rs deleted file mode 100644 index 956b83cd..00000000 --- a/embassy-stm32/src/bdma/v2.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) unsafe fn init() {} diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index ebb1748d..0f3fb9a8 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -6,82 +6,6 @@ use crate::pac::dma_requests; use crate::pac::peripherals; use crate::peripherals; -/* -#[allow(unused)] -pub(crate) async unsafe fn transfer_m2p( - ch: &mut impl Channel, - ch_func: u8, - src: &[u8], - dst: *mut u8, -) { - defmt::info!( - "m2p {} func {} {}-{}", - src.len(), - ch_func, - ch.num(), - ch.dma_ch_num() - ); - let n = ch.num(); - - STATE.ch_status[n].store(CH_STATUS_NONE, Ordering::Release); - - let ch_regs = ch.regs(); - let dmamux_regs = ch.dmamux_regs(); - let ch_mux_regs = dmamux_regs.ccr(ch.dmamux_ch_num() as _); - - ch_mux_regs.write(|reg| { - // one request? - reg.set_nbreq(0); - reg.set_dmareq_id(ch_func); - }); - - ch_mux_regs.modify(|reg| { - reg.set_ege(true); - //reg.set_se(true); - //reg.set_soie(true); - }); - - ch_regs.par().write_value(dst as _); - ch_regs.mar().write_value(src.as_ptr() as _); - ch_regs.ndtr().write_value(regs::Ndtr(src.len() as _)); - - ch_regs.cr().write(|reg| { - reg.set_dir(vals::Dir::FROMMEMORY); - reg.set_msize(vals::Size::BITS8); - reg.set_minc(vals::Inc::ENABLED); - reg.set_pinc(vals::Inc::DISABLED); - reg.set_teie(true); - reg.set_tcie(true); - reg.set_en(true); - }); - - let res = poll_fn(|cx| { - defmt::info!("poll"); - STATE.ch_wakers[n].register(cx.waker()); - match STATE.ch_status[n].load(Ordering::Acquire) { - CH_STATUS_NONE => Poll::Pending, - x => Poll::Ready(x), - } - }) - .await; - - defmt::info!("cr {:b}", ch_regs.cr().read().0); - - ch_regs.cr().modify(|reg| { - reg.set_en(false); - }); - - ch_mux_regs.modify(|reg| { - reg.set_ege(false); - //reg.set_se(true); - //reg.set_soie(true); - }); - - // TODO handle error - assert!(res == CH_STATUS_COMPLETED); -} - */ - pub(crate) unsafe fn configure_dmamux( dmamux_regs: pac::dmamux::Dmamux, dmamux_ch_num: u8, @@ -89,15 +13,12 @@ pub(crate) unsafe fn configure_dmamux( ) { 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); }); } @@ -236,6 +157,7 @@ use crate::usart; bdma_channels! { ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + #[cfg(usart)] impl_usart_dma_requests!($channel_peri, $dma_peri, $channel_num); }; } From c28bc5a8da4f4f197468c81a1149944f74fc57a2 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 13:48:12 -0400 Subject: [PATCH 21/32] Adapt for DMAEN for DMA1 if DMA1EN is not found (for all peripherals FOO1) for EN/RST rcc table. --- stm32-metapac-gen/src/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 640d746e..4e0aaf01 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -390,8 +390,13 @@ pub fn gen(options: Options) { if let Some(clock_prefix) = clock_prefix { // Workaround for clock registers being split on some chip families. Assume fields are // named after peripheral and look for first field matching and use that register. - let en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); - let rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); + let mut en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); + let mut rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); + + if en.is_none() && rst.is_none() && name.ends_with("1") { + en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name.strip_suffix("1").unwrap())); + rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name.strip_suffix("1").unwrap())); + } match (en, rst) { (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { From d31e30f382671fecae393f848f576ab45208bdf9 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 14:02:37 -0400 Subject: [PATCH 22/32] Undo special-casing FOO1 -> FOO in RCC searching. --- stm32-data | 2 +- stm32-metapac-gen/src/lib.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/stm32-data b/stm32-data index f5eb7fbb..5c3d2df9 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit f5eb7fbb53e46f7b2995d5f4f0b295a68476f1a3 +Subproject commit 5c3d2df911c8530d4584c731a5de99951858fccd diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 4e0aaf01..570a225c 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -393,11 +393,6 @@ pub fn gen(options: Options) { let mut en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); let mut rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); - if en.is_none() && rst.is_none() && name.ends_with("1") { - en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name.strip_suffix("1").unwrap())); - rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name.strip_suffix("1").unwrap())); - } - match (en, rst) { (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { let clock = if clock_prefix.is_empty() { From 06e899b14cba8e1071adbe9e17dec0542f677853 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 14:11:18 -0400 Subject: [PATCH 23/32] Adjust to DMA1EN in the rcc for l0. --- embassy-stm32/src/rcc/l0/mod.rs | 2 +- stm32-data | 2 +- stm32-metapac-gen/src/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rcc/l0/mod.rs b/embassy-stm32/src/rcc/l0/mod.rs index 0b11e708..6107d5f5 100644 --- a/embassy-stm32/src/rcc/l0/mod.rs +++ b/embassy-stm32/src/rcc/l0/mod.rs @@ -170,7 +170,7 @@ impl<'d> Rcc<'d> { pub fn enable_debug_wfe(&mut self, _dbg: &mut peripherals::DBGMCU, enable_dma: bool) { // NOTE(unsafe) We have exclusive access to the RCC and DBGMCU unsafe { - pac::RCC.ahbenr().modify(|w| w.set_dmaen(enable_dma)); + pac::RCC.ahbenr().modify(|w| w.set_dma1en(enable_dma)); pac::DBGMCU.cr().modify(|w| { w.set_dbg_sleep(true); diff --git a/stm32-data b/stm32-data index 5c3d2df9..9ff09761 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 5c3d2df911c8530d4584c731a5de99951858fccd +Subproject commit 9ff09761f32da472319756c1c2cd814fda10b571 diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 570a225c..640d746e 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -390,8 +390,8 @@ pub fn gen(options: Options) { if let Some(clock_prefix) = clock_prefix { // Workaround for clock registers being split on some chip families. Assume fields are // named after peripheral and look for first field matching and use that register. - let mut en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); - let mut rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); + let en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); + let rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); match (en, rst) { (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { From 0befa103676693ebbb52a5d38a0b3bb5e4d42f71 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 14:23:00 -0400 Subject: [PATCH 24/32] Trivial to force CI to do it's thing. --- embassy-stm32/src/bdma/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index 523dc254..b4da7928 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -428,6 +428,7 @@ pac::peripherals! { }; } }; + (uart, $peri:ident) => { pac::bdma_channels! { ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { From 6534b63e01b1f7d16f62743f007a2e9c43f9ec56 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 14:53:19 -0400 Subject: [PATCH 25/32] Simplify some macros around dmamux peripheral channels. --- embassy-stm32/src/dmamux/mod.rs | 51 ++++++++++++--------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index 0f3fb9a8..f6625146 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -100,54 +100,41 @@ peripherals! { }; } +#[allow(unused)] +macro_rules! impl_peripheral_channel { + ($channel_peri:ident, $direction:ident, $peri:ident, $request:expr) => { + impl sealed::PeripheralChannel + for peripherals::$channel_peri + { + fn request(&self) -> u8 { + $request + } + } + + impl PeripheralChannel for peripherals::$channel_peri {} + }; +} + #[allow(unused)] macro_rules! impl_usart_dma_requests { ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { dma_requests! { - // TODO: DRY this up. (usart, $peri:ident, RX, $request:expr) => { - impl sealed::PeripheralChannel for peripherals::$channel_peri { - fn request(&self) -> u8 { - $request - } - } - - impl PeripheralChannel for peripherals::$channel_peri { } - + impl_peripheral_channel($channel_peri, P2M, $peri, $request); }; (usart, $peri:ident, TX, $request:expr) => { - impl sealed::PeripheralChannel for peripherals::$channel_peri { - fn request(&self) -> u8 { - $request - } - } - - impl PeripheralChannel for peripherals::$channel_peri { } - + impl_peripheral_channel($channel_peri, M2P, $peri, $request); }; (uart, $peri:ident, TX, $request:expr) => { - impl sealed::PeripheralChannel for peripherals::$channel_peri { - fn request(&self) -> u8 { - $request - } - } - - impl PeripheralChannel for peripherals::$channel_peri { } + impl_peripheral_channel($channel_peri, P2M, $peri, $request); }; (uart, $peri:ident, RX, $request:expr) => { - impl sealed::PeripheralChannel for peripherals::$channel_peri { - fn request(&self) -> u8 { - $request - } - } - - impl PeripheralChannel for peripherals::$channel_peri { } + impl_peripheral_channel($channel_peri, M2P, $peri, $request); }; } - }; } From b0b61d99e69980d8c30923148d32c3f7aa50fcc0 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 15:34:34 -0400 Subject: [PATCH 26/32] Macros do indeed require a ! to invoke. --- embassy-stm32/src/dmamux/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index f6625146..564b8236 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -120,19 +120,19 @@ macro_rules! impl_usart_dma_requests { ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { dma_requests! { (usart, $peri:ident, RX, $request:expr) => { - impl_peripheral_channel($channel_peri, P2M, $peri, $request); + impl_peripheral_channel!($channel_peri, P2M, $peri, $request); }; (usart, $peri:ident, TX, $request:expr) => { - impl_peripheral_channel($channel_peri, M2P, $peri, $request); - }; - - (uart, $peri:ident, TX, $request:expr) => { - impl_peripheral_channel($channel_peri, P2M, $peri, $request); + impl_peripheral_channel!($channel_peri, M2P, $peri, $request); }; (uart, $peri:ident, RX, $request:expr) => { - impl_peripheral_channel($channel_peri, M2P, $peri, $request); + impl_peripheral_channel!($channel_peri, P2M, $peri, $request); + }; + + (uart, $peri:ident, TX, $request:expr) => { + impl_peripheral_channel!($channel_peri, M2P, $peri, $request); }; } }; From 2e10ab2e5c330d7b55f5d7f24379ccd48b6a8b1b Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 15:48:26 -0400 Subject: [PATCH 27/32] Let's count channels per DMA peripheral, shall we now? --- embassy-stm32/src/bdma/mod.rs | 2 +- stm32-metapac-gen/src/lib.rs | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index b4da7928..d62feb5b 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -152,7 +152,7 @@ unsafe fn on_irq() { pac::$dma.ifcr().write_value(isr); let dman = ::num() as usize; - for chn in 0..7 { + for chn in 0..crate::pac::dma_channels_count!($dma) { let n = dman * 8 + chn; if isr.teif(chn) { STATE.ch_status[n].store(CH_STATUS_ERROR, Ordering::Relaxed); diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 640d746e..e7e3382f 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -141,6 +141,21 @@ macro_rules! peripheral_count {{ write!(out, " }}\n").unwrap(); } +fn make_dma_channel_counts(out: &mut String, data: &HashMap) { + write!(out, + "#[macro_export] +macro_rules! dma_channels_count {{ + ").unwrap(); + for (name, count) in data { + write!(out, + "({}) => ({});\n", + name, count, + ).unwrap(); + } + write!(out, + " }}\n").unwrap(); +} + fn make_table(out: &mut String, name: &str, data: &Vec>) { write!( out, @@ -256,6 +271,7 @@ pub fn gen(options: Options) { let mut dma_requests_table: Vec> = Vec::new(); let mut peripheral_dma_channels_table: Vec> = Vec::new(); let mut peripheral_counts: HashMap = HashMap::new(); + let mut dma_channel_counts: HashMap = HashMap::new(); let dma_base = core .peripherals @@ -267,8 +283,6 @@ pub fn gen(options: Options) { let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; let gpio_stride = 0x400; - - let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); for (name, p) in &core.peripherals { @@ -460,6 +474,12 @@ pub fn gen(options: Options) { } } } + + let dma_peri_name = channel_info.dma.clone(); + dma_channel_counts.insert( + dma_peri_name.clone(), + dma_channel_counts.get(&dma_peri_name).map_or(1, |v| v + 1), + ); } for (name, &num) in &core.interrupts { @@ -511,6 +531,7 @@ pub fn gen(options: Options) { make_table(&mut extra, "bdma_channels", &bdma_channels_table); make_table(&mut extra, "dma_requests", &dma_requests_table); make_peripheral_counts(&mut extra, &peripheral_counts); + make_dma_channel_counts(&mut extra, &dma_channel_counts); for (module, version) in peripheral_versions { all_peripheral_versions.insert((module.clone(), version.clone())); From c39ac201ffad32a55d68dbe48de6185b91fc86af Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Mon, 12 Jul 2021 15:57:53 -0400 Subject: [PATCH 28/32] Update for stm32-data. --- stm32-data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stm32-data b/stm32-data index 9ff09761..bc74a980 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 9ff09761f32da472319756c1c2cd814fda10b571 +Subproject commit bc74a98017800aad50dd1448a24e3f54eaec8eb4 From 92247369e77bc55dd6247348a1f472cbe467d19f Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Tue, 13 Jul 2021 09:50:42 -0400 Subject: [PATCH 29/32] Remove some unused traits. Move some fns to associated consts. --- embassy-stm32/src/bdma/mod.rs | 28 +++++++---- embassy-stm32/src/dmamux/mod.rs | 86 ++++++++++++++------------------- stm32-metapac-gen/src/lib.rs | 5 ++ 3 files changed, 58 insertions(+), 61 deletions(-) diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index d62feb5b..d36361e4 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -13,7 +13,7 @@ use crate::interrupt; use crate::pac; use crate::pac::bdma::vals; -const CH_COUNT: usize = pac::peripheral_count!(DMA) * 8; +const CH_COUNT: usize = pac::peripheral_count!(bdma) * 8; const CH_STATUS_NONE: u8 = 0; const CH_STATUS_COMPLETED: u8 = 1; const CH_STATUS_ERROR: u8 = 2; @@ -271,11 +271,15 @@ macro_rules! impl_dma_channel { let state_num = self.state_num(); let regs = self.regs(); - use crate::dmamux::sealed::Channel as _MuxChannel; + use crate::dmamux::sealed::Channel as MuxChannel; use crate::dmamux::sealed::PeripheralChannel; - let dmamux_regs = self.dmamux_regs(); - let dmamux_ch_num = self.dmamux_ch_num(); - let request = PeripheralChannel::::request(self); + let dmamux_regs = ::DMAMUX_REGS; + let dmamux_ch_num = + ::DMAMUX_CH_NUM; + let request = >::REQUEST; unsafe { transfer_m2p( regs, @@ -316,7 +320,7 @@ macro_rules! impl_dma_channel { #[cfg(dmamux)] impl ReadDma for crate::peripherals::$channel_peri where - Self: crate::dmamux::sealed::PeripheralChannel, + Self: crate::dmamux::sealed::PeripheralChannel, T: 'static, { type ReadDmaFuture<'a> = impl Future; @@ -334,11 +338,15 @@ macro_rules! impl_dma_channel { let state_num = self.state_num(); let regs = self.regs(); - use crate::dmamux::sealed::Channel as _MuxChannel; + use crate::dmamux::sealed::Channel as MuxChannel; use crate::dmamux::sealed::PeripheralChannel; - let dmamux_regs = self.dmamux_regs(); - let dmamux_ch_num = self.dmamux_ch_num(); - let request = PeripheralChannel::::request(self); + let dmamux_regs = ::DMAMUX_REGS; + let dmamux_ch_num = + ::DMAMUX_CH_NUM; + let request = >::REQUEST; unsafe { transfer_p2m( regs, diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs index 564b8236..ecea0b29 100644 --- a/embassy-stm32/src/dmamux/mod.rs +++ b/embassy-stm32/src/dmamux/mod.rs @@ -25,79 +25,65 @@ pub(crate) unsafe fn configure_dmamux( pub(crate) mod sealed { use super::*; - pub trait DmaMux { - fn regs() -> pac::dmamux::Dmamux; - } - pub trait Channel { - fn dmamux_regs(&self) -> pac::dmamux::Dmamux; - fn dmamux_ch_num(&self) -> u8; + const DMAMUX_CH_NUM: u8; + const DMAMUX_REGS: pac::dmamux::Dmamux; } pub trait PeripheralChannel: Channel { - fn request(&self) -> u8; + const REQUEST: u8; } } -pub trait DmaMux: sealed::DmaMux {} pub trait Channel: sealed::Channel {} pub trait PeripheralChannel: sealed::Channel {} pub struct P2M; pub struct M2P; -#[allow(unused)] -macro_rules! impl_dma_channel { - ($channel_peri:ident, $dmamux_peri:ident, $channel_num:expr, $dma_peri: ident, $dma_num:expr) => { - impl Channel for peripherals::$channel_peri {} - impl sealed::Channel for peripherals::$channel_peri { - fn dmamux_regs(&self) -> pac::dmamux::Dmamux { - crate::pac::$dmamux_peri - } - - fn dmamux_ch_num(&self) -> u8 { - ($dma_num * 8) + $channel_num - } - } +macro_rules! dma_num { + (DMA1) => { + 0 + }; + (DMA2) => { + 1 + }; + (BDMA) => { + 0 }; } -macro_rules! impl_dmamux { - ($peri:ident) => { - impl sealed::DmaMux for peripherals::$peri { - fn regs() -> pac::dmamux::Dmamux { - pac::$peri - } +macro_rules! dmamux_peri { + (DMA1) => { + crate::pac::DMAMUX1 + }; + (DMA2) => { + crate::pac::DMAMUX1 + }; + (BDMA) => { + crate::pac::DMAMUX1 + }; +} + +#[allow(unused)] +macro_rules! impl_dma_channel { + ($channel_peri:ident, $channel_num:expr, $dma_peri: ident) => { + impl Channel for peripherals::$channel_peri {} + impl sealed::Channel for peripherals::$channel_peri { + const DMAMUX_CH_NUM: u8 = (dma_num!($dma_peri) * 8) + $channel_num; + const DMAMUX_REGS: pac::dmamux::Dmamux = dmamux_peri!($dma_peri); } - impl DmaMux for peripherals::$peri {} }; } peripherals! { - (bdma, DMA1) => { + (bdma, $peri:ident) => { bdma_channels! { - ($channel_peri:ident, DMA1, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA1, 0); + ($channel_peri:ident, $peri, $channel_num:expr) => { + impl_dma_channel!($channel_peri, $channel_num, $peri); }; } }; - (bdma, DMA2) => { - bdma_channels! { - ($channel_peri:ident, DMA2, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA2, 1); - }; - } - }; - (bdma, BDMA) => { - bdma_channels! { - ($channel_peri:ident, BDMA, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMAMUX1, $channel_num, DMA2, 1); - }; - } - }; - (dmamux, DMAMUX1) => { - impl_dmamux!(DMAMUX1); - }; } #[allow(unused)] @@ -106,9 +92,7 @@ macro_rules! impl_peripheral_channel { impl sealed::PeripheralChannel for peripherals::$channel_peri { - fn request(&self) -> u8 { - $request - } + const REQUEST: u8 = $request; } impl PeripheralChannel for peripherals::$channel_peri {} diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index e7e3382f..37254f6f 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -304,6 +304,11 @@ pub fn gen(options: Options) { if let Some(block) = &p.block { let bi = BlockInfo::parse(block); + peripheral_counts.insert( + bi.module.clone(), + peripheral_counts.get(&bi.module).map_or(1, |v| v + 1), + ); + for pin in &p.pins { let mut row = Vec::new(); row.push(name.clone()); From 8fbea38a5b3eada58943a3d3b346ca4944bfc896 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Tue, 13 Jul 2021 09:59:36 -0400 Subject: [PATCH 30/32] Simplify some of the bdma macros. Make more things associated consts. --- embassy-stm32/src/bdma/mod.rs | 67 +++++++++++++++-------------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index d36361e4..b94563e3 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -150,7 +150,7 @@ unsafe fn on_irq() { (bdma, $dma:ident) => { let isr = pac::$dma.isr().read(); pac::$dma.ifcr().write_value(isr); - let dman = ::num() as usize; + let dman = ::NUM as usize; for chn in 0..crate::pac::dma_channels_count!($dma) { let n = dman * 8 + chn; @@ -186,18 +186,18 @@ pub(crate) mod sealed { use super::*; pub trait Dma { - fn num() -> u8; + const NUM: u8; } pub trait Channel { + const CH_NUM: u8; + fn dma_regs() -> pac::bdma::Dma; fn state_num(&self) -> usize; - fn ch_num(&self) -> u8; - fn regs(&self) -> pac::bdma::Ch { - Self::dma_regs().ch(self.ch_num() as usize) + Self::dma_regs().ch(Self::CH_NUM as usize) } } } @@ -206,31 +206,27 @@ pub trait Dma: sealed::Dma + Sized {} pub trait Channel: sealed::Channel + Sized {} macro_rules! impl_dma { - ($peri:ident, $num:expr) => { + ($peri:ident) => { impl Dma for crate::peripherals::$peri {} impl sealed::Dma for crate::peripherals::$peri { - fn num() -> u8 { - $num - } + const NUM: u8 = dma_num!($peri); } }; } macro_rules! impl_dma_channel { - ($channel_peri:ident, $dma_peri:ident, $dma_num:expr, $ch_num:expr) => { + ($channel_peri:ident, $dma_peri:ident, $ch_num:expr) => { impl Channel for crate::peripherals::$channel_peri {} impl sealed::Channel for crate::peripherals::$channel_peri { + const CH_NUM: u8 = $ch_num; + #[inline] fn dma_regs() -> pac::bdma::Dma { crate::pac::$dma_peri } fn state_num(&self) -> usize { - ($dma_num * 8) + $ch_num - } - - fn ch_num(&self) -> u8 { - $ch_num + (dma_num!($dma_peri) * 8) + $ch_num } } @@ -363,31 +359,26 @@ macro_rules! impl_dma_channel { }; } +macro_rules! dma_num { + (DMA1) => { + 0 + }; + (DMA2) => { + 1 + }; + (BDMA) => { + 0 + }; +} pac::peripherals! { - (bdma, DMA1) => { - impl_dma!(DMA1, 0); - pac::bdma_channels! { - ($channel_peri:ident, DMA1, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMA1, 0, $channel_num); - }; - } + (bdma, $peri:ident) => { + impl_dma!($peri); }; - (bdma, DMA2) => { - impl_dma!(DMA2, 1); - pac::bdma_channels! { - ($channel_peri:ident, DMA2, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMA2, 1, $channel_num); - }; - } - }; - // Because H7cm changes the naming - (bdma, BDMA) => { - impl_dma!(BDMA, 0); - pac::bdma_channels! { - ($channel_peri:ident, BDMA, $channel_num:expr) => { - impl_dma_channel!($channel_peri, BDMA, 0, $channel_num); - }; - } +} + +pac::bdma_channels! { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl_dma_channel!($channel_peri, $dma_peri, $channel_num); }; } From 604a25ec5de6f8007f9ad61f315ea03d0d292829 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Tue, 13 Jul 2021 10:46:31 -0400 Subject: [PATCH 31/32] Reduce number of traits and impls. --- embassy-stm32/src/bdma/mod.rs | 46 ++++++++--------------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index b94563e3..8448185a 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -394,46 +394,20 @@ 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 { } - impl usart::sealed::RxDma for crate::peripherals::$channel_peri { } - }; - - ($peri:ident, usart, $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 { } - }; - - ($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::bdma_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 { } - }; - } + impl> usart::TxDma for T {} + impl> usart::sealed::TxDma for T {} + + impl> usart::RxDma for T {} + impl> usart::sealed::RxDma for T {} }; (uart, $peri:ident) => { - pac::bdma_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 { } - }; - } + impl> usart::TxDma for T {} + impl> usart::sealed::TxDma for T {} + + impl> usart::RxDma for T {} + impl> usart::sealed::RxDma for T {} }; } From 6e0e83cfd907c504c8d2ce05a7304b49565361ff Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Tue, 13 Jul 2021 10:56:35 -0400 Subject: [PATCH 32/32] More conversions to associated consts. --- embassy-stm32/src/bdma/mod.rs | 48 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs index 8448185a..39e8bec3 100644 --- a/embassy-stm32/src/bdma/mod.rs +++ b/embassy-stm32/src/bdma/mod.rs @@ -39,7 +39,7 @@ static STATE: State = State::new(); #[allow(unused)] pub(crate) async unsafe fn transfer_p2m( regs: pac::bdma::Ch, - state_number: usize, + state_number: u8, src: *const u8, dst: &mut [u8], #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, @@ -51,7 +51,7 @@ pub(crate) async unsafe fn transfer_p2m( // Reset status // Generate a DMB here to flush the store buffer (M7) before enabling the DMA - STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); + STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); let on_drop = OnDrop::new(|| unsafe { regs.cr().modify(|w| { @@ -78,8 +78,8 @@ pub(crate) async unsafe fn transfer_p2m( }); let res = poll_fn(|cx| { - STATE.ch_wakers[state_number].register(cx.waker()); - match STATE.ch_status[state_number].load(Ordering::Acquire) { + STATE.ch_wakers[state_number as usize].register(cx.waker()); + match STATE.ch_status[state_number as usize].load(Ordering::Acquire) { CH_STATUS_NONE => Poll::Pending, x => Poll::Ready(x), } @@ -93,7 +93,7 @@ pub(crate) async unsafe fn transfer_p2m( #[allow(unused)] pub(crate) async unsafe fn transfer_m2p( regs: pac::bdma::Ch, - state_number: usize, + state_number: u8, src: &[u8], dst: *mut u8, #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, @@ -105,7 +105,7 @@ pub(crate) async unsafe fn transfer_m2p( // Reset status // Generate a DMB here to flush the store buffer (M7) before enabling the DMA - STATE.ch_status[state_number].store(CH_STATUS_NONE, Ordering::Release); + STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); let on_drop = OnDrop::new(|| unsafe { regs.cr().modify(|w| { @@ -133,8 +133,8 @@ pub(crate) async unsafe fn transfer_m2p( }); let res = poll_fn(|cx| { - STATE.ch_wakers[state_number].register(cx.waker()); - match STATE.ch_status[state_number].load(Ordering::Acquire) { + STATE.ch_wakers[state_number as usize].register(cx.waker()); + match STATE.ch_status[state_number as usize].load(Ordering::Acquire) { CH_STATUS_NONE => Poll::Pending, x => Poll::Ready(x), } @@ -191,13 +191,11 @@ pub(crate) mod sealed { pub trait Channel { const CH_NUM: u8; - - fn dma_regs() -> pac::bdma::Dma; - - fn state_num(&self) -> usize; + const STATE_NUM: u8; + const DMA_REGS: pac::bdma::Dma; fn regs(&self) -> pac::bdma::Ch { - Self::dma_regs().ch(Self::CH_NUM as usize) + Self::DMA_REGS.ch(Self::CH_NUM as usize) } } } @@ -219,15 +217,17 @@ macro_rules! impl_dma_channel { impl Channel for crate::peripherals::$channel_peri {} impl sealed::Channel for crate::peripherals::$channel_peri { const CH_NUM: u8 = $ch_num; + const STATE_NUM: u8 = (dma_num!($dma_peri) * 8) + $ch_num; + const DMA_REGS: pac::bdma::Dma = crate::pac::$dma_peri; - #[inline] - fn dma_regs() -> pac::bdma::Dma { - crate::pac::$dma_peri - } + //#[inline] + //fn dma_regs() -> pac::bdma::Dma { + //crate::pac::$dma_peri + //} - fn state_num(&self) -> usize { - (dma_num!($dma_peri) * 8) + $ch_num - } + //fn state_num(&self) -> usize { + //(dma_num!($dma_peri) * 8) + $ch_num + //} } #[cfg(not(dmamux))] @@ -243,7 +243,7 @@ macro_rules! impl_dma_channel { { use sealed::Channel as _Channel; - let state_num = self.state_num(); + let state_num = Self::STATE_NUM; let regs = self.regs(); unsafe { transfer_m2p(regs, state_num, buf, dst) } @@ -264,7 +264,7 @@ macro_rules! impl_dma_channel { { use sealed::Channel as _Channel; - let state_num = self.state_num(); + let state_num = Self::STATE_NUM; let regs = self.regs(); use crate::dmamux::sealed::Channel as MuxChannel; @@ -307,7 +307,7 @@ macro_rules! impl_dma_channel { { use sealed::Channel as _Channel; - let state_num = self.state_num(); + let state_num = Self::STATE_NUM; let regs = self.regs(); unsafe { transfer_p2m(regs, state_num, src, buf) } } @@ -331,7 +331,7 @@ macro_rules! impl_dma_channel { { use sealed::Channel as _Channel; - let state_num = self.state_num(); + let state_num = Self::STATE_NUM; let regs = self.regs(); use crate::dmamux::sealed::Channel as MuxChannel;