Skip to content

Commit

Permalink
Fix dma nvic issues on dual core lines
Browse files Browse the repository at this point in the history
This commit addresses embassy-rs#3256 by disabling dma NVIC interrupt configuration at startup.
Instead, per-channel NVIC interrupt configuration is now done with the rest of the dma channel configuration.
This ensures that each core will only handle the interrupts of the DMA channels that it uses.
  • Loading branch information
liarokapisv committed Aug 17, 2024
1 parent 6d9ed4c commit adc6583
Show file tree
Hide file tree
Showing 14 changed files with 102 additions and 22 deletions.
70 changes: 50 additions & 20 deletions embassy-stm32/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1494,6 +1494,36 @@ fn main() {
.flat_map(|p| &p.registers)
.any(|p| p.kind == "dmamux");

let mut dma_irqs: BTreeMap<&str, Vec<String>> = BTreeMap::new();

for p in METADATA.peripherals {
if let Some(r) = &p.registers {
if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" || r.kind == "lpdma" {
for irq in p.interrupts {
let ch_name = format!("{}_{}", p.name, irq.signal);
let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap();

// Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
if has_dmamux && ch.dmamux.is_none() {
continue;
}

dma_irqs.entry(irq.interrupt).or_default().push(ch_name);
}
}
}
}

#[cfg(feature = "_dual-core")]
let mut dma_ch_to_irq: BTreeMap<&str, Vec<String>> = BTreeMap::new();

#[cfg(feature = "_dual-core")]
for (irq, channels) in &dma_irqs {
for channel in channels {
dma_ch_to_irq.entry(channel).or_default().push(irq.to_string());
}
}

for (ch_idx, ch) in METADATA.dma_channels.iter().enumerate() {
// Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
if has_dmamux && ch.dmamux.is_none() {
Expand All @@ -1502,6 +1532,16 @@ fn main() {

let name = format_ident!("{}", ch.name);
let idx = ch_idx as u8;
#[cfg(feature = "_dual-core")]
let irq = {
let irq_name = if let Some(x) = &dma_ch_to_irq.get(ch.name) {
format_ident!("{}", x.get(0).unwrap())
} else {
panic!("failed to find dma interrupt")
};
quote!(crate::pac::Interrupt::#irq_name)
};

g.extend(quote!(dma_channel_impl!(#name, #idx);));

let dma = format_ident!("{}", ch.dma);
Expand Down Expand Up @@ -1532,38 +1572,28 @@ fn main() {
None => quote!(),
};

#[cfg(not(feature = "_dual-core"))]
dmas.extend(quote! {
crate::dma::ChannelInfo {
dma: #dma_info,
num: #ch_num,
#dmamux
},
});
#[cfg(feature = "_dual-core")]
dmas.extend(quote! {
crate::dma::ChannelInfo {
dma: #dma_info,
num: #ch_num,
irq: #irq,
#dmamux
},
});
}

// ========
// Generate DMA IRQs.

let mut dma_irqs: BTreeMap<&str, Vec<String>> = BTreeMap::new();

for p in METADATA.peripherals {
if let Some(r) = &p.registers {
if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" {
for irq in p.interrupts {
let ch_name = format!("{}_{}", p.name, irq.signal);
let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap();

// Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
if has_dmamux && ch.dmamux.is_none() {
continue;
}

dma_irqs.entry(irq.interrupt).or_default().push(ch_name);
}
}
}
}

let dma_irqs: TokenStream = dma_irqs
.iter()
.map(|(irq, channels)| {
Expand Down
9 changes: 9 additions & 0 deletions embassy-stm32/src/dma/dma_bdma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use crate::{interrupt, pac};
pub(crate) struct ChannelInfo {
pub(crate) dma: DmaInfo,
pub(crate) num: usize,
#[cfg(feature = "_dual-core")]
pub(crate) irq: pac::Interrupt,
#[cfg(dmamux)]
pub(crate) dmamux: super::DmamuxInfo,
}
Expand Down Expand Up @@ -259,10 +261,12 @@ pub(crate) unsafe fn init(
foreach_interrupt! {
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, dma_priority);
#[cfg(not(feature = "_dual-core"))]
crate::interrupt::typelevel::$irq::enable();
};
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, bdma_priority);
#[cfg(not(feature = "_dual-core"))]
crate::interrupt::typelevel::$irq::enable();
};
}
Expand Down Expand Up @@ -341,6 +345,11 @@ impl AnyChannel {
options: TransferOptions,
) {
let info = self.info();
#[cfg(feature = "_dual-core")]
{
use embassy_hal_internal::interrupt::InterruptExt as _;
info.irq.enable();
}

#[cfg(dmamux)]
super::dmamux::configure_dmamux(&info.dmamux, _request);
Expand Down
9 changes: 9 additions & 0 deletions embassy-stm32/src/dma/gpdma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use crate::pac::gpdma::vals;
pub(crate) struct ChannelInfo {
pub(crate) dma: pac::gpdma::Gpdma,
pub(crate) num: usize,
#[cfg(feature = "_dual-core")]
pub(crate) irq: pac::Interrupt,
}

/// GPDMA transfer options.
Expand Down Expand Up @@ -57,6 +59,7 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: P
foreach_interrupt! {
($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
#[cfg(not(feature = "_dual-core"))]
crate::interrupt::typelevel::$irq::enable();
};
}
Expand All @@ -67,6 +70,12 @@ impl AnyChannel {
/// Safety: Must be called with a matching set of parameters for a valid dma channel
pub(crate) unsafe fn on_irq(&self) {
let info = self.info();
#[cfg(feature = "_dual-core")]
{
use embassy_hal_internal::interrupt::InterruptExt as _;
info.irq.enable();
}

let state = &STATE[self.id as usize];

let ch = info.dma.ch(info.num);
Expand Down
20 changes: 19 additions & 1 deletion embassy-stm32/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ pub use crate::pac::NVIC_PRIO_BITS;

/// `embassy-stm32` global configuration.
#[non_exhaustive]
#[derive(Clone, Copy)]
pub struct Config {
/// RCC config.
pub rcc: rcc::Config,
Expand Down Expand Up @@ -303,6 +304,7 @@ mod dual_core {
pub struct SharedData {
init_flag: AtomicUsize,
clocks: UnsafeCell<MaybeUninit<Clocks>>,
config: UnsafeCell<MaybeUninit<Config>>,
}

unsafe impl Sync for SharedData {}
Expand All @@ -325,6 +327,8 @@ mod dual_core {
rcc::set_freqs_ptr(shared_data.clocks.get());
let p = init_hw(config);

unsafe { *shared_data.config.get() }.write(config);

shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst);

p
Expand Down Expand Up @@ -372,9 +376,23 @@ mod dual_core {
fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals {
rcc::set_freqs_ptr(shared_data.clocks.get());

let config = unsafe { (*shared_data.config.get()).assume_init() };

// We use different timers on the different cores, so we have to still initialize one here
#[cfg(feature = "_time-driver")]
critical_section::with(|cs| {
unsafe {
dma::init(
cs,
#[cfg(bdma)]
config.bdma_interrupt_priority,
#[cfg(dma)]
config.dma_interrupt_priority,
#[cfg(gpdma)]
config.gpdma_interrupt_priority,
)
}

#[cfg(feature = "_time-driver")]
// must be after rcc init
time_driver::init(cs);
});
Expand Down
2 changes: 2 additions & 0 deletions embassy-stm32/src/rcc/bd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub enum LseMode {
Bypass,
}

#[derive(Clone, Copy)]
pub struct LseConfig {
pub frequency: Hertz,
pub mode: LseMode,
Expand Down Expand Up @@ -80,6 +81,7 @@ fn bdcr() -> Reg<Bdcr, RW> {
return crate::pac::RCC.csr1();
}

#[derive(Clone, Copy)]
pub struct LsConfig {
pub rtc: RtcClockSource,
pub lsi: bool,
Expand Down
1 change: 1 addition & 0 deletions embassy-stm32/src/rcc/c0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub struct Hsi {

/// Clocks configutation
#[non_exhaustive]
#[derive(Clone, Copy)]
pub struct Config {
/// HSI Configuration
pub hsi: Option<Hsi>,
Expand Down
1 change: 1 addition & 0 deletions embassy-stm32/src/rcc/f013.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub enum HrtimClockSource {

/// Clocks configutation
#[non_exhaustive]
#[derive(Clone, Copy)]
pub struct Config {
pub hsi: bool,
pub hse: Option<Hse>,
Expand Down
2 changes: 2 additions & 0 deletions embassy-stm32/src/rcc/f247.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ pub struct Pll {
/// Used to calculate flash waitstates. See
/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency
#[cfg(stm32f2)]
#[derive(Clone, Copy)]
pub enum VoltageScale {
/// 2.7 to 3.6 V
Range0,
Expand All @@ -76,6 +77,7 @@ pub enum VoltageScale {

/// Configuration of the core clocks
#[non_exhaustive]
#[derive(Clone, Copy)]
pub struct Config {
pub hsi: bool,
pub hse: Option<Hse>,
Expand Down
2 changes: 2 additions & 0 deletions embassy-stm32/src/rcc/g0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct Hse {
/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
/// frequency ranges for each of these settings.
#[derive(Clone, Copy)]
pub struct Pll {
/// PLL Source clock selection.
pub source: PllSource,
Expand All @@ -55,6 +56,7 @@ pub struct Pll {

/// Clocks configutation
#[non_exhaustive]
#[derive(Clone, Copy)]
pub struct Config {
/// HSI Enable
pub hsi: bool,
Expand Down
2 changes: 2 additions & 0 deletions embassy-stm32/src/rcc/g4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct Hse {
/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
/// frequency ranges for each of these settings.
#[derive(Clone, Copy)]
pub struct Pll {
/// PLL Source clock selection.
pub source: PllSource,
Expand All @@ -54,6 +55,7 @@ pub struct Pll {

/// Clocks configutation
#[non_exhaustive]
#[derive(Clone, Copy)]
pub struct Config {
/// HSI Enable
pub hsi: bool,
Expand Down
3 changes: 2 additions & 1 deletion embassy-stm32/src/rcc/h.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl From<TimerPrescaler> for Timpre {
/// Power supply configuration
/// See RM0433 Rev 4 7.4
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))]
#[derive(PartialEq)]
#[derive(Clone, Copy, PartialEq)]
pub enum SupplyConfig {
/// Default power supply configuration.
/// V CORE Power Domains are supplied from the LDO according to VOS.
Expand Down Expand Up @@ -180,6 +180,7 @@ pub enum SMPSSupplyVoltage {

/// Configuration of the core clocks
#[non_exhaustive]
#[derive(Clone, Copy)]
pub struct Config {
pub hsi: Option<HSIPrescaler>,
pub hse: Option<Hse>,
Expand Down
1 change: 1 addition & 0 deletions embassy-stm32/src/rcc/l.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub struct Hse {
}

/// Clocks configuration
#[derive(Clone, Copy)]
pub struct Config {
// base clock sources
pub msi: Option<MSIRange>,
Expand Down
1 change: 1 addition & 0 deletions embassy-stm32/src/rcc/u5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub struct Pll {
pub divr: Option<PllDiv>,
}

#[derive(Clone, Copy)]
pub struct Config {
// base clock sources
pub msi: Option<MSIRange>,
Expand Down
1 change: 1 addition & 0 deletions embassy-stm32/src/rcc/wba.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct Hse {
}

/// Clocks configuration
#[derive(Clone, Copy)]
pub struct Config {
// base clock sources
pub hsi: bool,
Expand Down

0 comments on commit adc6583

Please sign in to comment.