stm32/dma: Store wakers in "associated statics"

This commit is contained in:
Grant Miller
2022-10-18 23:15:42 -05:00
parent a669f4cfd8
commit fb53d74c57
3 changed files with 33 additions and 102 deletions

View File

@ -6,7 +6,6 @@ use core::task::Waker;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use super::{TransferOptions, Word, WordSize}; use super::{TransferOptions, Word, WordSize};
use crate::_generated::BDMA_CHANNEL_COUNT;
use crate::dma::Request; use crate::dma::Request;
use crate::interrupt::{Interrupt, InterruptExt}; use crate::interrupt::{Interrupt, InterruptExt};
use crate::pac; use crate::pac;
@ -22,21 +21,6 @@ impl From<WordSize> for vals::Size {
} }
} }
struct State {
ch_wakers: [AtomicWaker; BDMA_CHANNEL_COUNT],
}
impl State {
const fn new() -> Self {
const AW: AtomicWaker = AtomicWaker::new();
Self {
ch_wakers: [AW; BDMA_CHANNEL_COUNT],
}
}
}
static STATE: State = State::new();
/// 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! {
@ -52,6 +36,13 @@ foreach_dma_channel! {
// BDMA1 in H7 doesn't use DMAMUX, which breaks // BDMA1 in H7 doesn't use DMAMUX, which breaks
}; };
($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => { ($channel_peri:ident, $dma_peri:ident, bdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
impl crate::peripherals::$channel_peri {
fn waker() -> &'static AtomicWaker {
static WAKER: AtomicWaker = AtomicWaker::new();
&WAKER
}
}
impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
unsafe fn start_write<W: Word>(&mut self, _request: Request, buf: *const[W], reg_addr: *mut W, options: TransferOptions) { unsafe fn start_write<W: Word>(&mut self, _request: Request, buf: *const[W], reg_addr: *mut W, options: TransferOptions) {
@ -153,12 +144,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) } Self::waker().register(waker);
} }
fn on_irq() { fn on_irq() {
unsafe { unsafe {
low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, Self::waker());
} }
} }
} }
@ -248,11 +239,6 @@ mod low_level_api {
ch.ndtr().read().ndt() as u16 ch.ndtr().read().ndt() as u16
} }
/// Sets the waker for the specified DMA channel
pub unsafe fn set_waker(state_number: usize, waker: &Waker) {
STATE.ch_wakers[state_number].register(waker);
}
pub unsafe fn reset_status(dma: pac::bdma::Dma, channel_number: u8) { pub unsafe fn reset_status(dma: pac::bdma::Dma, channel_number: u8) {
dma.ifcr().write(|w| { dma.ifcr().write(|w| {
w.set_tcif(channel_number as _, true); w.set_tcif(channel_number as _, true);
@ -261,9 +247,8 @@ mod low_level_api {
} }
/// Safety: Must be called with a matching set of parameters for a valid dma channel /// 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) { pub unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: u8, waker: &'static AtomicWaker) {
let channel_num = channel_num as usize; let channel_num = channel_num as usize;
let index = index as usize;
let isr = dma.isr().read(); let isr = dma.isr().read();
let cr = dma.ch(channel_num).cr(); let cr = dma.ch(channel_num).cr();
@ -273,7 +258,7 @@ mod low_level_api {
} }
if isr.tcif(channel_num) && cr.read().tcie() { if isr.tcif(channel_num) && cr.read().tcie() {
cr.write(|_| ()); // Disable channel interrupts with the default value. cr.write(|_| ()); // Disable channel interrupts with the default value.
STATE.ch_wakers[index].wake(); waker.wake();
} }
} }
} }

View File

@ -4,7 +4,6 @@ use core::task::Waker;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize}; use super::{Burst, FlowControl, Request, TransferOptions, Word, WordSize};
use crate::_generated::DMA_CHANNEL_COUNT;
use crate::interrupt::{Interrupt, InterruptExt}; use crate::interrupt::{Interrupt, InterruptExt};
use crate::pac::dma::{regs, vals}; use crate::pac::dma::{regs, vals};
use crate::{interrupt, pac}; use crate::{interrupt, pac};
@ -39,33 +38,6 @@ impl From<FlowControl> for vals::Pfctrl {
} }
} }
struct ChannelState {
waker: AtomicWaker,
}
impl ChannelState {
const fn new() -> Self {
Self {
waker: AtomicWaker::new(),
}
}
}
struct State {
channels: [ChannelState; DMA_CHANNEL_COUNT],
}
impl State {
const fn new() -> Self {
const CH: ChannelState = ChannelState::new();
Self {
channels: [CH; DMA_CHANNEL_COUNT],
}
}
}
static STATE: State = State::new();
/// 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! {
@ -78,6 +50,13 @@ pub(crate) unsafe fn init() {
foreach_dma_channel! { foreach_dma_channel! {
($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => { ($channel_peri:ident, $dma_peri:ident, dma, $channel_num:expr, $index:expr, $dmamux:tt) => {
impl crate::peripherals::$channel_peri {
fn waker() -> &'static AtomicWaker {
static WAKER: AtomicWaker = AtomicWaker::new();
&WAKER
}
}
impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) { unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) {
let (ptr, len) = super::slice_ptr_parts(buf); let (ptr, len) = super::slice_ptr_parts(buf);
@ -192,12 +171,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 )} Self::waker().register(waker);
} }
fn on_irq() { fn on_irq() {
unsafe { unsafe {
low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, Self::waker());
} }
} }
} }
@ -381,11 +360,6 @@ mod low_level_api {
ch.ndtr().read().ndt() ch.ndtr().read().ndt()
} }
/// Sets the waker for the specified DMA channel
pub unsafe fn set_waker(state_number: usize, waker: &Waker) {
STATE.channels[state_number].waker.register(waker);
}
pub unsafe fn reset_status(dma: pac::dma::Dma, channel_number: u8) { pub unsafe fn reset_status(dma: pac::dma::Dma, channel_number: u8) {
let isrn = channel_number as usize / 4; let isrn = channel_number as usize / 4;
let isrbit = channel_number as usize % 4; let isrbit = channel_number as usize % 4;
@ -397,9 +371,8 @@ mod low_level_api {
} }
/// Safety: Must be called with a matching set of parameters for a valid dma channel /// 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, state_index: u8) { pub unsafe fn on_irq_inner(dma: pac::dma::Dma, channel_num: u8, waker: &'static AtomicWaker) {
let channel_num = channel_num as usize; let channel_num = channel_num as usize;
let state_index = state_index as usize;
let cr = dma.st(channel_num).cr(); let cr = dma.st(channel_num).cr();
let isr = dma.isr(channel_num / 4).read(); let isr = dma.isr(channel_num / 4).read();
@ -415,7 +388,7 @@ mod low_level_api {
// for double buffered mode, clear TCIF flag but do not stop the transfer // for double buffered mode, clear TCIF flag but do not stop the transfer
dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true)); dma.ifcr(channel_num / 4).write(|w| w.set_tcif(channel_num % 4, true));
} }
STATE.channels[state_index].waker.wake(); waker.wake();
} }
} }
} }

View File

@ -4,7 +4,6 @@ use core::task::Waker;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use super::{Request, TransferOptions, Word, WordSize}; use super::{Request, TransferOptions, Word, WordSize};
use crate::_generated::GPDMA_CHANNEL_COUNT;
use crate::interrupt::{Interrupt, InterruptExt}; use crate::interrupt::{Interrupt, InterruptExt};
use crate::pac::gpdma::{vals, Gpdma}; use crate::pac::gpdma::{vals, Gpdma};
use crate::{interrupt, pac}; use crate::{interrupt, pac};
@ -19,33 +18,6 @@ impl From<WordSize> for vals::ChTr1Dw {
} }
} }
struct ChannelState {
waker: AtomicWaker,
}
impl ChannelState {
const fn new() -> Self {
Self {
waker: AtomicWaker::new(),
}
}
}
struct State {
channels: [ChannelState; GPDMA_CHANNEL_COUNT],
}
impl State {
const fn new() -> Self {
const CH: ChannelState = ChannelState::new();
Self {
channels: [CH; GPDMA_CHANNEL_COUNT],
}
}
}
static STATE: State = State::new();
/// 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! {
@ -58,6 +30,13 @@ pub(crate) unsafe fn init() {
foreach_dma_channel! { foreach_dma_channel! {
($channel_peri:ident, $dma_peri:ident, gpdma, $channel_num:expr, $index:expr, $dmamux:tt) => { ($channel_peri:ident, $dma_peri:ident, gpdma, $channel_num:expr, $index:expr, $dmamux:tt) => {
impl crate::peripherals::$channel_peri {
fn waker() -> &'static AtomicWaker {
static WAKER: AtomicWaker = AtomicWaker::new();
&WAKER
}
}
impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri { impl crate::dma::sealed::Channel for crate::peripherals::$channel_peri {
unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) { unsafe fn start_write<W: Word>(&mut self, request: Request, buf: *const [W], reg_addr: *mut W, options: TransferOptions) {
let (ptr, len) = super::slice_ptr_parts(buf); let (ptr, len) = super::slice_ptr_parts(buf);
@ -144,12 +123,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 )} Self::waker().register(waker);
} }
fn on_irq() { fn on_irq() {
unsafe { unsafe {
low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, $index); low_level_api::on_irq_inner(pac::$dma_peri, $channel_num, Self::waker());
} }
} }
} }
@ -257,15 +236,9 @@ mod low_level_api {
ch.br1().read().bndt() ch.br1().read().bndt()
} }
/// Sets the waker for the specified DMA channel
pub unsafe fn set_waker(state_number: usize, waker: &Waker) {
STATE.channels[state_number].waker.register(waker);
}
/// Safety: Must be called with a matching set of parameters for a valid dma channel /// Safety: Must be called with a matching set of parameters for a valid dma channel
pub unsafe fn on_irq_inner(dma: Gpdma, channel_num: u8, state_index: u8) { pub unsafe fn on_irq_inner(dma: Gpdma, channel_num: u8, waker: &'static AtomicWaker) {
let channel_num = channel_num as usize; let channel_num = channel_num as usize;
let state_index = state_index as usize;
let ch = dma.ch(channel_num); let ch = dma.ch(channel_num);
let sr = ch.sr().read(); let sr = ch.sr().read();
@ -285,7 +258,7 @@ mod low_level_api {
if sr.suspf() || sr.tcf() { if sr.suspf() || sr.tcf() {
ch.cr().write(|w| w.set_reset(true)); ch.cr().write(|w| w.set_reset(true));
STATE.channels[state_index].waker.wake(); waker.wake();
} }
} }
} }