From 3d1391ef2d634ca6a90c68be7cc69af02e3dc33b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 15 Jul 2021 05:42:06 +0200 Subject: [PATCH] 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 _;