Skip to content

Commit

Permalink
STM32F0/F3 Remap DMA channels
Browse files Browse the repository at this point in the history
  • Loading branch information
fwolter committed Dec 15, 2024
1 parent 45d9bd5 commit c86a0f5
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 2 deletions.
59 changes: 58 additions & 1 deletion embassy-stm32/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down Expand Up @@ -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);
});
}
}
Expand Down
14 changes: 13 additions & 1 deletion embassy-stm32/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,24 +70,36 @@ 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<crate::peripherals::$instance $(, crate::$mod::$mode)?> for crate::peripherals::$channel {
fn request(&self) -> crate::dma::Request {
$request
}

fn remap(&self) {
critical_section::with(|_| {
#[allow(unused_unsafe)]
unsafe {
$remap;
}
});
}
}
};
}

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(),
Expand Down

0 comments on commit c86a0f5

Please sign in to comment.