diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 9f88c1141..0bce37e48 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -9,7 +9,7 @@ use crate::interrupt; use crate::pac; use crate::pac::dma::{regs, vals}; -use super::{Request, Word, WordSize}; +use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize}; impl From for vals::Size { fn from(raw: WordSize) -> Self { @@ -21,6 +21,26 @@ impl From for vals::Size { } } +impl From for vals::Burst { + fn from(burst: Burst) -> Self { + match burst { + Burst::Single => vals::Burst::SINGLE, + Burst::Incr4 => vals::Burst::INCR4, + Burst::Incr8 => vals::Burst::INCR8, + Burst::Incr16 => vals::Burst::INCR16, + } + } +} + +impl From for vals::Pfctrl { + fn from(flow: FlowControl) -> Self { + match flow { + FlowControl::Dma => vals::Pfctrl::DMA, + FlowControl::Peripheral => vals::Pfctrl::PERIPHERAL, + } + } +} + struct State { ch_wakers: [AtomicWaker; DMA_CHANNEL_COUNT], } @@ -49,7 +69,7 @@ pub(crate) unsafe fn init() { foreach_dma_channel! { ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => { impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { - unsafe fn start_write(&mut self, request: Request, buf: *const [W], reg_addr: *mut W) { + unsafe fn start_write(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) { let (ptr, len) = super::slice_ptr_parts(buf); low_level_api::start_transfer( pac::$dma_peri, @@ -61,6 +81,7 @@ foreach_dma_channel! { len, true, vals::Size::from(W::bits()), + options, #[cfg(dmamux)] ::DMAMUX_REGS, #[cfg(dmamux)] @@ -68,7 +89,7 @@ foreach_dma_channel! { ) } - unsafe fn start_write_repeated(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W) { + unsafe fn start_write_repeated(&mut self, request: Request, repeated: W, count: usize, reg_addr: *mut W, options: TransferOptions) { let buf = [repeated]; low_level_api::start_transfer( pac::$dma_peri, @@ -80,6 +101,7 @@ foreach_dma_channel! { count, false, vals::Size::from(W::bits()), + options, #[cfg(dmamux)] ::DMAMUX_REGS, #[cfg(dmamux)] @@ -87,7 +109,7 @@ foreach_dma_channel! { ) } - unsafe fn start_read(&mut self, request: Request, reg_addr: *const W, buf: *mut [W]) { + unsafe fn start_read(&mut self, request: Request, reg_addr: *const W, buf: *mut [W], options: TransferOptions) { let (ptr, len) = super::slice_ptr_parts_mut(buf); low_level_api::start_transfer( pac::$dma_peri, @@ -99,6 +121,7 @@ foreach_dma_channel! { len, true, vals::Size::from(W::bits()), + options, #[cfg(dmamux)] ::DMAMUX_REGS, #[cfg(dmamux)] @@ -146,6 +169,7 @@ mod low_level_api { mem_len: usize, incr_mem: bool, data_size: vals::Size, + options: TransferOptions, #[cfg(dmamux)] dmamux_regs: pac::dmamux::Dmamux, #[cfg(dmamux)] dmamux_ch_num: u8, ) { @@ -180,6 +204,10 @@ mod low_level_api { #[cfg(dma_v2)] w.set_chsel(request); + w.set_pburst(options.pburst.into()); + w.set_mburst(options.mburst.into()); + w.set_pfctrl(options.flow_ctrl.into()); + w.set_en(true); }); } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 4768a448c..f5b05589b 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -46,6 +46,7 @@ pub(crate) mod sealed { request: Request, buf: *const [W], reg_addr: *mut W, + options: TransferOptions, ); /// Starts this channel for writing a word repeatedly. @@ -58,6 +59,7 @@ pub(crate) mod sealed { repeated: W, count: usize, reg_addr: *mut W, + options: TransferOptions, ); /// Starts this channel for reading a stream of words. @@ -71,6 +73,7 @@ pub(crate) mod sealed { request: Request, reg_addr: *const W, buf: *mut [W], + options: TransferOptions, ); /// Requests the channel to stop. @@ -126,6 +129,43 @@ impl Word for u32 { } } +pub enum Burst { + /// Single transfer + Single, + /// Incremental burst of 4 beats + Incr4, + /// Incremental burst of 8 beats + Incr8, + /// Incremental burst of 16 beats + Incr16, +} + +pub enum FlowControl { + /// Flow control by DMA + Dma, + /// Flow control by peripheral + Peripheral, +} + +pub struct TransferOptions { + /// Peripheral burst transfer configuration + pub pburst: Burst, + /// Memory burst transfer configuration + pub mburst: Burst, + /// Flow control configuration + pub flow_ctrl: FlowControl, +} + +impl Default for TransferOptions { + fn default() -> Self { + Self { + pburst: Burst::Single, + mburst: Burst::Single, + flow_ctrl: FlowControl::Dma, + } + } +} + mod transfers { use super::*; @@ -139,7 +179,7 @@ mod transfers { assert!(buf.len() > 0 && buf.len() <= 0xFFFF); unborrow!(channel); - unsafe { channel.start_read::(request, reg_addr, buf) }; + unsafe { channel.start_read::(request, reg_addr, buf, Default::default()) }; Transfer::new(channel) } @@ -154,7 +194,7 @@ mod transfers { assert!(buf.len() > 0 && buf.len() <= 0xFFFF); unborrow!(channel); - unsafe { channel.start_write::(request, buf, reg_addr) }; + unsafe { channel.start_write::(request, buf, reg_addr, Default::default()) }; Transfer::new(channel) } @@ -169,7 +209,15 @@ mod transfers { ) -> impl Future + 'a { unborrow!(channel); - unsafe { channel.start_write_repeated::(request, repeated, count, reg_addr) }; + unsafe { + channel.start_write_repeated::( + request, + repeated, + count, + reg_addr, + Default::default(), + ) + }; Transfer::new(channel) }