From 3d1391ef2d634ca6a90c68be7cc69af02e3dc33b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 15 Jul 2021 05:42:06 +0200 Subject: [PATCH 01/13] stm32/dma: impl all variants --- embassy-stm32/src/bdma/mod.rs | 413 -------------------------- embassy-stm32/src/dma/bdma.rs | 222 ++++++++++++++ embassy-stm32/src/dma/dma.rs | 210 +++++++++++++ embassy-stm32/src/dma/dmamux.rs | 61 ++++ embassy-stm32/src/dma/mod.rs | 69 ++++- embassy-stm32/src/dma/v1.rs | 2 - embassy-stm32/src/dma/v2.rs | 331 --------------------- embassy-stm32/src/dma_traits.rs | 32 -- embassy-stm32/src/dmamux/mod.rs | 137 --------- embassy-stm32/src/lib.rs | 14 +- embassy-stm32/src/usart/mod.rs | 83 ++++-- embassy-stm32/src/usart/v1.rs | 45 ++- embassy-stm32/src/usart/v2.rs | 13 +- examples/stm32f4/src/bin/spi.rs | 2 +- examples/stm32f4/src/bin/usart.rs | 3 +- examples/stm32f4/src/bin/usart_dma.rs | 11 +- examples/stm32l4/src/bin/spi.rs | 2 +- examples/stm32l4/src/bin/usart.rs | 2 +- examples/stm32l4/src/bin/usart_dma.rs | 2 +- 19 files changed, 665 insertions(+), 989 deletions(-) delete mode 100644 embassy-stm32/src/bdma/mod.rs create mode 100644 embassy-stm32/src/dma/bdma.rs create mode 100644 embassy-stm32/src/dma/dma.rs create mode 100644 embassy-stm32/src/dma/dmamux.rs delete mode 100644 embassy-stm32/src/dma/v1.rs delete mode 100644 embassy-stm32/src/dma/v2.rs delete mode 100644 embassy-stm32/src/dma_traits.rs delete mode 100644 embassy-stm32/src/dmamux/mod.rs diff --git a/embassy-stm32/src/bdma/mod.rs b/embassy-stm32/src/bdma/mod.rs deleted file mode 100644 index f57358f6..00000000 --- a/embassy-stm32/src/bdma/mod.rs +++ /dev/null @@ -1,413 +0,0 @@ -#![macro_use] - -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!(bdma) * 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: u8, - 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 as usize].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 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), - } - }) - .await; - - // TODO handle error - assert!(res == CH_STATUS_COMPLETED); -} - -#[allow(unused)] -pub(crate) async unsafe fn transfer_m2p( - regs: pac::bdma::Ch, - state_number: u8, - 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 as usize].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 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), - } - }) - .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..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); - 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) => { - ::enable(); - }; - } -} - -pub(crate) mod sealed { - use super::*; - - pub trait Dma { - const NUM: u8; - } - - pub trait Channel { - const CH_NUM: u8; - 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) - } - } -} - -pub trait Dma: sealed::Dma + Sized {} -pub trait Channel: sealed::Channel + Sized {} - -macro_rules! impl_dma { - ($peri:ident) => { - impl Dma for crate::peripherals::$peri {} - impl sealed::Dma for crate::peripherals::$peri { - const NUM: u8 = dma_num!($peri); - } - }; -} - -macro_rules! impl_dma_channel { - ($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; - 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 - //} - - //fn state_num(&self) -> usize { - //(dma_num!($dma_peri) * 8) + $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 = ::DMAMUX_REGS; - let dmamux_ch_num = - ::DMAMUX_CH_NUM; - let request = >::REQUEST; - 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 = ::DMAMUX_REGS; - let dmamux_ch_num = - ::DMAMUX_CH_NUM; - let request = >::REQUEST; - unsafe { - transfer_p2m( - regs, - state_num, - src, - buf, - dmamux_regs, - dmamux_ch_num, - request, - ) - } - } - } - }; -} - -macro_rules! dma_num { - (DMA1) => { - 0 - }; - (DMA2) => { - 1 - }; - (BDMA) => { - 0 - }; -} -pac::peripherals! { - (bdma, $peri:ident) => { - impl_dma!($peri); - }; -} - -pac::bdma_channels! { - ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { - impl_dma_channel!($channel_peri, $dma_peri, $channel_num); - }; -} - -pac::interrupts! { - (DMA, $irq:ident) => { - #[crate::interrupt] - unsafe fn $irq () { - on_irq() - } - }; -} - -#[cfg(usart)] -use crate::usart; - -pac::peripherals! { - (usart, $peri:ident) => { - 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) => { - impl> usart::TxDma for T {} - impl> usart::sealed::TxDma for T {} - - impl> usart::RxDma for T {} - impl> usart::sealed::RxDma for T {} - }; -} diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs new file mode 100644 index 00000000..9449d4bf --- /dev/null +++ b/embassy-stm32/src/dma/bdma.rs @@ -0,0 +1,222 @@ +#![macro_use] + +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::{Channel, Request}; +use crate::interrupt; +use crate::pac; +use crate::pac::bdma::vals; +use crate::rcc::sealed::RccPeripheral; + +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; + +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 do_transfer( + dma: pac::bdma::Dma, + channel_number: u8, + state_number: u8, + request: Request, + dir: vals::Dir, + peri_addr: *const u8, + mem_addr: *mut u8, + mem_len: usize, + #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, + #[cfg(dmamux)] dmamux_ch_num: u8, +) { + // ndtr is max 16 bits. + assert!(mem_len <= 0xFFFF); + + let ch = dma.ch(channel_number as _); + + // Reset status + // Generate a DMB here to flush the store buffer (M7) before enabling the DMA + STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); + + let on_drop = OnDrop::new(|| unsafe { + ch.cr().modify(|w| { + w.set_tcie(false); + w.set_teie(false); + w.set_en(false); + }); + while ch.cr().read().en() {} + }); + + #[cfg(dmamux)] + super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); + + #[cfg(bdma_v2)] + critical_section::with(|_| { + dma.cselr() + .modify(|w| w.set_cs(channel_number as _, request)) + }); + + ch.par().write_value(peri_addr as u32); + ch.mar().write_value(mem_addr as u32); + ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); + ch.cr().write(|w| { + w.set_psize(vals::Size::BITS8); + w.set_msize(vals::Size::BITS8); + w.set_minc(vals::Inc::ENABLED); + w.set_dir(dir); + w.set_teie(true); + w.set_tcie(true); + w.set_en(true); + }); + + let res = poll_fn(|cx| { + 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), + } + }) + .await; + + on_drop.defuse(); + + // TODO handle error + assert!(res == CH_STATUS_COMPLETED); +} + +macro_rules! dma_num { + (DMA1) => { + 0 + }; + (DMA2) => { + 1 + }; + (BDMA) => { + 0 + }; +} + +unsafe fn on_irq() { + pac::peripherals! { + (bdma, $dma:ident) => { + let isr = pac::$dma.isr().read(); + pac::$dma.ifcr().write_value(isr); + let dman = dma_num!($dma); + + 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); + 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(); + }; + } + pac::peripherals! { + (bdma, $peri:ident) => { + crate::peripherals::$peri::enable(); + }; + } +} + +pac::bdma_channels! { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {} + impl Channel for crate::peripherals::$channel_peri + { + type ReadFuture<'a> = impl Future; + type WriteFuture<'a> = impl Future; + + fn read<'a>( + &'a mut self, + request: Request, + src: *mut u8, + buf: &'a mut [u8], + ) -> Self::ReadFuture<'a> { + unsafe { + do_transfer( + crate::pac::$dma_peri, + $channel_num, + (dma_num!($dma_peri) * 8) + $channel_num, + request, + vals::Dir::FROMPERIPHERAL, + src, + buf.as_mut_ptr(), + buf.len(), + #[cfg(dmamux)] + ::DMAMUX_REGS, + #[cfg(dmamux)] + ::DMAMUX_CH_NUM, + ) + } + } + + fn write<'a>( + &'a mut self, + request: Request, + buf: &'a [u8], + dst: *mut u8, + ) -> Self::WriteFuture<'a> { + unsafe { + do_transfer( + crate::pac::$dma_peri, + $channel_num, + (dma_num!($dma_peri) * 8) + $channel_num, + request, + vals::Dir::FROMMEMORY, + dst, + buf.as_ptr() as *mut u8, + buf.len(), + #[cfg(dmamux)] + ::DMAMUX_REGS, + #[cfg(dmamux)] + ::DMAMUX_CH_NUM, + ) + } + } + } + }; +} + +pac::interrupts! { + (DMA, $irq:ident) => { + #[crate::interrupt] + unsafe fn $irq () { + on_irq() + } + }; +} diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs new file mode 100644 index 00000000..b0df6ddc --- /dev/null +++ b/embassy-stm32/src/dma/dma.rs @@ -0,0 +1,210 @@ +use core::task::Poll; + +use atomic_polyfill::{AtomicU8, Ordering}; +use core::future::Future; +use embassy::interrupt::{Interrupt, InterruptExt}; +use embassy::util::AtomicWaker; +use futures::future::poll_fn; + +use crate::interrupt; +use crate::pac; +use crate::pac::dma::{regs, vals}; +use crate::rcc::sealed::RccPeripheral; + +use super::{Channel, Request}; + +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(); + +//async unsafe fn do_transfer(ch: &mut impl Channel, ch_func: u8, src: *const u8, dst: &mut [u8]) { + +pub(crate) async unsafe fn do_transfer( + dma: pac::dma::Dma, + channel_number: u8, + state_number: u8, + request: Request, + dir: vals::Dir, + peri_addr: *const u8, + mem_addr: *mut u8, + mem_len: usize, + #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, + #[cfg(dmamux)] dmamux_ch_num: u8, +) { + // ndtr is max 16 bits. + assert!(mem_len <= 0xFFFF); + + // Reset status + // Generate a DMB here to flush the store buffer (M7) before enabling the DMA + STATE.ch_status[state_number as usize].store(CH_STATUS_NONE, Ordering::Release); + + let ch = dma.st(channel_number as _); + + #[cfg(dmamux)] + super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); + + unsafe { + ch.par().write_value(peri_addr as u32); + ch.m0ar().write_value(mem_addr as u32); + ch.ndtr().write_value(regs::Ndtr(mem_len as _)); + ch.cr().write(|w| { + w.set_dir(dir); + w.set_msize(vals::Size::BITS8); + w.set_psize(vals::Size::BITS8); + w.set_minc(vals::Inc::INCREMENTED); + w.set_pinc(vals::Inc::FIXED); + w.set_teie(true); + w.set_tcie(true); + w.set_en(true); + + #[cfg(dma_v2)] + w.set_chsel(request); + }); + } + + let res = poll_fn(|cx| { + let n = channel_number as usize; + 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; + + // TODO handle error + assert!(res == CH_STATUS_COMPLETED); +} + +macro_rules! dma_num { + (DMA1) => { + 0 + }; + (DMA2) => { + 1 + }; +} + +unsafe fn on_irq() { + pac::peripherals! { + (dma, $dma:ident) => { + for isrn in 0..2 { + let isr = pac::$dma.isr(isrn).read(); + pac::$dma.ifcr(isrn).write_value(isr); + let dman = dma_num!($dma); + + for chn in 0..4 { + let n = dman * 8 + isrn * 4 + 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) => { + interrupt::$irq::steal().enable(); + }; + } + pac::peripherals! { + (dma, $peri:ident) => { + crate::peripherals::$peri::enable(); + }; + } +} + +pac::dma_channels! { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {} + impl Channel for crate::peripherals::$channel_peri + { + type ReadFuture<'a> = impl Future; + type WriteFuture<'a> = impl Future; + + fn read<'a>( + &'a mut self, + request: Request, + src: *mut u8, + buf: &'a mut [u8], + ) -> Self::ReadFuture<'a> { + unsafe { + do_transfer( + crate::pac::$dma_peri, + $channel_num, + (dma_num!($dma_peri) * 8) + $channel_num, + request, + vals::Dir::PERIPHERALTOMEMORY, + src, + buf.as_mut_ptr(), + buf.len(), + #[cfg(dmamux)] + ::DMAMUX_REGS, + #[cfg(dmamux)] + ::DMAMUX_CH_NUM, + ) + } + } + + fn write<'a>( + &'a mut self, + request: Request, + buf: &'a [u8], + dst: *mut u8, + ) -> Self::WriteFuture<'a> { + unsafe { + do_transfer( + crate::pac::$dma_peri, + $channel_num, + (dma_num!($dma_peri) * 8) + $channel_num, + request, + vals::Dir::MEMORYTOPERIPHERAL, + dst, + buf.as_ptr() as *mut u8, + buf.len(), + #[cfg(dmamux)] + ::DMAMUX_REGS, + #[cfg(dmamux)] + ::DMAMUX_CH_NUM, + ) + } + } + } + }; +} + +pac::interrupts! { + (DMA, $irq:ident) => { + #[crate::interrupt] + unsafe fn $irq () { + on_irq() + } + }; +} diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs new file mode 100644 index 00000000..ca2879c2 --- /dev/null +++ b/embassy-stm32/src/dma/dmamux.rs @@ -0,0 +1,61 @@ +#![macro_use] + +use crate::pac; +use crate::peripherals; + +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| { + reg.set_nbreq(0); + reg.set_dmareq_id(request); + }); + + ch_mux_regs.modify(|reg| { + reg.set_ege(true); + }); +} + +pub(crate) trait MuxChannel { + const DMAMUX_CH_NUM: u8; + const DMAMUX_REGS: pac::dmamux::Dmamux; +} + +macro_rules! dma_num { + (DMA1) => { + 0 + }; + (DMA2) => { + 1 + }; + (BDMA) => { + 0 + }; +} + +macro_rules! dmamux_peri { + (DMA1) => { + crate::pac::DMAMUX1 + }; + (DMA2) => { + crate::pac::DMAMUX1 + }; + (BDMA) => { + crate::pac::DMAMUX1 + }; +} + +pac::bdma_channels! { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl MuxChannel 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); + } + }; +} + +/// safety: must be called only once +pub(crate) unsafe fn init() {} diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index ed080cd1..ebad3d7b 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -1,9 +1,62 @@ -#![macro_use] - -#[cfg_attr(dma_v1, path = "v1.rs")] -#[cfg_attr(dma_v2, path = "v2.rs")] -mod _version; - +#[cfg(bdma)] +mod bdma; #[cfg(dma)] -#[allow(unused)] -pub use _version::*; +mod dma; +#[cfg(dmamux)] +mod dmamux; + +use core::future::Future; +use embassy::util::Unborrow; + +#[cfg(any(bdma_v2, dma_v2, dmamux))] +pub type Request = u8; +#[cfg(not(any(bdma_v2, dma_v2, dmamux)))] +pub type Request = (); + +pub(crate) mod sealed { + pub trait Channel {} +} + +pub trait Channel: sealed::Channel { + type ReadFuture<'a>: Future + 'a + where + Self: 'a; + + type WriteFuture<'a>: Future + 'a + where + Self: 'a; + + fn read<'a>( + &'a mut self, + request: Request, + src: *mut u8, + buf: &'a mut [u8], + ) -> Self::ReadFuture<'a>; + + fn write<'a>( + &'a mut self, + request: Request, + buf: &'a [u8], + dst: *mut u8, + ) -> Self::WriteFuture<'a>; +} + +pub struct NoDma; + +unsafe impl Unborrow for NoDma { + type Target = NoDma; + + unsafe fn unborrow(self) -> Self::Target { + self + } +} + +// safety: must be called only once at startup +pub(crate) unsafe fn init() { + #[cfg(bdma)] + bdma::init(); + #[cfg(dma)] + dma::init(); + #[cfg(dmamux)] + dmamux::init(); +} diff --git a/embassy-stm32/src/dma/v1.rs b/embassy-stm32/src/dma/v1.rs deleted file mode 100644 index 4544108e..00000000 --- a/embassy-stm32/src/dma/v1.rs +++ /dev/null @@ -1,2 +0,0 @@ -/// safety: must be called only once -pub(crate) unsafe fn init() {} diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs deleted file mode 100644 index df3b922f..00000000 --- a/embassy-stm32/src/dma/v2.rs +++ /dev/null @@ -1,331 +0,0 @@ -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; - -use crate::interrupt; -use crate::pac; -use crate::pac::dma::{regs, vals}; - -use crate::pac::dma_channels; -use crate::pac::interrupts; -use crate::pac::peripheral_count; -use crate::pac::peripheral_dma_channels; -use crate::pac::peripherals; -use crate::peripherals; - -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)] // Used by usart/v1.rs which may or may not be enabled -pub(crate) async unsafe fn transfer_p2m( - ch: &mut impl Channel, - ch_func: u8, - src: *const u8, - dst: &mut [u8], -) { - let n = ch.num(); - let c = ch.regs(); - - // 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[n].store(CH_STATUS_NONE, Ordering::Release); - - unsafe { - c.par().write_value(src as _); - c.m0ar().write_value(dst.as_ptr() as _); - c.ndtr().write_value(regs::Ndtr(dst.len() as _)); - c.cr().write(|w| { - w.set_dir(vals::Dir::PERIPHERALTOMEMORY); - w.set_msize(vals::Size::BITS8); - w.set_psize(vals::Size::BITS8); - w.set_minc(vals::Inc::INCREMENTED); - w.set_pinc(vals::Inc::FIXED); - w.set_chsel(ch_func); - w.set_teie(true); - w.set_tcie(true); - w.set_en(true); - }); - } - - let res = poll_fn(|cx| { - 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; - - // TODO handle error - assert!(res == CH_STATUS_COMPLETED); -} - -#[allow(unused)] // Used by usart/v1.rs which may or may not be enabled -pub(crate) async unsafe fn transfer_m2p( - ch: &mut impl Channel, - ch_func: u8, - src: &[u8], - dst: *mut u8, -) { - let n = ch.num(); - let c = ch.regs(); - - // 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[n].store(CH_STATUS_NONE, Ordering::Release); - - unsafe { - c.par().write_value(dst as _); - c.m0ar().write_value(src.as_ptr() as _); - c.ndtr().write_value(regs::Ndtr(src.len() as _)); - c.cr().write(|w| { - w.set_dir(vals::Dir::MEMORYTOPERIPHERAL); - w.set_msize(vals::Size::BITS8); - w.set_psize(vals::Size::BITS8); - w.set_minc(vals::Inc::INCREMENTED); - w.set_pinc(vals::Inc::FIXED); - w.set_chsel(ch_func); - w.set_teie(true); - w.set_tcie(true); - w.set_en(true); - }); - } - - let res = poll_fn(|cx| { - STATE.ch_wakers[n].register(cx.waker()); - match STATE.ch_status[n].load(Ordering::Acquire) { - CH_STATUS_NONE => { - let left = c.ndtr().read().ndt(); - Poll::Pending - } - x => Poll::Ready(x), - } - }) - .await; - - // TODO handle error - assert!(res == CH_STATUS_COMPLETED); -} - -unsafe fn on_irq() { - peripherals! { - (dma, $dma:ident) => { - for isrn in 0..2 { - let isr = pac::$dma.isr(isrn).read(); - pac::$dma.ifcr(isrn).write_value(isr); - let dman = ::num() as usize; - - for chn in 0..4 { - let n = dman * 8 + isrn * 4 + 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() { - interrupts! { - (DMA, $irq:ident) => { - interrupt::$irq::steal().enable(); - }; - } -} - -pub(crate) mod sealed { - use super::*; - - pub trait Dma { - fn num() -> u8; - fn regs() -> &'static pac::dma::Dma; - } - - pub trait Channel { - fn dma_regs() -> &'static pac::dma::Dma; - - fn num(&self) -> usize; - - fn ch_num(&self) -> u8; - - fn regs(&self) -> pac::dma::St { - Self::dma_regs().st(self.ch_num() as _) - } - } - - pub trait PeripheralChannel: Channel { - fn request(&self) -> u8; - } -} - -pub trait Dma: sealed::Dma + Sized {} -pub trait Channel: sealed::Channel + Sized {} -pub trait PeripheralChannel: sealed::PeripheralChannel + Sized {} - -macro_rules! impl_dma { - ($peri:ident, $num:expr) => { - impl Dma for peripherals::$peri {} - impl sealed::Dma for peripherals::$peri { - fn num() -> u8 { - $num - } - fn regs() -> &'static pac::dma::Dma { - &pac::$peri - } - } - }; -} - -macro_rules! impl_dma_channel { - ($channel_peri:ident, $dma_peri:ident, $dma_num:expr, $ch_num:expr) => { - impl Channel for peripherals::$channel_peri {} - impl sealed::Channel for peripherals::$channel_peri { - #[inline] - fn dma_regs() -> &'static pac::dma::Dma { - &crate::pac::$dma_peri - } - - fn num(&self) -> usize { - ($dma_num * 8) + $ch_num - } - - fn ch_num(&self) -> u8 { - $ch_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! { - (dma, DMA1) => { - impl_dma!(DMA1, 0); - dma_channels! { - ($channel_peri:ident, DMA1, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMA1, 0, $channel_num); - }; - } - }; - (dma, DMA2) => { - impl_dma!(DMA2, 1); - dma_channels! { - ($channel_peri:ident, DMA2, $channel_num:expr) => { - impl_dma_channel!($channel_peri, DMA2, 1, $channel_num); - }; - } - }; -} - -interrupts! { - (DMA, $irq:ident) => { - #[crate::interrupt] - unsafe fn $irq () { - on_irq() - } - }; -} - -pub struct P2M; -pub struct M2P; - -#[cfg(usart)] -use crate::usart; -peripheral_dma_channels! { - ($peri:ident, usart, $kind:ident, RX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num: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 { - $event_num - } - } - - impl PeripheralChannel for peripherals::$channel_peri { } - }; - - ($peri:ident, usart, $kind:ident, TX, $channel_peri:ident, $dma_peri:ident, $channel_num:expr, $event_num: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 { - $event_num - } - } - - impl PeripheralChannel for peripherals::$channel_peri { } - }; -} diff --git a/embassy-stm32/src/dma_traits.rs b/embassy-stm32/src/dma_traits.rs deleted file mode 100644 index 6733d911..00000000 --- a/embassy-stm32/src/dma_traits.rs +++ /dev/null @@ -1,32 +0,0 @@ -use core::future::Future; -use embassy::util::Unborrow; - -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; -} - -pub struct NoDma; - -unsafe impl Unborrow for NoDma { - type Target = NoDma; - - unsafe fn unborrow(self) -> Self::Target { - self - } -} diff --git a/embassy-stm32/src/dmamux/mod.rs b/embassy-stm32/src/dmamux/mod.rs deleted file mode 100644 index ecea0b29..00000000 --- a/embassy-stm32/src/dmamux/mod.rs +++ /dev/null @@ -1,137 +0,0 @@ -#![macro_use] - -use crate::pac; -use crate::pac::bdma_channels; -use crate::pac::dma_requests; -use crate::pac::peripherals; -use crate::peripherals; - -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| { - reg.set_nbreq(0); - reg.set_dmareq_id(request); - }); - - ch_mux_regs.modify(|reg| { - reg.set_ege(true); - }); -} - -pub(crate) mod sealed { - use super::*; - - pub trait Channel { - const DMAMUX_CH_NUM: u8; - const DMAMUX_REGS: pac::dmamux::Dmamux; - } - - pub trait PeripheralChannel: Channel { - const REQUEST: u8; - } -} - -pub trait Channel: sealed::Channel {} -pub trait PeripheralChannel: sealed::Channel {} - -pub struct P2M; -pub struct M2P; - -macro_rules! dma_num { - (DMA1) => { - 0 - }; - (DMA2) => { - 1 - }; - (BDMA) => { - 0 - }; -} - -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); - } - }; -} - -peripherals! { - (bdma, $peri:ident) => { - bdma_channels! { - ($channel_peri:ident, $peri, $channel_num:expr) => { - impl_dma_channel!($channel_peri, $channel_num, $peri); - }; - } - }; -} - -#[allow(unused)] -macro_rules! impl_peripheral_channel { - ($channel_peri:ident, $direction:ident, $peri:ident, $request:expr) => { - impl sealed::PeripheralChannel - for peripherals::$channel_peri - { - const REQUEST: 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! { - (usart, $peri:ident, RX, $request:expr) => { - 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, RX, $request:expr) => { - impl_peripheral_channel!($channel_peri, P2M, $peri, $request); - }; - - (uart, $peri:ident, TX, $request:expr) => { - impl_peripheral_channel!($channel_peri, M2P, $peri, $request); - }; - } - }; -} - -#[allow(unused)] -#[cfg(usart)] -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); - }; -} - -/// safety: must be called only once -pub(crate) unsafe fn init() {} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 22999a69..c10310e2 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -19,25 +19,18 @@ pub mod interrupt; pub mod time; // Always-present hardware +pub mod dma; 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)] -pub mod bdma; #[cfg(timer)] pub mod clock; #[cfg(dac)] pub mod dac; -#[cfg(dma)] -pub mod dma; -#[cfg(dmamux)] -pub mod dmamux; #[cfg(all(eth, feature = "net"))] pub mod eth; #[cfg(exti)] @@ -94,12 +87,7 @@ pub fn init(config: Config) -> Peripherals { let p = Peripherals::take(); unsafe { - #[cfg(dma)] dma::init(); - #[cfg(bdma)] - bdma::init(); - #[cfg(dmamux)] - dmamux::init(); #[cfg(exti)] exti::init(); diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index c3ac8bc5..bf6fa913 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -3,7 +3,7 @@ #[cfg_attr(usart_v1, path = "v1.rs")] #[cfg_attr(usart_v2, path = "v2.rs")] mod _version; -use crate::peripherals; +use crate::{dma, peripherals}; pub use _version::*; use crate::gpio::Pin; @@ -72,9 +72,6 @@ pub enum Error { pub(crate) mod sealed { use super::*; - #[cfg(any(dma, bdma, dmamux))] - use crate::dma_traits::WriteDma; - pub trait Instance { fn regs(&self) -> crate::pac::usart::Usart; } @@ -94,11 +91,13 @@ pub(crate) mod sealed { fn af_num(&self) -> u8; } - #[cfg(any(bdma, dma, dmamux))] - pub trait RxDma {} + pub trait RxDma { + fn request(&self) -> dma::Request; + } - #[cfg(any(bdma, dma, dmamux))] - pub trait TxDma: WriteDma {} + pub trait TxDma { + fn request(&self) -> dma::Request; + } } pub trait Instance: sealed::Instance + RccPeripheral {} @@ -107,12 +106,8 @@ pub trait TxPin: sealed::TxPin {} pub trait CtsPin: sealed::CtsPin {} pub trait RtsPin: sealed::RtsPin {} pub trait CkPin: sealed::CkPin {} - -#[cfg(any(bdma, dma, dmamux))] -pub trait RxDma: sealed::RxDma {} - -#[cfg(any(bdma, dma, dmamux))] -pub trait TxDma: sealed::TxDma {} +pub trait RxDma: sealed::RxDma + dma::Channel {} +pub trait TxDma: sealed::TxDma + dma::Channel {} crate::pac::peripherals!( (usart, $inst:ident) => { @@ -141,46 +136,86 @@ macro_rules! impl_pin { crate::pac::peripheral_pins!( // USART - ($inst:ident, usart, USART, $pin:ident, TX, $af:expr) => { impl_pin!($inst, $pin, TxPin, $af); }; - ($inst:ident, usart, USART, $pin:ident, RX, $af:expr) => { impl_pin!($inst, $pin, RxPin, $af); }; - ($inst:ident, usart, USART, $pin:ident, CTS, $af:expr) => { impl_pin!($inst, $pin, CtsPin, $af); }; - ($inst:ident, usart, USART, $pin:ident, RTS, $af:expr) => { impl_pin!($inst, $pin, RtsPin, $af); }; - ($inst:ident, usart, USART, $pin:ident, CK, $af:expr) => { impl_pin!($inst, $pin, CkPin, $af); }; // UART - ($inst:ident, uart, UART, $pin:ident, TX, $af:expr) => { impl_pin!($inst, $pin, TxPin, $af); }; - ($inst:ident, uart, UART, $pin:ident, RX, $af:expr) => { impl_pin!($inst, $pin, RxPin, $af); }; - ($inst:ident, uart, UART, $pin:ident, CTS, $af:expr) => { impl_pin!($inst, $pin, CtsPin, $af); }; - ($inst:ident, uart, UART, $pin:ident, RTS, $af:expr) => { impl_pin!($inst, $pin, RtsPin, $af); }; - ($inst:ident, uart, UART, $pin:ident, CK, $af:expr) => { impl_pin!($inst, $pin, CkPin, $af); }; ); + +macro_rules! impl_dma { + ($inst:ident, ALL, $signal:ident, $request:expr) => { + impl sealed::$signal for T { + fn request(&self) -> dma::Request { + $request + } + } + + impl $signal for T {} + }; + ($inst:ident, $channel:ident, $signal:ident, $request:expr) => { + impl sealed::$signal for peripherals::$channel { + fn request(&self) -> dma::Request { + $request + } + } + + impl $signal for peripherals::$channel {} + }; +} + +crate::pac::peripheral_dma_channels! { + ($peri:ident, usart, $kind:ident, RX, $channel:ident, $dma_peri:ident, $channel_num:expr, $request:expr) => { + impl_dma!($peri, $channel, RxDma, $request); + }; + ($peri:ident, usart, $kind:ident, TX, $channel:ident, $dma_peri:ident, $channel_num:expr, $request:expr) => { + impl_dma!($peri, $channel, TxDma, $request); + }; + ($peri:ident, uart, $kind:ident, RX, $channel:ident, $dma_peri:ident, $channel_num:expr, $request:expr) => { + impl_dma!($peri, $channel, RxDma, $request); + }; + ($peri:ident, uart, $kind:ident, TX, $channel:ident, $dma_peri:ident, $channel_num:expr, $request:expr) => { + impl_dma!($peri, $channel, TxDma, $request); + }; +} +crate::pac::dma_requests! { + (usart, $peri:ident, RX, $request:expr) => { + impl_dma!($peri, ALL, RxDma, $request); + }; + (usart, $peri:ident, TX, $request:expr) => { + impl_dma!($peri, ALL, TxDma, $request); + }; + (uart, $peri:ident, RX, $request:expr) => { + impl_dma!($peri, ALL, RxDma, $request); + }; + (uart, $peri:ident, TX, $request:expr) => { + impl_dma!($peri, ALL, TxDma, $request); + }; +} diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs index 16993895..0f39c364 100644 --- a/embassy-stm32/src/usart/v1.rs +++ b/embassy-stm32/src/usart/v1.rs @@ -1,25 +1,31 @@ +use core::future::Future; use core::marker::PhantomData; - use embassy::util::Unborrow; use embassy_extras::unborrow; - -use crate::pac::usart::{regs, vals}; +use futures::TryFutureExt; use super::*; +use crate::dma::NoDma; +use crate::pac::usart::{regs, vals}; -pub struct Uart<'d, T: Instance> { +pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { inner: T, phantom: PhantomData<&'d mut T>, + tx_dma: TxDma, + #[allow(dead_code)] + rx_dma: RxDma, } -impl<'d, T: Instance> Uart<'d, T> { +impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { pub fn new( inner: impl Unborrow, rx: impl Unborrow>, tx: impl Unborrow>, + tx_dma: impl Unborrow, + rx_dma: impl Unborrow, config: Config, ) -> Self { - unborrow!(inner, rx, tx); + unborrow!(inner, rx, tx, tx_dma, rx_dma); T::enable(); let pclk_freq = T::frequency(); @@ -53,11 +59,16 @@ impl<'d, T: Instance> Uart<'d, T> { Self { inner, phantom: PhantomData, + tx_dma, + rx_dma, } } - #[cfg(dma)] - pub async fn write_dma(&mut self, ch: &mut impl TxDma, buffer: &[u8]) -> Result<(), Error> { + async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error> + where + TxDma: crate::usart::TxDma, + { + let ch = &mut self.tx_dma; unsafe { self.inner.regs().cr3().modify(|reg| { reg.set_dmat(true); @@ -65,7 +76,7 @@ impl<'d, T: Instance> Uart<'d, T> { } let r = self.inner.regs(); let dst = r.dr().ptr() as *mut u8; - ch.transfer(buffer, dst).await; + ch.write(ch.request(), buffer, dst).await; Ok(()) } @@ -98,7 +109,9 @@ impl<'d, T: Instance> Uart<'d, T> { } } -impl<'d, T: Instance> embedded_hal::blocking::serial::Write for Uart<'d, T> { +impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write + for Uart<'d, T, NoDma, RxDma> +{ type Error = Error; fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { unsafe { @@ -118,3 +131,15 @@ impl<'d, T: Instance> embedded_hal::blocking::serial::Write for Uart<'d, T> Ok(()) } } + +// rustfmt::skip because intellij removes the 'where' claus on the associated type. +#[rustfmt::skip] +impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma> + where TxDma: crate::usart::TxDma +{ + type WriteFuture<'a> where Self: 'a = impl Future>; + + fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { + self.write_dma(buf).map_err(|_| embassy_traits::uart::Error::Other) + } +} diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index b958c0a0..b97e3614 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs @@ -1,21 +1,18 @@ use core::marker::PhantomData; - +use core::future::Future; +use futures::TryFutureExt; use embassy::util::Unborrow; use embassy_extras::unborrow; use crate::pac::usart::{regs, vals}; - use super::*; -use core::future::Future; -use futures::TryFutureExt; +use crate::dma::NoDma; -use crate::dma_traits::NoDma; - -#[allow(dead_code)] pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { inner: T, phantom: PhantomData<&'d mut T>, tx_dma: TxDma, + #[allow(dead_code)] rx_dma: RxDma, } @@ -83,7 +80,7 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { } let r = self.inner.regs(); let dst = r.tdr().ptr() as *mut u8; - ch.transfer(buffer, dst).await; + ch.write(ch.request(), buffer, dst).await; Ok(()) } diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs index dda0ee4e..aa48ceed 100644 --- a/examples/stm32f4/src/bin/spi.rs +++ b/examples/stm32f4/src/bin/spi.rs @@ -61,7 +61,7 @@ fn main() -> ! { let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); loop { - let mut buf = [0x0A; 4]; + let mut buf = [0x0Au8; 4]; unwrap!(cs.set_low()); unwrap!(spi.transfer(&mut buf)); unwrap!(cs.set_high()); diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 42f154b0..31525036 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs @@ -12,6 +12,7 @@ use cortex_m::prelude::_embedded_hal_blocking_serial_Write; use embassy::executor::Executor; use embassy::time::Clock; use embassy::util::Forever; +use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use example_common::*; @@ -23,7 +24,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap(); info!("wrote Hello, starting echo"); diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index 66ca6242..39e199d5 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs @@ -13,26 +13,25 @@ use cortex_m_rt::entry; use embassy::executor::Executor; use embassy::time::Clock; use embassy::util::Forever; +use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; +use embassy_traits::uart::Write as _; use example_common::*; use heapless::String; use stm32f4::stm32f429 as pac; #[embassy::task] async fn main_task() { - let mut p = embassy_stm32::init(Default::default()); + let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_3, NoDma, 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(); + usart.write(s.as_bytes()).await.unwrap(); info!("wrote DMA"); } } diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs index 45ccfceb..7cac01fd 100644 --- a/examples/stm32l4/src/bin/spi.rs +++ b/examples/stm32l4/src/bin/spi.rs @@ -57,7 +57,7 @@ fn main() -> ! { let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); loop { - let mut buf = [0x0A; 4]; + let mut buf = [0x0Au8; 4]; unwrap!(cs.set_low()); unwrap!(spi.transfer(&mut buf)); unwrap!(cs.set_high()); diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index e9a44f15..f572b1ef 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs @@ -13,7 +13,7 @@ use cortex_m_rt::entry; use embassy::executor::Executor; use embassy::time::Clock; use embassy::util::Forever; -use embassy_stm32::dma_traits::NoDma; +use embassy_stm32::dma::NoDma; use embassy_stm32::pac; use embassy_stm32::usart::{Config, Uart}; use example_common::*; diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 1eadd3ad..12857bc7 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs @@ -13,7 +13,7 @@ use cortex_m_rt::entry; use embassy::executor::Executor; use embassy::time::Clock; use embassy::util::Forever; -use embassy_stm32::dma_traits::NoDma; +use embassy_stm32::dma::NoDma; use embassy_stm32::pac; use embassy_stm32::usart::{Config, Uart}; use embassy_traits::uart::Write as _; From 2ee20f5dcb27ef6e340569922a861ce3d9596d74 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 15 Jul 2021 05:43:06 +0200 Subject: [PATCH 02/13] Update vscode settings. --- .vscode/settings.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ceb87ad5..a5a65663 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,12 +1,17 @@ { "editor.formatOnSave": true, + "rust-analyzer.assist.importEnforceGranularity": true, + "rust-analyzer.assist.importGranularity": "module", "rust-analyzer.checkOnSave.allFeatures": false, "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.cargo.noDefaultFeatures": true, + "rust-analyzer.checkOnSave.noDefaultFeatures": true, "rust-analyzer.cargo.target": "thumbv7em-none-eabi", "rust-analyzer.cargo.features": [ // These are needed to prevent embassy-net from failing to build "embassy-net/medium-ethernet", - "embassy-net/tcp" + "embassy-net/tcp", + "embassy-net/pool-16", ], "rust-analyzer.procMacro.enable": true, "rust-analyzer.cargo.runBuildScripts": true, From 63a0e188eae16bdf3c40ec627bbfbdcaa1cf4978 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 15 Jul 2021 06:31:54 +0200 Subject: [PATCH 03/13] stm32/dma: fix h7 impls --- embassy-stm32/src/dma/bdma.rs | 42 ++++++++++++++++++++++++++++++- embassy-stm32/src/dma/dmamux.rs | 37 +++++++++++++++------------ examples/stm32h7/src/bin/usart.rs | 9 +++---- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 9449d4bf..37bd24d0 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -138,7 +138,6 @@ unsafe fn on_irq() { } } - /// safety: must be called only once pub(crate) unsafe fn init() { pac::interrupts! { @@ -212,6 +211,9 @@ pac::bdma_channels! { }; } +// HACK: on stm32h7 "DMA" interrupts are for DMA, not BDMA, so this +// would cause duplicate interrupt definitions. Do it manually insted +#[cfg(not(rcc_h7))] pac::interrupts! { (DMA, $irq:ident) => { #[crate::interrupt] @@ -220,3 +222,41 @@ pac::interrupts! { } }; } + +#[cfg(rcc_h7)] +mod _if_h7 { + use super::*; + + #[crate::interrupt] + unsafe fn BDMA_CHANNEL0() { + on_irq() + } + #[crate::interrupt] + unsafe fn BDMA_CHANNEL1() { + on_irq() + } + #[crate::interrupt] + unsafe fn BDMA_CHANNEL2() { + on_irq() + } + #[crate::interrupt] + unsafe fn BDMA_CHANNEL3() { + on_irq() + } + #[crate::interrupt] + unsafe fn BDMA_CHANNEL4() { + on_irq() + } + #[crate::interrupt] + unsafe fn BDMA_CHANNEL5() { + on_irq() + } + #[crate::interrupt] + unsafe fn BDMA_CHANNEL6() { + on_irq() + } + #[crate::interrupt] + unsafe fn BDMA_CHANNEL7() { + on_irq() + } +} diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index ca2879c2..e9fa4823 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs @@ -31,28 +31,33 @@ macro_rules! dma_num { (DMA2) => { 1 }; - (BDMA) => { - 0 - }; -} - -macro_rules! dmamux_peri { - (DMA1) => { - crate::pac::DMAMUX1 - }; - (DMA2) => { - crate::pac::DMAMUX1 - }; - (BDMA) => { - crate::pac::DMAMUX1 - }; } +#[cfg(not(rcc_h7))] pac::bdma_channels! { ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { impl MuxChannel 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); + const DMAMUX_REGS: pac::dmamux::Dmamux = pac::DMAMUX1; + } + }; +} + +#[cfg(rcc_h7)] +pac::dma_channels! { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl MuxChannel for peripherals::$channel_peri { + const DMAMUX_CH_NUM: u8 = (dma_num!($dma_peri) * 8) + $channel_num; + const DMAMUX_REGS: pac::dmamux::Dmamux = pac::DMAMUX1; + } + }; +} +#[cfg(rcc_h7)] +pac::bdma_channels! { + ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + impl MuxChannel for peripherals::$channel_peri { + const DMAMUX_CH_NUM: u8 = $channel_num; + const DMAMUX_REGS: pac::dmamux::Dmamux = pac::DMAMUX2; } }; } diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index d8e60158..143f9449 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs @@ -1,4 +1,3 @@ - #![no_std] #![no_main] #![feature(trait_alias)] @@ -13,12 +12,12 @@ use cortex_m::prelude::_embedded_hal_blocking_serial_Write; use embassy::executor::Executor; use embassy::time::Clock; use embassy::util::Forever; +use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; -use embassy_stm32::dma_traits::NoDma; use example_common::*; -use stm32h7xx_hal as hal; use hal::prelude::*; +use stm32h7xx_hal as hal; use cortex_m_rt::entry; use stm32h7::stm32h743 as pac; @@ -60,8 +59,7 @@ fn main() -> ! { let rcc = pp.RCC.constrain(); - rcc - .sys_ck(96.mhz()) + rcc.sys_ck(96.mhz()) .pclk1(48.mhz()) .pclk2(48.mhz()) .pclk3(48.mhz()) @@ -89,7 +87,6 @@ fn main() -> ! { w }); - unsafe { embassy::time::set_clock(&ZeroClock) }; let executor = EXECUTOR.put(Executor::new()); From d0f2dc3abd85e7d198a59b10be1357c31300733f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 15 Jul 2021 06:33:34 +0200 Subject: [PATCH 04/13] Fix rustfmt --- embassy-stm32/src/usart/v2.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index b97e3614..8a4d63b2 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs @@ -1,12 +1,12 @@ -use core::marker::PhantomData; use core::future::Future; -use futures::TryFutureExt; +use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_extras::unborrow; +use futures::TryFutureExt; -use crate::pac::usart::{regs, vals}; use super::*; use crate::dma::NoDma; +use crate::pac::usart::{regs, vals}; pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { inner: T, From ae948415a79937c30ff5774b2483926287dad962 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 15 Jul 2021 15:34:48 +0200 Subject: [PATCH 05/13] stm32/dma: disable after finishing --- embassy-stm32/src/dma/bdma.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 37bd24d0..c6e77488 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -99,8 +99,6 @@ pub(crate) async unsafe fn do_transfer( }) .await; - on_drop.defuse(); - // TODO handle error assert!(res == CH_STATUS_COMPLETED); } From 1254e99be12b8a2520b46936a016480d5f689dd7 Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Fri, 16 Jul 2021 13:51:53 -0400 Subject: [PATCH 06/13] Be able to scrub out BDMA-centric IRQs. Further refine distinction between DMA and BDMA interrupts in the table. --- stm32-metapac-gen/src/lib.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index a9ee8800..3cfb884c 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -284,6 +284,9 @@ pub fn gen(options: Options) { let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); + let mut has_bdma = false; + let mut has_dma = false; + for (name, p) in &core.peripherals { let captures = number_suffix_re.captures(&name).unwrap(); let root_peri_name = captures.get(1).unwrap().as_str().to_string(); @@ -303,6 +306,12 @@ pub fn gen(options: Options) { if let Some(block) = &p.block { let bi = BlockInfo::parse(block); + if bi.module == "bdma" { + has_bdma = true + } else if bi.module == "dma" { + has_dma = true + } + peripheral_counts.insert( bi.module.clone(), peripheral_counts.get(&bi.module).map_or(1, |v| v + 1), @@ -522,8 +531,16 @@ pub fn gen(options: Options) { interrupt_table.push(vec![name.clone()]); - if name.starts_with("DMA") || name.contains("_DMA") { - interrupt_table.push(vec!["DMA".to_string(), name.clone()]); + if name.starts_with("DMA1_") || name.starts_with("DMA2_") || name.contains("_DMA") { + if has_dma { + interrupt_table.push(vec!["DMA".to_string(), name.clone()]); + } else if has_bdma { + interrupt_table.push(vec!["BDMA".to_string(), name.clone()]); + } + } + + if name.starts_with("BDMA_") || name.starts_with("BDMA1_") || name.starts_with("BDMA2_") { + interrupt_table.push(vec!["BDMA".to_string(), name.clone()]); } if name.contains("EXTI") { From 0119ea809dba3a0b002174f615650a5a8fd9c22e Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Fri, 16 Jul 2021 14:40:25 -0400 Subject: [PATCH 07/13] Get DMA on H7 working, add usart_dma example for H7. --- embassy-stm32/src/dma/bdma.rs | 45 +----------- embassy-stm32/src/dma/dma.rs | 13 +++- examples/stm32h7/src/bin/usart_dma.rs | 100 ++++++++++++++++++++++++++ stm32-data | 2 +- 4 files changed, 115 insertions(+), 45 deletions(-) create mode 100644 examples/stm32h7/src/bin/usart_dma.rs diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index c6e77488..26adda08 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -139,7 +139,7 @@ unsafe fn on_irq() { /// safety: must be called only once pub(crate) unsafe fn init() { pac::interrupts! { - (DMA, $irq:ident) => { + (BDMA, $irq:ident) => { crate::interrupt::$irq::steal().enable(); }; } @@ -209,52 +209,11 @@ pac::bdma_channels! { }; } -// HACK: on stm32h7 "DMA" interrupts are for DMA, not BDMA, so this -// would cause duplicate interrupt definitions. Do it manually insted -#[cfg(not(rcc_h7))] pac::interrupts! { - (DMA, $irq:ident) => { + (BDMA, $irq:ident) => { #[crate::interrupt] unsafe fn $irq () { on_irq() } }; } - -#[cfg(rcc_h7)] -mod _if_h7 { - use super::*; - - #[crate::interrupt] - unsafe fn BDMA_CHANNEL0() { - on_irq() - } - #[crate::interrupt] - unsafe fn BDMA_CHANNEL1() { - on_irq() - } - #[crate::interrupt] - unsafe fn BDMA_CHANNEL2() { - on_irq() - } - #[crate::interrupt] - unsafe fn BDMA_CHANNEL3() { - on_irq() - } - #[crate::interrupt] - unsafe fn BDMA_CHANNEL4() { - on_irq() - } - #[crate::interrupt] - unsafe fn BDMA_CHANNEL5() { - on_irq() - } - #[crate::interrupt] - unsafe fn BDMA_CHANNEL6() { - on_irq() - } - #[crate::interrupt] - unsafe fn BDMA_CHANNEL7() { - on_irq() - } -} diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index b0df6ddc..1d6f7aee 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -3,7 +3,7 @@ use core::task::Poll; use atomic_polyfill::{AtomicU8, Ordering}; use core::future::Future; use embassy::interrupt::{Interrupt, InterruptExt}; -use embassy::util::AtomicWaker; +use embassy::util::{AtomicWaker, OnDrop}; use futures::future::poll_fn; use crate::interrupt; @@ -38,6 +38,7 @@ static STATE: State = State::new(); //async unsafe fn do_transfer(ch: &mut impl Channel, ch_func: u8, src: *const u8, dst: &mut [u8]) { +#[allow(unused)] pub(crate) async unsafe fn do_transfer( dma: pac::dma::Dma, channel_number: u8, @@ -59,6 +60,15 @@ pub(crate) async unsafe fn do_transfer( let ch = dma.st(channel_number as _); + let on_drop = OnDrop::new(|| unsafe { + ch.cr().modify(|w| { + w.set_tcie(false); + w.set_teie(false); + w.set_en(false); + }); + while ch.cr().read().en() {} + }); + #[cfg(dmamux)] super::dmamux::configure_dmamux(dmamux_regs, dmamux_ch_num, request); @@ -74,6 +84,7 @@ pub(crate) async unsafe fn do_transfer( w.set_pinc(vals::Inc::FIXED); w.set_teie(true); w.set_tcie(true); + w.set_trbuff(true); w.set_en(true); #[cfg(dma_v2)] diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs new file mode 100644 index 00000000..fd5da8b3 --- /dev/null +++ b/examples/stm32h7/src/bin/usart_dma.rs @@ -0,0 +1,100 @@ +#![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 embassy::executor::Executor; +use embassy::time::Clock; +use embassy::util::Forever; +use embassy_stm32::dma::NoDma; +use embassy_stm32::usart::{Config, Uart}; +use example_common::*; +use embassy_traits::uart::Write as _Write; + +use hal::prelude::*; +use stm32h7xx_hal as hal; + +use cortex_m_rt::entry; +use stm32h7::stm32h743 as pac; +use heapless::String; + +#[embassy::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_0, NoDma, 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(s.as_bytes()).await.ok(); + + 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(); + + let pwrcfg = pp.PWR.constrain().freeze(); + + let rcc = pp.RCC.constrain(); + + rcc.sys_ck(96.mhz()) + .pclk1(48.mhz()) + .pclk2(48.mhz()) + .pclk3(48.mhz()) + .pclk4(48.mhz()) + .pll1_q_ck(48.mhz()) + .freeze(pwrcfg, &pp.SYSCFG); + + let pp = unsafe { pac::Peripherals::steal() }; + + pp.DBGMCU.cr.modify(|_, w| { + w.dbgsleep_d1().set_bit(); + w.dbgstby_d1().set_bit(); + w.dbgstop_d1().set_bit(); + w.d1dbgcken().set_bit(); + w + }); + + pp.RCC.ahb4enr.modify(|_, w| { + w.gpioaen().set_bit(); + w.gpioben().set_bit(); + w.gpiocen().set_bit(); + w.gpioden().set_bit(); + w.gpioeen().set_bit(); + w.gpiofen().set_bit(); + w + }); + + unsafe { embassy::time::set_clock(&ZeroClock) }; + + let executor = EXECUTOR.put(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} diff --git a/stm32-data b/stm32-data index 32ca7902..ddd0f206 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 32ca79020ec7523fe4c3fcfc02006cb1ea637a19 +Subproject commit ddd0f206e22143436230dca6d3fcfc0e02e55dfd From 01cc733c615a3d72cee3ba761950c9c607318c6e Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Fri, 16 Jul 2021 15:44:22 -0400 Subject: [PATCH 08/13] Prep for new stm32-data with dmamux differentiation, but not yet using. --- stm32-data | 2 +- stm32-metapac-gen/src/lib.rs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/stm32-data b/stm32-data index ddd0f206..d285fced 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit ddd0f206e22143436230dca6d3fcfc0e02e55dfd +Subproject commit d285fced6573703be875436409f8c83dd80ae183 diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 3cfb884c..ff919d8b 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -50,7 +50,7 @@ pub struct Peripheral { #[serde(default)] pub dma_channels: HashMap>, #[serde(default)] - pub dma_requests: HashMap, + pub dma_requests: HashMap, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] @@ -72,6 +72,12 @@ pub struct PeripheralDmaChannel { pub request: Option, } +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)] +pub struct PeripheralDmaRequest { + pub dmamux: String, + pub request: u32, +} + struct BlockInfo { /// usart_v1/USART -> usart module: String, @@ -335,7 +341,8 @@ pub fn gen(options: Options) { row.push(bi.module.clone()); row.push(name.clone()); row.push(dma_request.0.clone()); - row.push(dma_request.1.to_string()); + row.push(dma_request.1.request.to_string()); + // TODO add the `dmamux` column dma_requests_table.push(row); } From dff4b42a33aa4d7c6a21bcd5017249f4de5c44b1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 15 Jul 2021 21:40:08 +0200 Subject: [PATCH 09/13] stm32/dma: Fix macrotable column count not matching in DMAMUX-less BDMAv1. --- stm32-metapac-gen/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index ff919d8b..5c2d605b 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -358,6 +358,8 @@ pub fn gen(options: Options) { row.push(core.dma_channels[&channel.channel].channel.to_string()); if let Some(request) = channel.request { row.push(request.to_string()); + } else { + row.push("()".to_string()); } peripheral_dma_channels_table.push(row); } From 54b5012c568f5b952fefe50ad6a032b54172dabd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Jul 2021 07:35:59 +0200 Subject: [PATCH 10/13] stm32/dma: update codegen+macrotables for new stm32-data --- embassy-stm32/src/dma/bdma.rs | 4 +- embassy-stm32/src/dma/dma.rs | 2 +- embassy-stm32/src/dma/dmamux.rs | 35 ++------------ embassy-stm32/src/usart/mod.rs | 26 +++------- stm32-data | 2 +- stm32-metapac-gen/src/lib.rs | 84 ++++++++++++--------------------- 6 files changed, 42 insertions(+), 111 deletions(-) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 26adda08..3d9ff9eb 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -150,8 +150,8 @@ pub(crate) unsafe fn init() { } } -pac::bdma_channels! { - ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { +pac::dma_channels! { + ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $dmamux:tt) => { impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {} impl Channel for crate::peripherals::$channel_peri { diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 1d6f7aee..9b1c1160 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -153,7 +153,7 @@ pub(crate) unsafe fn init() { } pac::dma_channels! { - ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $dmamux:tt) => { impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {} impl Channel for crate::peripherals::$channel_peri { diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index e9fa4823..186ec247 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs @@ -24,40 +24,11 @@ pub(crate) trait MuxChannel { const DMAMUX_REGS: pac::dmamux::Dmamux; } -macro_rules! dma_num { - (DMA1) => { - 0 - }; - (DMA2) => { - 1 - }; -} - -#[cfg(not(rcc_h7))] -pac::bdma_channels! { - ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { - impl MuxChannel for peripherals::$channel_peri { - const DMAMUX_CH_NUM: u8 = (dma_num!($dma_peri) * 8) + $channel_num; - const DMAMUX_REGS: pac::dmamux::Dmamux = pac::DMAMUX1; - } - }; -} - -#[cfg(rcc_h7)] pac::dma_channels! { - ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { + ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => { impl MuxChannel for peripherals::$channel_peri { - const DMAMUX_CH_NUM: u8 = (dma_num!($dma_peri) * 8) + $channel_num; - const DMAMUX_REGS: pac::dmamux::Dmamux = pac::DMAMUX1; - } - }; -} -#[cfg(rcc_h7)] -pac::bdma_channels! { - ($channel_peri:ident, $dma_peri:ident, $channel_num:expr) => { - impl MuxChannel for peripherals::$channel_peri { - const DMAMUX_CH_NUM: u8 = $channel_num; - const DMAMUX_REGS: pac::dmamux::Dmamux = pac::DMAMUX2; + const DMAMUX_CH_NUM: u8 = $dmamux_channel; + const DMAMUX_REGS: pac::dmamux::Dmamux = pac::$dmamux; } }; } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index bf6fa913..92021d0a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -171,7 +171,7 @@ crate::pac::peripheral_pins!( ); macro_rules! impl_dma { - ($inst:ident, ALL, $signal:ident, $request:expr) => { + ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => { impl sealed::$signal for T { fn request(&self) -> dma::Request { $request @@ -180,7 +180,7 @@ macro_rules! impl_dma { impl $signal for T {} }; - ($inst:ident, $channel:ident, $signal:ident, $request:expr) => { + ($inst:ident, {channel: $channel:ident}, $signal:ident, $request:expr) => { impl sealed::$signal for peripherals::$channel { fn request(&self) -> dma::Request { $request @@ -192,30 +192,16 @@ macro_rules! impl_dma { } crate::pac::peripheral_dma_channels! { - ($peri:ident, usart, $kind:ident, RX, $channel:ident, $dma_peri:ident, $channel_num:expr, $request:expr) => { + ($peri:ident, usart, $kind:ident, RX, $channel:tt, $request:expr) => { impl_dma!($peri, $channel, RxDma, $request); }; - ($peri:ident, usart, $kind:ident, TX, $channel:ident, $dma_peri:ident, $channel_num:expr, $request:expr) => { + ($peri:ident, usart, $kind:ident, TX, $channel:tt, $request:expr) => { impl_dma!($peri, $channel, TxDma, $request); }; - ($peri:ident, uart, $kind:ident, RX, $channel:ident, $dma_peri:ident, $channel_num:expr, $request:expr) => { + ($peri:ident, uart, $kind:ident, RX, $channel:tt, $request:expr) => { impl_dma!($peri, $channel, RxDma, $request); }; - ($peri:ident, uart, $kind:ident, TX, $channel:ident, $dma_peri:ident, $channel_num:expr, $request:expr) => { + ($peri:ident, uart, $kind:ident, TX, $channel:tt, $request:expr) => { impl_dma!($peri, $channel, TxDma, $request); }; } -crate::pac::dma_requests! { - (usart, $peri:ident, RX, $request:expr) => { - impl_dma!($peri, ALL, RxDma, $request); - }; - (usart, $peri:ident, TX, $request:expr) => { - impl_dma!($peri, ALL, TxDma, $request); - }; - (uart, $peri:ident, RX, $request:expr) => { - impl_dma!($peri, ALL, RxDma, $request); - }; - (uart, $peri:ident, TX, $request:expr) => { - impl_dma!($peri, ALL, TxDma, $request); - }; -} diff --git a/stm32-data b/stm32-data index d285fced..8702a3a3 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit d285fced6573703be875436409f8c83dd80ae183 +Subproject commit 8702a3a3bb83a59515dab2cf9f75952fa6edae8a diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 5c2d605b..fee99111 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -49,8 +49,6 @@ pub struct Peripheral { pub pins: Vec, #[serde(default)] pub dma_channels: HashMap>, - #[serde(default)] - pub dma_requests: HashMap, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] @@ -64,20 +62,17 @@ pub struct Pin { pub struct DmaChannel { pub dma: String, pub channel: u32, + pub dmamux: Option, + pub dmamux_channel: Option, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)] pub struct PeripheralDmaChannel { - pub channel: String, + pub channel: Option, + pub dmamux: Option, pub request: Option, } -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)] -pub struct PeripheralDmaRequest { - pub dmamux: String, - pub request: u32, -} - struct BlockInfo { /// usart_v1/USART -> usart module: String, @@ -272,19 +267,10 @@ 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(); let mut dma_channel_counts: HashMap = HashMap::new(); - let dma_base = core - .peripherals - .get(&"DMA".to_string()) - .unwrap_or_else(|| core.peripherals.get(&"DMA1".to_string()).unwrap()) - .address; - let dma_stride = 0x400; - let gpio_base = core.peripherals.get(&"GPIOA".to_string()).unwrap().address; let gpio_stride = 0x400; @@ -336,26 +322,20 @@ pub fn gen(options: Options) { peripheral_pins_table.push(row); } - for dma_request in &p.dma_requests { - let mut row = Vec::new(); - row.push(bi.module.clone()); - row.push(name.clone()); - row.push(dma_request.0.clone()); - row.push(dma_request.1.request.to_string()); - // TODO add the `dmamux` column - dma_requests_table.push(row); - } - - for (event, dma_channels) in &p.dma_channels { + for (request, dma_channels) in &p.dma_channels { for channel in dma_channels.iter() { let mut row = Vec::new(); row.push(name.clone()); row.push(bi.module.clone()); row.push(bi.block.clone()); - row.push(event.clone()); - row.push(channel.channel.clone()); - row.push(core.dma_channels[&channel.channel].dma.clone()); - row.push(core.dma_channels[&channel.channel].channel.to_string()); + row.push(request.clone()); + if let Some(channel) = &channel.channel { + row.push(format!("{{channel: {}}}", channel)); + } else if let Some(dmamux) = &channel.dmamux { + row.push(format!("{{dmamux: {}}}", dmamux)); + } else { + unreachable!(); + } if let Some(request) = channel.request { row.push(request.to_string()); } else { @@ -399,15 +379,6 @@ pub fn gen(options: Options) { ]); } } - "dma" => { - let dma_num = if name == "DMA" { - 0 - } else { - let dma_letter = name.chars().skip(3).next().unwrap(); - dma_letter as u32 - '1' as u32 - }; - assert_eq!(p.address, dma_base + dma_stride * dma_num); - } _ => {} } @@ -507,21 +478,25 @@ pub fn gen(options: Options) { for (id, channel_info) in &core.dma_channels { let mut row = Vec::new(); - let dma_peri = core.peripherals.get(&channel_info.dma); + let dma_peri = core.peripherals.get(&channel_info.dma).unwrap(); + let bi = BlockInfo::parse(dma_peri.block.as_ref().unwrap()); + row.push(id.clone()); row.push(channel_info.dma.clone()); + row.push(bi.module.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); - } - } + if let Some(dmamux) = &channel_info.dmamux { + let dmamux_channel = channel_info.dmamux_channel.unwrap(); + row.push(format!( + "{{dmamux: {}, dmamux_channel: {}}}", + dmamux, dmamux_channel + )); + } else { + row.push("{}".to_string()); } + dma_channels_table.push(row); + let dma_peri_name = channel_info.dma.clone(); dma_channel_counts.insert( dma_peri_name.clone(), @@ -548,7 +523,8 @@ pub fn gen(options: Options) { } } - if name.starts_with("BDMA_") || name.starts_with("BDMA1_") || name.starts_with("BDMA2_") { + if name.starts_with("BDMA_") || name.starts_with("BDMA1_") || name.starts_with("BDMA2_") + { interrupt_table.push(vec!["BDMA".to_string(), name.clone()]); } @@ -583,8 +559,6 @@ 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); make_dma_channel_counts(&mut extra, &dma_channel_counts); From 3655048e0f8238dc64425ff79d9cf951b9b1f340 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Jul 2021 07:49:49 +0200 Subject: [PATCH 11/13] stm32/dma: add MuxChannel trait to distinguish DMAMUX1 and DMAMUX2 channels. --- embassy-stm32/src/dma/bdma.rs | 8 ++++---- embassy-stm32/src/dma/dma.rs | 8 ++++---- embassy-stm32/src/dma/dmamux.rs | 22 ++++++++++++++++++---- embassy-stm32/src/dma/mod.rs | 3 +++ embassy-stm32/src/usart/mod.rs | 10 ++++++++-- 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 3d9ff9eb..4c26a950 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -175,9 +175,9 @@ pac::dma_channels! { buf.as_mut_ptr(), buf.len(), #[cfg(dmamux)] - ::DMAMUX_REGS, + ::DMAMUX_REGS, #[cfg(dmamux)] - ::DMAMUX_CH_NUM, + ::DMAMUX_CH_NUM, ) } } @@ -199,9 +199,9 @@ pac::dma_channels! { buf.as_ptr() as *mut u8, buf.len(), #[cfg(dmamux)] - ::DMAMUX_REGS, + ::DMAMUX_REGS, #[cfg(dmamux)] - ::DMAMUX_CH_NUM, + ::DMAMUX_CH_NUM, ) } } diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 9b1c1160..75fc1403 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -177,9 +177,9 @@ pac::dma_channels! { buf.as_mut_ptr(), buf.len(), #[cfg(dmamux)] - ::DMAMUX_REGS, + ::DMAMUX_REGS, #[cfg(dmamux)] - ::DMAMUX_CH_NUM, + ::DMAMUX_CH_NUM, ) } } @@ -201,9 +201,9 @@ pac::dma_channels! { buf.as_ptr() as *mut u8, buf.len(), #[cfg(dmamux)] - ::DMAMUX_REGS, + ::DMAMUX_REGS, #[cfg(dmamux)] - ::DMAMUX_CH_NUM, + ::DMAMUX_CH_NUM, ) } } diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 186ec247..718859a4 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs @@ -19,17 +19,31 @@ pub(crate) unsafe fn configure_dmamux( }); } -pub(crate) trait MuxChannel { - const DMAMUX_CH_NUM: u8; - const DMAMUX_REGS: pac::dmamux::Dmamux; +pub(crate) mod sealed { + use super::*; + pub trait MuxChannel { + const DMAMUX_CH_NUM: u8; + const DMAMUX_REGS: pac::dmamux::Dmamux; + } +} + +pub struct DMAMUX1; +#[cfg(rcc_h7)] +pub struct DMAMUX2; + +pub trait MuxChannel: sealed::MuxChannel + super::Channel { + type Mux; } pac::dma_channels! { ($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, {dmamux: $dmamux:ident, dmamux_channel: $dmamux_channel:expr}) => { - impl MuxChannel for peripherals::$channel_peri { + impl sealed::MuxChannel for peripherals::$channel_peri { const DMAMUX_CH_NUM: u8 = $dmamux_channel; const DMAMUX_REGS: pac::dmamux::Dmamux = pac::$dmamux; } + impl MuxChannel for peripherals::$channel_peri { + type Mux = $dmamux; + } }; } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index ebad3d7b..fbf82b87 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -5,6 +5,9 @@ mod dma; #[cfg(dmamux)] mod dmamux; +#[cfg(dmamux)] +pub use dmamux::*; + use core::future::Future; use embassy::util::Unborrow; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 92021d0a..9df00d3a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -172,13 +172,19 @@ crate::pac::peripheral_pins!( macro_rules! impl_dma { ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => { - impl sealed::$signal for T { + impl sealed::$signal for T + where + T: crate::dma::MuxChannel, + { fn request(&self) -> dma::Request { $request } } - impl $signal for T {} + impl $signal for T where + T: crate::dma::MuxChannel + { + } }; ($inst:ident, {channel: $channel:ident}, $signal:ident, $request:expr) => { impl sealed::$signal for peripherals::$channel { From 36be877ba3dc102150c59fb3ad58adf28172f4b8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Jul 2021 08:01:20 +0200 Subject: [PATCH 12/13] stm32/dma: only set TRBUFF in DMAv1 (H7) --- embassy-stm32/src/dma/dma.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 75fc1403..591279ef 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -84,6 +84,7 @@ pub(crate) async unsafe fn do_transfer( w.set_pinc(vals::Inc::FIXED); w.set_teie(true); w.set_tcie(true); + #[cfg(dma_v1)] w.set_trbuff(true); w.set_en(true); From d7176da37c372d8a57283af540f4fecb532540aa Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Jul 2021 08:04:33 +0200 Subject: [PATCH 13/13] stm32/examples: update DMA channel names --- examples/stm32f4/src/bin/usart_dma.rs | 2 +- examples/stm32h7/src/bin/usart_dma.rs | 2 +- examples/stm32l4/src/bin/usart_dma.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index 39e199d5..b578aebc 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs @@ -25,7 +25,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_3, NoDma, config); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs index fd5da8b3..0073d5c6 100644 --- a/examples/stm32h7/src/bin/usart_dma.rs +++ b/examples/stm32h7/src/bin/usart_dma.rs @@ -29,7 +29,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_0, NoDma, config); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 12857bc7..e325e3da 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs @@ -25,7 +25,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_3, NoDma, config); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config); for n in 0u32.. { let mut s: String<128> = String::new();