stm32: avoid creating many tiny critical sections in init.
Saves 292 bytes on stm32f0 bilnky with max optimizations (from 3132 to 2840).
This commit is contained in:
parent
66e399b5c6
commit
97ca0e77bf
@ -4,6 +4,7 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
|||||||
|
|
||||||
use cortex_m::interrupt::InterruptNumber;
|
use cortex_m::interrupt::InterruptNumber;
|
||||||
use cortex_m::peripheral::NVIC;
|
use cortex_m::peripheral::NVIC;
|
||||||
|
use critical_section::CriticalSection;
|
||||||
|
|
||||||
/// Generate a standard `mod interrupt` for a HAL.
|
/// Generate a standard `mod interrupt` for a HAL.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
@ -91,6 +92,12 @@ macro_rules! interrupt_mod {
|
|||||||
fn set_priority(prio: crate::interrupt::Priority) {
|
fn set_priority(prio: crate::interrupt::Priority) {
|
||||||
Self::IRQ.set_priority(prio)
|
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.
|
/// Set the interrupt priority.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_priority(self, prio: Priority) {
|
fn set_priority(self, prio: Priority) {
|
||||||
critical_section::with(|_| unsafe {
|
unsafe {
|
||||||
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
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*
|
///Returns all the peripherals *once*
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn take() -> Self {
|
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]
|
#[no_mangle]
|
||||||
static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
|
static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
|
||||||
|
|
||||||
critical_section::with(|_| unsafe {
|
// safety: OK because we're inside a CS.
|
||||||
|
unsafe {
|
||||||
if _EMBASSY_DEVICE_PERIPHERALS {
|
if _EMBASSY_DEVICE_PERIPHERALS {
|
||||||
panic!("init called more than once!")
|
panic!("init called more than once!")
|
||||||
}
|
}
|
||||||
_EMBASSY_DEVICE_PERIPHERALS = true;
|
_EMBASSY_DEVICE_PERIPHERALS = true;
|
||||||
Self::steal()
|
Self::steal()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,23 +554,19 @@ fn main() {
|
|||||||
fn frequency() -> crate::time::Hertz {
|
fn frequency() -> crate::time::Hertz {
|
||||||
#clock_frequency
|
#clock_frequency
|
||||||
}
|
}
|
||||||
fn enable_and_reset() {
|
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
|
||||||
critical_section::with(|_cs| {
|
|
||||||
#before_enable
|
#before_enable
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
crate::rcc::clock_refcount_add(_cs);
|
crate::rcc::clock_refcount_add(_cs);
|
||||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
|
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
|
||||||
#after_enable
|
#after_enable
|
||||||
#rst
|
#rst
|
||||||
})
|
|
||||||
}
|
}
|
||||||
fn disable() {
|
fn disable_with_cs(_cs: critical_section::CriticalSection) {
|
||||||
critical_section::with(|_cs| {
|
|
||||||
#before_disable
|
#before_disable
|
||||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
|
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
crate::rcc::clock_refcount_sub(_cs);
|
crate::rcc::clock_refcount_sub(_cs);
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,18 +567,14 @@ foreach_peripheral!(
|
|||||||
critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
|
critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_and_reset() {
|
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
|
||||||
critical_section::with(|_| {
|
|
||||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
|
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
|
||||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
|
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
|
||||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
|
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable() {
|
fn disable_with_cs(_cs: critical_section::CriticalSection) {
|
||||||
critical_section::with(|_| {
|
|
||||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
|
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,10 +77,10 @@ impl State {
|
|||||||
static STATE: State = State::new();
|
static STATE: State = State::new();
|
||||||
|
|
||||||
/// safety: must be called only once
|
/// 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! {
|
foreach_interrupt! {
|
||||||
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
|
($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();
|
crate::interrupt::typelevel::$irq::enable();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -154,10 +154,10 @@ impl State {
|
|||||||
static STATE: State = State::new();
|
static STATE: State = State::new();
|
||||||
|
|
||||||
/// safety: must be called only once
|
/// 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! {
|
foreach_interrupt! {
|
||||||
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
|
($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();
|
interrupt::typelevel::$irq::enable();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,6 @@ foreach_dma_channel! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// safety: must be called only once
|
/// safety: must be called only once
|
||||||
pub(crate) unsafe fn init() {
|
pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||||
crate::_generated::init_dmamux();
|
crate::_generated::init_dmamux();
|
||||||
}
|
}
|
||||||
|
@ -53,10 +53,10 @@ impl State {
|
|||||||
static STATE: State = State::new();
|
static STATE: State = State::new();
|
||||||
|
|
||||||
/// safety: must be called only once
|
/// 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! {
|
foreach_interrupt! {
|
||||||
($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
|
($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();
|
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
|
// safety: must be called only once at startup
|
||||||
pub(crate) unsafe fn init(
|
pub(crate) unsafe fn init(
|
||||||
|
cs: critical_section::CriticalSection,
|
||||||
#[cfg(bdma)] bdma_priority: Priority,
|
#[cfg(bdma)] bdma_priority: Priority,
|
||||||
#[cfg(dma)] dma_priority: Priority,
|
#[cfg(dma)] dma_priority: Priority,
|
||||||
#[cfg(gpdma)] gpdma_priority: Priority,
|
#[cfg(gpdma)] gpdma_priority: Priority,
|
||||||
) {
|
) {
|
||||||
#[cfg(bdma)]
|
#[cfg(bdma)]
|
||||||
bdma::init(bdma_priority);
|
bdma::init(cs, bdma_priority);
|
||||||
#[cfg(dma)]
|
#[cfg(dma)]
|
||||||
dma::init(dma_priority);
|
dma::init(cs, dma_priority);
|
||||||
#[cfg(gpdma)]
|
#[cfg(gpdma)]
|
||||||
gpdma::init(gpdma_priority);
|
gpdma::init(cs, gpdma_priority);
|
||||||
#[cfg(dmamux)]
|
#[cfg(dmamux)]
|
||||||
dmamux::init();
|
dmamux::init(cs);
|
||||||
}
|
}
|
||||||
|
@ -367,7 +367,7 @@ macro_rules! enable_irq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// safety: must be called only once
|
/// 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;
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
|
|
||||||
foreach_exti_irq!(enable_irq);
|
foreach_exti_irq!(enable_irq);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
|
|
||||||
|
use critical_section::CriticalSection;
|
||||||
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
|
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
|
||||||
|
|
||||||
use crate::pac::gpio::{self, vals};
|
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)]
|
#[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();
|
crate::_generated::init_gpio();
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,8 @@ impl Default for Config {
|
|||||||
|
|
||||||
/// Initialize embassy.
|
/// Initialize embassy.
|
||||||
pub fn init(config: Config) -> Peripherals {
|
pub fn init(config: Config) -> Peripherals {
|
||||||
let p = Peripherals::take();
|
critical_section::with(|cs| {
|
||||||
|
let p = Peripherals::take_with_cs(cs);
|
||||||
|
|
||||||
#[cfg(dbgmcu)]
|
#[cfg(dbgmcu)]
|
||||||
if config.enable_debug_during_sleep {
|
if config.enable_debug_during_sleep {
|
||||||
@ -186,11 +187,11 @@ pub fn init(config: Config) -> Peripherals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
|
#[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)))]
|
#[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)))]
|
#[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))]
|
||||||
peripherals::FLASH::enable_and_reset();
|
peripherals::FLASH::enable_and_reset_with_cs(cs);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
#[cfg(feature = "_split-pins-enabled")]
|
#[cfg(feature = "_split-pins-enabled")]
|
||||||
@ -205,8 +206,9 @@ pub fn init(config: Config) -> Peripherals {
|
|||||||
pmcr.set_pc3so(true);
|
pmcr.set_pc3so(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
gpio::init();
|
gpio::init(cs);
|
||||||
dma::init(
|
dma::init(
|
||||||
|
cs,
|
||||||
#[cfg(bdma)]
|
#[cfg(bdma)]
|
||||||
config.bdma_interrupt_priority,
|
config.bdma_interrupt_priority,
|
||||||
#[cfg(dma)]
|
#[cfg(dma)]
|
||||||
@ -215,21 +217,20 @@ pub fn init(config: Config) -> Peripherals {
|
|||||||
config.gpdma_interrupt_priority,
|
config.gpdma_interrupt_priority,
|
||||||
);
|
);
|
||||||
#[cfg(feature = "exti")]
|
#[cfg(feature = "exti")]
|
||||||
exti::init();
|
exti::init(cs);
|
||||||
|
|
||||||
rcc::init(config.rcc);
|
rcc::init(config.rcc);
|
||||||
|
|
||||||
// must be after rcc init
|
// must be after rcc init
|
||||||
#[cfg(feature = "_time-driver")]
|
#[cfg(feature = "_time-driver")]
|
||||||
time_driver::init();
|
time_driver::init(cs);
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
while !crate::rcc::low_power_ready() {
|
while !crate::rcc::low_power_ready() {
|
||||||
critical_section::with(|cs| {
|
|
||||||
crate::rcc::clock_refcount_sub(cs);
|
crate::rcc::clock_refcount_sub(cs);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p
|
p
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -229,10 +229,19 @@ pub mod low_level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
|
use critical_section::CriticalSection;
|
||||||
|
|
||||||
pub trait RccPeripheral {
|
pub trait RccPeripheral {
|
||||||
fn frequency() -> crate::time::Hertz;
|
fn frequency() -> crate::time::Hertz;
|
||||||
fn enable_and_reset();
|
fn enable_and_reset_with_cs(cs: CriticalSection);
|
||||||
fn disable();
|
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 {
|
impl RtcDriver {
|
||||||
fn init(&'static self) {
|
fn init(&'static self, cs: critical_section::CriticalSection) {
|
||||||
let r = T::regs_gp16();
|
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();
|
let timer_freq = T::frequency();
|
||||||
|
|
||||||
critical_section::with(|_| {
|
|
||||||
r.cr1().modify(|w| w.set_cen(false));
|
r.cr1().modify(|w| w.set_cen(false));
|
||||||
r.cnt().write(|w| w.set_cnt(0));
|
r.cnt().write(|w| w.set_cnt(0));
|
||||||
|
|
||||||
@ -190,7 +189,6 @@ impl RtcDriver {
|
|||||||
unsafe { <T as BasicInstance>::Interrupt::enable() };
|
unsafe { <T as BasicInstance>::Interrupt::enable() };
|
||||||
|
|
||||||
r.cr1().modify(|w| w.set_cen(true));
|
r.cr1().modify(|w| w.set_cen(true));
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_interrupt(&self) {
|
fn on_interrupt(&self) {
|
||||||
@ -462,6 +460,6 @@ pub(crate) fn get_driver() -> &'static RtcDriver {
|
|||||||
&DRIVER
|
&DRIVER
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init(cs: CriticalSection) {
|
||||||
DRIVER.init()
|
DRIVER.init(cs)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user