From c53ab325c1943ef4f2f4890734444930a585531d Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Tue, 29 Jun 2021 10:59:22 -0400 Subject: [PATCH] Wire up DMA with USART v1. --- embassy-stm32/src/dma/mod.rs | 12 ++++- embassy-stm32/src/dma/v2.rs | 91 +++++++++++++++++++++++++++++---- embassy-stm32/src/rcc/f4/mod.rs | 4 +- embassy-stm32/src/usart/mod.rs | 5 +- embassy-stm32/src/usart/v1.rs | 27 ++++------ 5 files changed, 107 insertions(+), 32 deletions(-) diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index a8a22ce8..371741ff 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -1,6 +1,6 @@ #![macro_use] -//#[cfg_attr(dma_v1, path = "v1.rs")] +#[cfg_attr(dma_v1, path = "v1.rs")] #[cfg_attr(dma_v2, path = "v2.rs")] mod _version; @@ -19,4 +19,12 @@ pub trait WriteDma { T: 'a; } -pub trait ReadDma {} +pub trait ReadDma { + type ReadDmaFuture<'a>: Future + 'a + where + Self: 'a; + + fn transfer<'a>(&'a mut self, src: *const u8, buf: &'a mut [u8]) -> Self::ReadDmaFuture<'a> + where + T: 'a; +} diff --git a/embassy-stm32/src/dma/v2.rs b/embassy-stm32/src/dma/v2.rs index 6c6bbde2..4cce1adf 100644 --- a/embassy-stm32/src/dma/v2.rs +++ b/embassy-stm32/src/dma/v2.rs @@ -39,6 +39,52 @@ impl State { 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 + STATE.ch_status[n].store(CH_STATUS_NONE, Ordering::Relaxed); + + 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::Relaxed) { + 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, @@ -75,7 +121,10 @@ pub(crate) async unsafe fn transfer_m2p( let res = poll_fn(|cx| { STATE.ch_wakers[n].register(cx.waker()); match STATE.ch_status[n].load(Ordering::Relaxed) { - CH_STATUS_NONE => Poll::Pending, + CH_STATUS_NONE => { + let left = c.ndtr().read().ndt(); + Poll::Pending + } x => Poll::Ready(x), } }) @@ -137,14 +186,14 @@ pub(crate) mod sealed { } } - pub trait PeripheralChannel: Channel { + 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 {} +pub trait PeripheralChannel: sealed::PeripheralChannel + Sized {} macro_rules! impl_dma { ($peri:ident, $num:expr) => { @@ -180,7 +229,7 @@ macro_rules! impl_dma_channel { impl WriteDma for peripherals::$channel_peri where - Self: sealed::PeripheralChannel, + Self: sealed::PeripheralChannel, T: 'static, { type WriteDmaFuture<'a> = impl Future; @@ -189,10 +238,30 @@ macro_rules! impl_dma_channel { where T: 'a, { - let request = sealed::PeripheralChannel::::request(self); + 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) } + } + } }; } @@ -217,12 +286,16 @@ peripherals! { 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! { @@ -230,25 +303,25 @@ peripheral_dma_channels! { impl usart::RxDma for peripherals::$channel_peri { } impl usart::sealed::RxDma for peripherals::$channel_peri { } - impl sealed::PeripheralChannel for peripherals::$channel_peri { + impl sealed::PeripheralChannel for peripherals::$channel_peri { fn request(&self) -> u8 { $event_num } } - impl PeripheralChannel for peripherals::$channel_peri { } + 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 { + impl sealed::PeripheralChannel for peripherals::$channel_peri { fn request(&self) -> u8 { $event_num } } - impl PeripheralChannel for peripherals::$channel_peri { } + impl PeripheralChannel for peripherals::$channel_peri { } }; } diff --git a/embassy-stm32/src/rcc/f4/mod.rs b/embassy-stm32/src/rcc/f4/mod.rs index 4b17bdf4..6000192b 100644 --- a/embassy-stm32/src/rcc/f4/mod.rs +++ b/embassy-stm32/src/rcc/f4/mod.rs @@ -132,7 +132,7 @@ impl RccExt for RCC { ClockSrc::HSI16 => { // Enable HSI16 unsafe { - rcc.cr().write(|w| w.set_hsion(true)); + rcc.cr().modify(|w| w.set_hsion(true)); while !rcc.cr().read().hsirdy() {} } @@ -141,7 +141,7 @@ impl RccExt for RCC { ClockSrc::HSE(freq) => { // Enable HSE unsafe { - rcc.cr().write(|w| w.set_hseon(true)); + rcc.cr().modify(|w| w.set_hseon(true)); while !rcc.cr().read().hserdy() {} } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 24793b6b..08be583c 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1,13 +1,14 @@ #![macro_use] #[cfg_attr(usart_v1, path = "v1.rs")] -//#[cfg_attr(usart_v2, path = "v2.rs")] +#[cfg_attr(usart_v2, path = "v2.rs")] mod _version; use crate::peripherals; pub use _version::*; use crate::gpio::Pin; use crate::pac::usart::Usart; +use crate::rcc::RccPeripheral; /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] @@ -51,7 +52,7 @@ pub(crate) mod sealed { pub trait TxDma: WriteDma {} } -pub trait Instance: sealed::Instance {} +pub trait Instance: sealed::Instance + RccPeripheral {} pub trait RxPin: sealed::RxPin {} pub trait TxPin: sealed::TxPin {} pub trait CtsPin: sealed::CtsPin {} diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs index a721e89a..1f05dc9a 100644 --- a/embassy-stm32/src/usart/v1.rs +++ b/embassy-stm32/src/usart/v1.rs @@ -63,14 +63,17 @@ impl<'d, T: Instance> Uart<'d, T> { rx: impl Unborrow>, tx: impl Unborrow>, config: Config, - pclk_freq: u32, + //pclk_freq: u32, ) -> Self { unborrow!(inner, rx, tx); + let pclk_freq = T::frequency(); + //let pclk_freq = 16_000_000; + // TODO: enable in RCC // TODO: better calculation, including error checking and OVER8 if possible. - let div = (pclk_freq + (config.baudrate / 2)) / config.baudrate; + let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate; let r = inner.regs(); @@ -108,25 +111,15 @@ impl<'d, T: Instance> Uart<'d, T> { ch: &mut impl TxDma, buffer: &[u8], ) -> Result<(), Error> { + unsafe { + self.inner.regs().cr3().modify(|reg| { + reg.set_dmat(true); + }); + } let r = self.inner.regs(); let dst = r.dr().ptr() as *mut u8; ch.transfer(buffer, dst).await; Ok(()) - /* - let ch_func = 4; // USART3_TX - - unsafe { - r.cr3().write(|w| { - w.set_dmat(true); - }); - - let dst = r.dr().ptr() as *mut u8; - - crate::dma::transfer_m2p(ch, ch_func, buffer, dst).await; - } - - Ok(()) - */ } pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {