stm32/low-power: create one critical-section for all time ops
This commit is contained in:
parent
02b0523199
commit
7cf327130e
@ -64,7 +64,11 @@ impl super::Rtc {
|
|||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
/// start the wakeup alarm and wtih a duration that is as close to but less than
|
/// start the wakeup alarm and wtih a duration that is as close to but less than
|
||||||
/// the requested duration, and record the instant the wakeup alarm was started
|
/// the requested duration, and record the instant the wakeup alarm was started
|
||||||
pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) {
|
pub(crate) fn start_wakeup_alarm(
|
||||||
|
&self,
|
||||||
|
requested_duration: embassy_time::Duration,
|
||||||
|
cs: critical_section::CriticalSection,
|
||||||
|
) {
|
||||||
use embassy_time::{Duration, TICK_HZ};
|
use embassy_time::{Duration, TICK_HZ};
|
||||||
|
|
||||||
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
||||||
@ -102,25 +106,13 @@ impl super::Rtc {
|
|||||||
self.instant(),
|
self.instant(),
|
||||||
);
|
);
|
||||||
|
|
||||||
critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none()))
|
assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
|
||||||
pub(crate) fn enable_wakeup_line(&self) {
|
|
||||||
use crate::interrupt::typelevel::Interrupt;
|
|
||||||
use crate::pac::EXTI;
|
|
||||||
|
|
||||||
<RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
|
|
||||||
unsafe { <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::enable() };
|
|
||||||
|
|
||||||
EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
|
||||||
EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
/// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
|
/// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
|
||||||
/// was called, otherwise none
|
/// was called, otherwise none
|
||||||
pub(crate) fn stop_wakeup_alarm(&self) -> Option<embassy_time::Duration> {
|
pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
|
||||||
use crate::interrupt::typelevel::Interrupt;
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
|
|
||||||
trace!("rtc: stop wakeup alarm at {}", self.instant());
|
trace!("rtc: stop wakeup alarm at {}", self.instant());
|
||||||
@ -137,13 +129,23 @@ impl super::Rtc {
|
|||||||
<RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
|
<RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
|
||||||
});
|
});
|
||||||
|
|
||||||
critical_section::with(|cs| {
|
|
||||||
if let Some(stop_time) = self.stop_time.borrow(cs).take() {
|
if let Some(stop_time) = self.stop_time.borrow(cs).take() {
|
||||||
Some(self.instant() - stop_time)
|
Some(self.instant() - stop_time)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "low-power")]
|
||||||
|
pub(crate) fn enable_wakeup_line(&self) {
|
||||||
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
|
use crate::pac::EXTI;
|
||||||
|
|
||||||
|
<RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
|
||||||
|
unsafe { <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::enable() };
|
||||||
|
|
||||||
|
EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||||
|
EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the RTC config
|
/// Applies the RTC config
|
||||||
|
@ -266,16 +266,13 @@ impl RtcDriver {
|
|||||||
f(alarm.ctx.get());
|
f(alarm.ctx.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
/*
|
||||||
/// Set the rtc but panic if it's already been set
|
Low-power private functions: all operate within a critical seciton
|
||||||
pub(crate) fn set_rtc(&self, rtc: &'static Rtc) {
|
*/
|
||||||
critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
/// Compute the approximate amount of time until the next alarm
|
/// Compute the approximate amount of time until the next alarm
|
||||||
fn time_until_next_alarm(&self) -> embassy_time::Duration {
|
fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration {
|
||||||
critical_section::with(|cs| {
|
|
||||||
let now = self.now() + 32;
|
let now = self.now() + 32;
|
||||||
|
|
||||||
embassy_time::Duration::from_ticks(
|
embassy_time::Duration::from_ticks(
|
||||||
@ -286,12 +283,11 @@ impl RtcDriver {
|
|||||||
.min()
|
.min()
|
||||||
.unwrap_or(u64::MAX),
|
.unwrap_or(u64::MAX),
|
||||||
)
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
/// Add the given offset to the current time
|
/// Add the given offset to the current time
|
||||||
fn add_time(&self, offset: embassy_time::Duration) {
|
fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
|
||||||
let offset = offset.as_ticks();
|
let offset = offset.as_ticks();
|
||||||
let cnt = T::regs_gp16().cnt().read().cnt() as u32;
|
let cnt = T::regs_gp16().cnt().read().cnt() as u32;
|
||||||
let period = self.period.load(Ordering::SeqCst);
|
let period = self.period.load(Ordering::SeqCst);
|
||||||
@ -322,51 +318,57 @@ impl RtcDriver {
|
|||||||
T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16));
|
T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16));
|
||||||
|
|
||||||
// Now, recompute all alarms
|
// Now, recompute all alarms
|
||||||
critical_section::with(|cs| {
|
|
||||||
for i in 0..ALARM_COUNT {
|
for i in 0..ALARM_COUNT {
|
||||||
let alarm_handle = unsafe { AlarmHandle::new(i as u8) };
|
let alarm_handle = unsafe { AlarmHandle::new(i as u8) };
|
||||||
let alarm = self.get_alarm(cs, alarm_handle);
|
let alarm = self.get_alarm(cs, alarm_handle);
|
||||||
|
|
||||||
self.set_alarm(alarm_handle, alarm.timestamp.get());
|
self.set_alarm(alarm_handle, alarm.timestamp.get());
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
/// Stop the wakeup alarm, if enabled, and add the appropriate offset
|
/// Stop the wakeup alarm, if enabled, and add the appropriate offset
|
||||||
fn stop_wakeup_alarm(&self) {
|
fn stop_wakeup_alarm(&self, cs: CriticalSection) {
|
||||||
critical_section::with(|cs| {
|
if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) {
|
||||||
if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm() {
|
self.add_time(offset, cs);
|
||||||
self.add_time(offset);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Low-power public functions: all create a critical section
|
||||||
|
*/
|
||||||
|
#[cfg(feature = "low-power")]
|
||||||
|
/// Set the rtc but panic if it's already been set
|
||||||
|
pub(crate) fn set_rtc(&self, rtc: &'static Rtc) {
|
||||||
|
critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
/// Pause the timer if ready; return err if not
|
/// Pause the timer if ready; return err if not
|
||||||
pub(crate) fn pause_time(&self) -> Result<(), ()> {
|
pub(crate) fn pause_time(&self) -> Result<(), ()> {
|
||||||
|
critical_section::with(|cs| {
|
||||||
/*
|
/*
|
||||||
If the wakeup timer is currently running, then we need to stop it and
|
If the wakeup timer is currently running, then we need to stop it and
|
||||||
add the elapsed time to the current time
|
add the elapsed time to the current time, as this will impact the result
|
||||||
|
of `time_until_next_alarm`.
|
||||||
*/
|
*/
|
||||||
self.stop_wakeup_alarm();
|
self.stop_wakeup_alarm(cs);
|
||||||
|
|
||||||
let time_until_next_alarm = self.time_until_next_alarm();
|
let time_until_next_alarm = self.time_until_next_alarm(cs);
|
||||||
if time_until_next_alarm < embassy_time::Duration::from_millis(250) {
|
if time_until_next_alarm < embassy_time::Duration::from_millis(250) {
|
||||||
Err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
critical_section::with(|cs| {
|
|
||||||
self.rtc
|
self.rtc
|
||||||
.borrow(cs)
|
.borrow(cs)
|
||||||
.get()
|
.get()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.start_wakeup_alarm(time_until_next_alarm);
|
.start_wakeup_alarm(time_until_next_alarm, cs);
|
||||||
});
|
|
||||||
|
|
||||||
T::regs_gp16().cr1().modify(|w| w.set_cen(false));
|
T::regs_gp16().cr1().modify(|w| w.set_cen(false));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
@ -378,9 +380,11 @@ impl RtcDriver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stop_wakeup_alarm();
|
critical_section::with(|cs| {
|
||||||
|
self.stop_wakeup_alarm(cs);
|
||||||
|
|
||||||
T::regs_gp16().cr1().modify(|w| w.set_cen(true));
|
T::regs_gp16().cr1().modify(|w| w.set_cen(true));
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,14 +19,32 @@ use static_cell::make_static;
|
|||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let executor = Executor::take();
|
Executor::take().run(|spawner| {
|
||||||
executor.run(|spawner| {
|
|
||||||
unwrap!(spawner.spawn(async_main(spawner)));
|
unwrap!(spawner.spawn(async_main(spawner)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn async_main(_spawner: Spawner) {
|
async fn task_1() {
|
||||||
|
for _ in 0..9 {
|
||||||
|
info!("task 1: waiting for 500ms...");
|
||||||
|
Timer::after(Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn task_2() {
|
||||||
|
for _ in 0..5 {
|
||||||
|
info!("task 2: waiting for 1000ms...");
|
||||||
|
Timer::after(Duration::from_millis(1000)).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Test OK");
|
||||||
|
cortex_m::asm::bkpt();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn async_main(spawner: Spawner) {
|
||||||
let mut config = config();
|
let mut config = config();
|
||||||
|
|
||||||
config.rcc.lse = Some(Hertz(32_768));
|
config.rcc.lse = Some(Hertz(32_768));
|
||||||
@ -48,11 +66,6 @@ async fn async_main(_spawner: Spawner) {
|
|||||||
|
|
||||||
stop_with_rtc(rtc);
|
stop_with_rtc(rtc);
|
||||||
|
|
||||||
info!("Waiting...");
|
spawner.spawn(task_1()).unwrap();
|
||||||
Timer::after(Duration::from_secs(2)).await;
|
spawner.spawn(task_2()).unwrap();
|
||||||
info!("Waiting...");
|
|
||||||
Timer::after(Duration::from_secs(3)).await;
|
|
||||||
|
|
||||||
info!("Test OK");
|
|
||||||
cortex_m::asm::bkpt();
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user