stm32: Refactor DMA interrupts
Previously, every dma interrupt handler called the same `on_irq` function which had to check the state of every dma channel. Now, each dma interrupt handler only calls an `on_irq` method for its corresponding channel or channels.
This commit is contained in:
parent
9735c38592
commit
8c45c98e41
4 changed files with 65 additions and 65 deletions
|
@ -105,46 +105,37 @@ fn main() {
|
||||||
// ========
|
// ========
|
||||||
// Generate DMA IRQs.
|
// Generate DMA IRQs.
|
||||||
|
|
||||||
let mut dma_irqs: HashSet<&str> = HashSet::new();
|
let mut dma_irqs: HashMap<&str, Vec<(&str, &str)>> = HashMap::new();
|
||||||
let mut bdma_irqs: HashSet<&str> = HashSet::new();
|
|
||||||
|
|
||||||
for p in METADATA.peripherals {
|
for p in METADATA.peripherals {
|
||||||
if let Some(r) = &p.registers {
|
if let Some(r) = &p.registers {
|
||||||
match r.kind {
|
if r.kind == "dma" || r.kind == "bdma" {
|
||||||
"dma" => {
|
for irq in p.interrupts {
|
||||||
for irq in p.interrupts {
|
dma_irqs
|
||||||
dma_irqs.insert(irq.interrupt);
|
.entry(irq.interrupt)
|
||||||
}
|
.or_default()
|
||||||
|
.push((p.name, irq.signal));
|
||||||
}
|
}
|
||||||
"bdma" => {
|
|
||||||
for irq in p.interrupts {
|
|
||||||
bdma_irqs.insert(irq.interrupt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tokens: Vec<_> = dma_irqs.iter().map(|s| format_ident!("{}", s)).collect();
|
for (irq, channels) in dma_irqs {
|
||||||
g.extend(quote! {
|
let irq = format_ident!("{}", irq);
|
||||||
#(
|
|
||||||
#[crate::interrupt]
|
|
||||||
unsafe fn #tokens () {
|
|
||||||
crate::dma::dma::on_irq();
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
});
|
|
||||||
|
|
||||||
let tokens: Vec<_> = bdma_irqs.iter().map(|s| format_ident!("{}", s)).collect();
|
let channels = channels
|
||||||
g.extend(quote! {
|
.iter()
|
||||||
#(
|
.map(|(dma, ch)| format_ident!("{}_{}", dma, ch));
|
||||||
|
|
||||||
|
g.extend(quote! {
|
||||||
#[crate::interrupt]
|
#[crate::interrupt]
|
||||||
unsafe fn #tokens () {
|
unsafe fn #irq () {
|
||||||
crate::dma::bdma::on_irq();
|
#(
|
||||||
|
<crate::peripherals::#channels as crate::dma::sealed::Channel>::on_irq();
|
||||||
|
)*
|
||||||
}
|
}
|
||||||
)*
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
// ========
|
// ========
|
||||||
// Generate RccPeripheral impls
|
// Generate RccPeripheral impls
|
||||||
|
|
|
@ -38,26 +38,6 @@ impl State {
|
||||||
|
|
||||||
static STATE: State = State::new();
|
static STATE: State = State::new();
|
||||||
|
|
||||||
pub(crate) unsafe fn on_irq() {
|
|
||||||
foreach_peripheral! {
|
|
||||||
(bdma, BDMA1) => {
|
|
||||||
// BDMA1 in H7 doesn't use DMAMUX, which breaks
|
|
||||||
};
|
|
||||||
(bdma, $dma:ident) => {
|
|
||||||
let isr = pac::$dma.isr().read();
|
|
||||||
foreach_dma_channel! {
|
|
||||||
($channel_peri:ident, $dma, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
|
|
||||||
let cr = pac::$dma.ch($channel_num).cr();
|
|
||||||
if isr.tcif($channel_num) && cr.read().tcie() {
|
|
||||||
cr.write(|_| ()); // Disable channel interrupts with the default value.
|
|
||||||
STATE.ch_wakers[$index].wake();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// safety: must be called only once
|
/// safety: must be called only once
|
||||||
pub(crate) unsafe fn init() {
|
pub(crate) unsafe fn init() {
|
||||||
foreach_interrupt! {
|
foreach_interrupt! {
|
||||||
|
@ -150,6 +130,12 @@ foreach_dma_channel! {
|
||||||
fn set_waker(&mut self, waker: &Waker) {
|
fn set_waker(&mut self, waker: &Waker) {
|
||||||
unsafe { low_level_api::set_waker($index, waker) }
|
unsafe { low_level_api::set_waker($index, waker) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_irq() {
|
||||||
|
unsafe {
|
||||||
|
low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::dma::Channel for crate::peripherals::$channel_peri {}
|
impl crate::dma::Channel for crate::peripherals::$channel_peri {}
|
||||||
|
@ -243,4 +229,18 @@ mod low_level_api {
|
||||||
w.set_teif(channel_number as _, true);
|
w.set_teif(channel_number as _, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Safety: Must be called with a matching set of parameters for a valid dma channel
|
||||||
|
pub unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: u8, index: u8) {
|
||||||
|
let channel_num = channel_num as usize;
|
||||||
|
let index = index as usize;
|
||||||
|
|
||||||
|
let isr = dma.isr().read();
|
||||||
|
let cr = dma.ch(channel_num).cr();
|
||||||
|
|
||||||
|
if isr.tcif(channel_num) && cr.read().tcie() {
|
||||||
|
cr.write(|_| ()); // Disable channel interrupts with the default value.
|
||||||
|
STATE.ch_wakers[index].wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,22 +36,6 @@ impl State {
|
||||||
|
|
||||||
static STATE: State = State::new();
|
static STATE: State = State::new();
|
||||||
|
|
||||||
pub(crate) unsafe fn on_irq() {
|
|
||||||
foreach_peripheral! {
|
|
||||||
(dma, $dma:ident) => {
|
|
||||||
foreach_dma_channel! {
|
|
||||||
($channel_peri:ident, $dma, dma, $channel_num:expr, $index:expr, $dmamux:tt) => {
|
|
||||||
let cr = pac::$dma.st($channel_num).cr();
|
|
||||||
if pac::$dma.isr($channel_num/4).read().tcif($channel_num%4) && cr.read().tcie() {
|
|
||||||
cr.write(|_| ()); // Disable channel interrupts with the default value.
|
|
||||||
STATE.ch_wakers[$index].wake();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// safety: must be called only once
|
/// safety: must be called only once
|
||||||
pub(crate) unsafe fn init() {
|
pub(crate) unsafe fn init() {
|
||||||
foreach_interrupt! {
|
foreach_interrupt! {
|
||||||
|
@ -137,6 +121,12 @@ foreach_dma_channel! {
|
||||||
fn set_waker(&mut self, waker: &Waker) {
|
fn set_waker(&mut self, waker: &Waker) {
|
||||||
unsafe {low_level_api::set_waker($index, waker )}
|
unsafe {low_level_api::set_waker($index, waker )}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_irq() {
|
||||||
|
unsafe {
|
||||||
|
low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::dma::Channel for crate::peripherals::$channel_peri { }
|
impl crate::dma::Channel for crate::peripherals::$channel_peri { }
|
||||||
|
@ -240,4 +230,18 @@ mod low_level_api {
|
||||||
w.set_teif(isrbit, true);
|
w.set_teif(isrbit, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Safety: Must be called with a matching set of parameters for a valid dma channel
|
||||||
|
pub unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: u8, index: u8) {
|
||||||
|
let channel_num = channel_num as usize;
|
||||||
|
let index = index as usize;
|
||||||
|
|
||||||
|
let cr = dma.st(channel_num).cr();
|
||||||
|
let isr = dma.isr(channel_num / 4).read();
|
||||||
|
|
||||||
|
if isr.tcif(channel_num % 4) && cr.read().tcie() {
|
||||||
|
cr.write(|_| ()); // Disable channel interrupts with the default value.
|
||||||
|
STATE.ch_wakers[index].wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,11 @@ pub(crate) mod sealed {
|
||||||
|
|
||||||
/// Sets the waker that is called when this channel stops (either completed or manually stopped)
|
/// Sets the waker that is called when this channel stops (either completed or manually stopped)
|
||||||
fn set_waker(&mut self, waker: &Waker);
|
fn set_waker(&mut self, waker: &Waker);
|
||||||
|
|
||||||
|
/// This is called when this channel triggers an interrupt.
|
||||||
|
/// Note: Because some channels share an interrupt, this function might be
|
||||||
|
/// called for a channel that didn't trigger an interrupt.
|
||||||
|
fn on_irq();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue