From c86a0f5bd0ebfcca09e009fab547f407f8d2da2d Mon Sep 17 00:00:00 2001 From: Fabian Wolter Date: Sun, 15 Dec 2024 20:15:11 +0100 Subject: [PATCH] STM32F0/F3 Remap DMA channels Fixes #3643 --- embassy-stm32/build.rs | 59 ++++++++++++++++++++++++++++++++++++- embassy-stm32/src/macros.rs | 14 ++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index f92d8b8ba5..9e9d9b8ae6 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1238,6 +1238,27 @@ fn main() { // ======== // Generate dma_trait_impl! + let syscfg_peripheral = METADATA + .peripherals + .iter() + .find(|p| p.name.eq_ignore_ascii_case("syscfg")) + .unwrap(); + + let syscfg_ir = syscfg_peripheral.registers.as_ref().unwrap().ir; + + let cfgr1_offset = syscfg_ir + .blocks + .iter() + .find(|b| b.name.eq_ignore_ascii_case("syscfg")) + .unwrap() + .items + .iter() + .find(|i| i.name.eq_ignore_ascii_case("cfgr1")) + .unwrap() + .byte_offset; + + let cfgr1 = syscfg_peripheral.address as u32 + cfgr1_offset; + let signals: HashMap<_, _> = [ // (kind, signal) => trait (("adc", "ADC"), quote!(crate::adc::RxDma)), @@ -1329,9 +1350,45 @@ fn main() { quote!(()) }; + let remap = ch.remap.map_or(quote! { () }, |remap| { + let fields: Vec<_> = syscfg_ir + .fieldsets + .iter() + .find(|i| i.name.eq_ignore_ascii_case("cfgr1")) + .unwrap() + .fields + .iter() + .filter(|f| { + let field_name = f.name.to_lowercase(); + field_name.contains("dma_rmp") + && field_name.contains(p.name.to_lowercase().as_str()) + }) + .collect(); + + let remap_field = if fields.len() == 1 { + fields.first().unwrap() + } else { + fields + .iter() + .find(|f| f.name.contains(ch.signal.to_lowercase().as_str())) + .unwrap() + }; + + let BitOffset::Regular(ref bit_offset) = remap_field.bit_offset else { + panic!("cursed bit offset") + }; + let bit_offset: u8 = bit_offset.offset.try_into().unwrap(); + + if remap { + quote! { (#cfgr1 as *mut u32).write((#cfgr1 as *mut u32).read() | 1 << #bit_offset) } + } else { + quote! { (#cfgr1 as *mut u32).write((#cfgr1 as *mut u32).read() & !(1 << #bit_offset)) } + } + }); + let channel = format_ident!("{}", channel); g.extend(quote! { - dma_trait_impl!(#tr, #peri, #channel, #request); + dma_trait_impl!(#tr, #peri, #channel, #request, #remap); }); } } diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs index ae53deb089..ae045fa38d 100644 --- a/embassy-stm32/src/macros.rs +++ b/embassy-stm32/src/macros.rs @@ -70,17 +70,28 @@ macro_rules! dma_trait { /// Note: in some chips, ST calls this the "channel", and calls channels "streams". /// `embassy-stm32` always uses the "channel" and "request number" names. fn request(&self) -> crate::dma::Request; + #[doc = "Remap the DMA channel"] + fn remap(&self); } }; } #[allow(unused)] macro_rules! dma_trait_impl { - (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $channel:ident, $request:expr) => { + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $channel:ident, $request:expr, $remap:expr) => { impl crate::$mod::$trait for crate::peripherals::$channel { fn request(&self) -> crate::dma::Request { $request } + + fn remap(&self) { + critical_section::with(|_| { + #[allow(unused_unsafe)] + unsafe { + $remap; + } + }); + } } }; } @@ -88,6 +99,7 @@ macro_rules! dma_trait_impl { macro_rules! new_dma { ($name:ident) => {{ let dma = $name.into_ref(); + dma.remap(); let request = dma.request(); Some(crate::dma::ChannelAndRequest { channel: dma.map_into(),