Merge pull request #2045 from embassy-rs/stm32-cs-spam
Avoid creating many tiny critical sections in embassy-stm32::init
This commit is contained in:
commit
debda2f52c
@ -4,6 +4,7 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
use cortex_m::interrupt::InterruptNumber;
|
||||
use cortex_m::peripheral::NVIC;
|
||||
use critical_section::CriticalSection;
|
||||
|
||||
/// Generate a standard `mod interrupt` for a HAL.
|
||||
#[macro_export]
|
||||
@ -91,6 +92,12 @@ macro_rules! interrupt_mod {
|
||||
fn set_priority(prio: crate::interrupt::Priority) {
|
||||
Self::IRQ.set_priority(prio)
|
||||
}
|
||||
|
||||
/// Set the interrupt priority with an already-acquired critical section
|
||||
#[inline]
|
||||
fn set_priority_with_cs(cs: critical_section::CriticalSection, prio: crate::interrupt::Priority) {
|
||||
Self::IRQ.set_priority_with_cs(cs, prio)
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
@ -195,10 +202,29 @@ pub unsafe trait InterruptExt: InterruptNumber + Copy {
|
||||
/// Set the interrupt priority.
|
||||
#[inline]
|
||||
fn set_priority(self, prio: Priority) {
|
||||
critical_section::with(|_| unsafe {
|
||||
unsafe {
|
||||
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
||||
nvic.set_priority(self, prio.into())
|
||||
})
|
||||
|
||||
// On thumbv6, set_priority must do a RMW to change 8bit in a 32bit reg.
|
||||
#[cfg(armv6m)]
|
||||
critical_section::with(|_| nvic.set_priority(self, prio.into()));
|
||||
// On thumbv7+, set_priority does an atomic 8bit write, so no CS needed.
|
||||
#[cfg(not(armv6m))]
|
||||
nvic.set_priority(self, prio.into());
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the interrupt priority with an already-acquired critical section
|
||||
///
|
||||
/// Equivalent to `set_priority`, except you pass a `CriticalSection` to prove
|
||||
/// you've already acquired a critical section. This prevents acquiring another
|
||||
/// one, which saves code size.
|
||||
#[inline]
|
||||
fn set_priority_with_cs(self, _cs: CriticalSection, prio: Priority) {
|
||||
unsafe {
|
||||
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
||||
nvic.set_priority(self, prio.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,17 +48,23 @@ macro_rules! peripherals_struct {
|
||||
///Returns all the peripherals *once*
|
||||
#[inline]
|
||||
pub(crate) fn take() -> Self {
|
||||
critical_section::with(Self::take_with_cs)
|
||||
}
|
||||
|
||||
///Returns all the peripherals *once*
|
||||
#[inline]
|
||||
pub(crate) fn take_with_cs(_cs: critical_section::CriticalSection) -> Self {
|
||||
#[no_mangle]
|
||||
static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
|
||||
|
||||
critical_section::with(|_| unsafe {
|
||||
// safety: OK because we're inside a CS.
|
||||
unsafe {
|
||||
if _EMBASSY_DEVICE_PERIPHERALS {
|
||||
panic!("init called more than once!")
|
||||
}
|
||||
_EMBASSY_DEVICE_PERIPHERALS = true;
|
||||
Self::steal()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,23 +554,19 @@ fn main() {
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
#clock_frequency
|
||||
}
|
||||
fn enable_and_reset() {
|
||||
critical_section::with(|_cs| {
|
||||
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
|
||||
#before_enable
|
||||
#[cfg(feature = "low-power")]
|
||||
crate::rcc::clock_refcount_add(_cs);
|
||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
|
||||
#after_enable
|
||||
#rst
|
||||
})
|
||||
}
|
||||
fn disable() {
|
||||
critical_section::with(|_cs| {
|
||||
fn disable_with_cs(_cs: critical_section::CriticalSection) {
|
||||
#before_disable
|
||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
|
||||
#[cfg(feature = "low-power")]
|
||||
crate::rcc::clock_refcount_sub(_cs);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,18 +567,14 @@ foreach_peripheral!(
|
||||
critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
|
||||
}
|
||||
|
||||
fn enable_and_reset() {
|
||||
critical_section::with(|_| {
|
||||
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
|
||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
|
||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
|
||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
|
||||
})
|
||||
}
|
||||
|
||||
fn disable() {
|
||||
critical_section::with(|_| {
|
||||
fn disable_with_cs(_cs: critical_section::CriticalSection) {
|
||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,10 +77,10 @@ impl State {
|
||||
static STATE: State = State::new();
|
||||
|
||||
/// safety: must be called only once
|
||||
pub(crate) unsafe fn init(irq_priority: Priority) {
|
||||
pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
|
||||
foreach_interrupt! {
|
||||
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
|
||||
crate::interrupt::typelevel::$irq::set_priority(irq_priority);
|
||||
crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
|
||||
crate::interrupt::typelevel::$irq::enable();
|
||||
};
|
||||
}
|
||||
|
@ -154,10 +154,10 @@ impl State {
|
||||
static STATE: State = State::new();
|
||||
|
||||
/// safety: must be called only once
|
||||
pub(crate) unsafe fn init(irq_priority: Priority) {
|
||||
pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
|
||||
foreach_interrupt! {
|
||||
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
|
||||
interrupt::typelevel::$irq::set_priority(irq_priority);
|
||||
interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
|
||||
interrupt::typelevel::$irq::enable();
|
||||
};
|
||||
}
|
||||
|
@ -47,6 +47,6 @@ foreach_dma_channel! {
|
||||
}
|
||||
|
||||
/// safety: must be called only once
|
||||
pub(crate) unsafe fn init() {
|
||||
pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
crate::_generated::init_dmamux();
|
||||
}
|
||||
|
@ -53,10 +53,10 @@ impl State {
|
||||
static STATE: State = State::new();
|
||||
|
||||
/// safety: must be called only once
|
||||
pub(crate) unsafe fn init(irq_priority: Priority) {
|
||||
pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
|
||||
foreach_interrupt! {
|
||||
($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
|
||||
crate::interrupt::typelevel::$irq::set_priority(irq_priority);
|
||||
crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
|
||||
crate::interrupt::typelevel::$irq::enable();
|
||||
};
|
||||
}
|
||||
|
@ -56,16 +56,17 @@ pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) {
|
||||
|
||||
// safety: must be called only once at startup
|
||||
pub(crate) unsafe fn init(
|
||||
cs: critical_section::CriticalSection,
|
||||
#[cfg(bdma)] bdma_priority: Priority,
|
||||
#[cfg(dma)] dma_priority: Priority,
|
||||
#[cfg(gpdma)] gpdma_priority: Priority,
|
||||
) {
|
||||
#[cfg(bdma)]
|
||||
bdma::init(bdma_priority);
|
||||
bdma::init(cs, bdma_priority);
|
||||
#[cfg(dma)]
|
||||
dma::init(dma_priority);
|
||||
dma::init(cs, dma_priority);
|
||||
#[cfg(gpdma)]
|
||||
gpdma::init(gpdma_priority);
|
||||
gpdma::init(cs, gpdma_priority);
|
||||
#[cfg(dmamux)]
|
||||
dmamux::init();
|
||||
dmamux::init(cs);
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ macro_rules! enable_irq {
|
||||
}
|
||||
|
||||
/// safety: must be called only once
|
||||
pub(crate) unsafe fn init() {
|
||||
pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
|
||||
foreach_exti_irq!(enable_irq);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#![macro_use]
|
||||
use core::convert::Infallible;
|
||||
|
||||
use critical_section::CriticalSection;
|
||||
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
|
||||
|
||||
use crate::pac::gpio::{self, vals};
|
||||
@ -757,9 +758,9 @@ foreach_pin!(
|
||||
};
|
||||
);
|
||||
|
||||
pub(crate) unsafe fn init() {
|
||||
pub(crate) unsafe fn init(_cs: CriticalSection) {
|
||||
#[cfg(afio)]
|
||||
<crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable_and_reset();
|
||||
<crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(_cs);
|
||||
|
||||
crate::_generated::init_gpio();
|
||||
}
|
||||
|
@ -155,7 +155,8 @@ impl Default for Config {
|
||||
|
||||
/// Initialize embassy.
|
||||
pub fn init(config: Config) -> Peripherals {
|
||||
let p = Peripherals::take();
|
||||
critical_section::with(|cs| {
|
||||
let p = Peripherals::take_with_cs(cs);
|
||||
|
||||
#[cfg(dbgmcu)]
|
||||
if config.enable_debug_during_sleep {
|
||||
@ -186,11 +187,11 @@ pub fn init(config: Config) -> Peripherals {
|
||||
}
|
||||
|
||||
#[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
|
||||
peripherals::SYSCFG::enable_and_reset();
|
||||
peripherals::SYSCFG::enable_and_reset_with_cs(cs);
|
||||
#[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))]
|
||||
peripherals::PWR::enable_and_reset();
|
||||
peripherals::PWR::enable_and_reset_with_cs(cs);
|
||||
#[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))]
|
||||
peripherals::FLASH::enable_and_reset();
|
||||
peripherals::FLASH::enable_and_reset_with_cs(cs);
|
||||
|
||||
unsafe {
|
||||
#[cfg(feature = "_split-pins-enabled")]
|
||||
@ -205,8 +206,9 @@ pub fn init(config: Config) -> Peripherals {
|
||||
pmcr.set_pc3so(true);
|
||||
});
|
||||
|
||||
gpio::init();
|
||||
gpio::init(cs);
|
||||
dma::init(
|
||||
cs,
|
||||
#[cfg(bdma)]
|
||||
config.bdma_interrupt_priority,
|
||||
#[cfg(dma)]
|
||||
@ -215,21 +217,20 @@ pub fn init(config: Config) -> Peripherals {
|
||||
config.gpdma_interrupt_priority,
|
||||
);
|
||||
#[cfg(feature = "exti")]
|
||||
exti::init();
|
||||
exti::init(cs);
|
||||
|
||||
rcc::init(config.rcc);
|
||||
|
||||
// must be after rcc init
|
||||
#[cfg(feature = "_time-driver")]
|
||||
time_driver::init();
|
||||
time_driver::init(cs);
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
while !crate::rcc::low_power_ready() {
|
||||
critical_section::with(|cs| {
|
||||
crate::rcc::clock_refcount_sub(cs);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
p
|
||||
})
|
||||
}
|
||||
|
@ -229,10 +229,19 @@ pub mod low_level {
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use critical_section::CriticalSection;
|
||||
|
||||
pub trait RccPeripheral {
|
||||
fn frequency() -> crate::time::Hertz;
|
||||
fn enable_and_reset();
|
||||
fn disable();
|
||||
fn enable_and_reset_with_cs(cs: CriticalSection);
|
||||
fn disable_with_cs(cs: CriticalSection);
|
||||
|
||||
fn enable_and_reset() {
|
||||
critical_section::with(|cs| Self::enable_and_reset_with_cs(cs))
|
||||
}
|
||||
fn disable() {
|
||||
critical_section::with(|cs| Self::disable_with_cs(cs))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,14 +152,13 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
|
||||
});
|
||||
|
||||
impl RtcDriver {
|
||||
fn init(&'static self) {
|
||||
fn init(&'static self, cs: critical_section::CriticalSection) {
|
||||
let r = T::regs_gp16();
|
||||
|
||||
<T as RccPeripheral>::enable_and_reset();
|
||||
<T as RccPeripheral>::enable_and_reset_with_cs(cs);
|
||||
|
||||
let timer_freq = T::frequency();
|
||||
|
||||
critical_section::with(|_| {
|
||||
r.cr1().modify(|w| w.set_cen(false));
|
||||
r.cnt().write(|w| w.set_cnt(0));
|
||||
|
||||
@ -190,7 +189,6 @@ impl RtcDriver {
|
||||
unsafe { <T as BasicInstance>::Interrupt::enable() };
|
||||
|
||||
r.cr1().modify(|w| w.set_cen(true));
|
||||
})
|
||||
}
|
||||
|
||||
fn on_interrupt(&self) {
|
||||
@ -462,6 +460,6 @@ pub(crate) fn get_driver() -> &'static RtcDriver {
|
||||
&DRIVER
|
||||
}
|
||||
|
||||
pub(crate) fn init() {
|
||||
DRIVER.init()
|
||||
pub(crate) fn init(cs: CriticalSection) {
|
||||
DRIVER.init(cs)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user