Skip to content

Commit

Permalink
refactor: fix embasy time driver implementation
Browse files Browse the repository at this point in the history
The original time driver is actually running on so-called "low-power" mode.
i.e. it does not tick. It sleeps(WFI) to next alarm instead.
The Embassy timer driver implies the tick should be activated every TICK_HZ.
This is OK for EXTI awaits, which also awakes the core.But it'll fail when
using peripherals like DMA(requires CPU time to finish job).
  • Loading branch information
andelf committed Apr 30, 2024
1 parent 54e0861 commit 9cfc045
Showing 1 changed file with 12 additions and 6 deletions.
18 changes: 12 additions & 6 deletions src/embassy/time_driver_systick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ impl SystickDriver {

// UNDOCUMENTED: Avoid initial interrupt
rb.cmp().write(|w| *w = u64::MAX - 1);
rb.cmp().write_value(0);
critical_section::with(|_| {
rb.sr().write(|w| w.set_cntif(false)); // clear

// Configration: Upcount, No reload, HCLK as clock source
rb.ctlr().modify(|w| {
w.set_init(true);
// w.set_init(true);
w.set_mode(vals::Mode::UPCOUNT);
w.set_stre(false);
w.set_stclk(vals::Stclk::HCLK);
Expand All @@ -78,12 +79,20 @@ impl SystickDriver {
#[inline(always)]
fn on_interrupt(&self) {
let rb = &crate::pac::SYSTICK;
rb.ctlr().modify(|w| w.set_stie(false)); // disable interrupt
rb.sr().write(|w| w.set_cntif(false)); // clear IF

critical_section::with(|cs| {
let next_timestamp = critical_section::with(|cs| {
let next = self.alarms.borrow(cs)[0].timestamp.get();
if next > self.now() {
return next;
}
self.trigger_alarm(cs);
return u64::MAX;
});

let period = self.period.load(Ordering::Relaxed) as u64;
let new_cmp = u64::min(self.raw_cnt().wrapping_add(period), next_timestamp * period);
rb.cmp().write_value(new_cmp);
}

fn trigger_alarm(&self, cs: CriticalSection) {
Expand Down Expand Up @@ -157,15 +166,12 @@ impl Driver for SystickDriver {
if timestamp <= t {
// If alarm timestamp has passed the alarm will not fire.
// Disarm the alarm and return `false` to indicate that.
rb.ctlr().modify(|w| w.set_stie(false));

alarm.timestamp.set(u64::MAX);

return false;
}

let safe_cmp = timestamp.saturating_add(period);
rb.cmp().write_value(safe_cmp);
rb.ctlr().modify(|w| w.set_stie(true));

true
Expand Down

0 comments on commit 9cfc045

Please sign in to comment.