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:
Grant Miller
2022-03-08 13:52:33 -06:00
parent 9735c38592
commit 8c45c98e41
4 changed files with 65 additions and 65 deletions

View File

@ -38,26 +38,6 @@ impl State {
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
pub(crate) unsafe fn init() {
foreach_interrupt! {
@ -150,6 +130,12 @@ foreach_dma_channel! {
fn set_waker(&mut self, waker: &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 {}
@ -243,4 +229,18 @@ mod low_level_api {
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();
}
}
}

View File

@ -36,22 +36,6 @@ impl State {
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
pub(crate) unsafe fn init() {
foreach_interrupt! {
@ -137,6 +121,12 @@ foreach_dma_channel! {
fn set_waker(&mut self, waker: &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 { }
@ -240,4 +230,18 @@ mod low_level_api {
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();
}
}
}

View File

@ -88,6 +88,11 @@ pub(crate) mod sealed {
/// Sets the waker that is called when this channel stops (either completed or manually stopped)
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();
}
}