Skip to content

Commit

Permalink
Implement embedded_hal_async::delay::DelayUs trait for SYSTIMER a…
Browse files Browse the repository at this point in the history
…larms (esp-rs#812)

* Implement `embedded_hal_async::delay::DelayUs` trait for `SYSTIMER` alarms

* Update CHANGELOG.md

* Address review feedback
  • Loading branch information
jessebraham authored Sep 25, 2023
1 parent 56b8edd commit b91b3b1
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 62 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add UART support for splitting into TX and RX (#754)
- Async support for I2S (#801)
- Async support for PARL_IO (#807)
- Implement `embeded_hal_async::delay::DelayUs` trait for `SYSTIMER` alarms (#812)

### Changed

Expand All @@ -42,6 +43,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `Uart::new` now takes the `&Clocks` struct to ensure baudrate is correct for CPU/APB speed. (#808)
- `Uart::new_with_config` takes an `Config` instead of `Option<Config>`. (#808)
- `Alarm::set_period` takes a period (duration) instead of a frequency (#812)
- `Alarm::interrupt_clear` is now `Alarm::clear_interrupt` to be consistent (#812)

## [0.12.0]

Expand Down
16 changes: 8 additions & 8 deletions esp-hal-common/src/embassy/time_driver_systimer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl EmbassyTimer {

fn on_interrupt(&self, id: usize) {
critical_section::with(|cs| {
self.clear_interrupt(id);
self.interrupt_clear(id);
self.trigger_alarm(id, cs);
})
}
Expand Down Expand Up @@ -96,11 +96,11 @@ impl EmbassyTimer {
})
}

fn clear_interrupt(&self, id: usize) {
fn interrupt_clear(&self, id: usize) {
match id {
0 => self.alarm0.clear_interrupt(),
1 => self.alarm1.clear_interrupt(),
2 => self.alarm2.clear_interrupt(),
0 => self.alarm0.interrupt_clear(),
1 => self.alarm1.interrupt_clear(),
2 => self.alarm2.interrupt_clear(),
_ => {}
}
}
Expand All @@ -109,15 +109,15 @@ impl EmbassyTimer {
match id {
0 => {
self.alarm0.set_target(timestamp);
self.alarm0.interrupt_enable(true);
self.alarm0.enable_interrupt(true);
}
1 => {
self.alarm1.set_target(timestamp);
self.alarm1.interrupt_enable(true);
self.alarm1.enable_interrupt(true);
}
2 => {
self.alarm2.set_target(timestamp);
self.alarm2.interrupt_enable(true);
self.alarm2.enable_interrupt(true);
}
_ => {}
}
Expand Down
119 changes: 111 additions & 8 deletions esp-hal-common/src/systimer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl<'d> SystemTimer<'d> {
#[cfg(esp32s2)]
pub const BIT_MASK: u64 = u64::MAX;
#[cfg(not(esp32s2))]
pub const BIT_MASK: u64 = 0xFFFFFFFFFFFFF;
pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF;

#[cfg(esp32s2)]
pub const TICKS_PER_SECOND: u64 = 80_000_000; // TODO this can change when we have support for changing APB frequency
Expand Down Expand Up @@ -114,7 +114,7 @@ impl<T, const CHANNEL: u8> Alarm<T, CHANNEL> {
Self { _pd: PhantomData }
}

pub fn interrupt_enable(&self, val: bool) {
pub fn enable_interrupt(&self, val: bool) {
let systimer = unsafe { &*SYSTIMER::ptr() };
match CHANNEL {
0 => systimer.int_ena.modify(|_, w| w.target0_int_ena().bit(val)),
Expand All @@ -124,7 +124,7 @@ impl<T, const CHANNEL: u8> Alarm<T, CHANNEL> {
}
}

pub fn clear_interrupt(&self) {
pub fn interrupt_clear(&self) {
let systimer = unsafe { &*SYSTIMER::ptr() };
match CHANNEL {
0 => systimer.int_clr.write(|w| w.target0_int_clr().set_bit()),
Expand Down Expand Up @@ -225,19 +225,20 @@ impl<const CHANNEL: u8> Alarm<Target, CHANNEL> {
}

impl<const CHANNEL: u8> Alarm<Periodic, CHANNEL> {
pub fn set_period(&self, period: fugit::HertzU32) {
let time_period: MicrosDurationU32 = period.into_duration();
let us = time_period.ticks();
pub fn set_period(&self, period: MicrosDurationU32) {
let us = period.ticks();
let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000) as u32;

self.configure(|tconf, hi, lo| unsafe {
tconf.write(|w| {
w.target0_period_mode()
.set_bit()
.target0_period()
.bits(us * (SystemTimer::TICKS_PER_SECOND as u32 / 1000_000))
.bits(ticks)
});
hi.write(|w| w.timer_target0_hi().bits(0));
lo.write(|w| w.timer_target0_lo().bits(0));
})
});
}

pub fn into_target(self) -> Alarm<Target, CHANNEL> {
Expand All @@ -262,3 +263,105 @@ impl<T> Alarm<T, 2> {
Self { _pd: PhantomData }
}
}

#[cfg(feature = "async")]
mod asynch {
use core::{
pin::Pin,
task::{Context, Poll},
};

use embassy_sync::waitqueue::AtomicWaker;
use procmacros::interrupt;

use super::*;

const NUM_ALARMS: usize = 3;

const INIT: AtomicWaker = AtomicWaker::new();
static WAKERS: [AtomicWaker; NUM_ALARMS] = [INIT; NUM_ALARMS];

pub(crate) struct AlarmFuture<'a, const N: u8> {
phantom: PhantomData<&'a Alarm<Periodic, N>>,
}

impl<'a, const N: u8> AlarmFuture<'a, N> {
pub(crate) fn new(alarm: &'a Alarm<Periodic, N>) -> Self {
alarm.interrupt_clear();
alarm.enable_interrupt(true);

Self {
phantom: PhantomData,
}
}

fn event_bit_is_clear(&self) -> bool {
let r = unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena
.read();

match N {
0 => r.target0_int_ena().bit_is_clear(),
1 => r.target1_int_ena().bit_is_clear(),
2 => r.target2_int_ena().bit_is_clear(),
_ => unreachable!(),
}
}
}

impl<'a, const N: u8> core::future::Future for AlarmFuture<'a, N> {
type Output = ();

fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
WAKERS[N as usize].register(ctx.waker());

if self.event_bit_is_clear() {
Poll::Ready(())
} else {
Poll::Pending
}
}
}

impl<const CHANNEL: u8> embedded_hal_async::delay::DelayUs for Alarm<Periodic, CHANNEL> {
async fn delay_us(&mut self, us: u32) {
let period = MicrosDurationU32::from_ticks(us);
self.set_period(period);

AlarmFuture::new(self).await;
}

async fn delay_ms(&mut self, ms: u32) {
for _ in 0..ms {
self.delay_us(1000).await;
}
}
}

#[interrupt]
fn SYSTIMER_TARGET0() {
unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena
.modify(|_, w| w.target0_int_ena().clear_bit());

WAKERS[0].wake();
}

#[interrupt]
fn SYSTIMER_TARGET1() {
unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena
.modify(|_, w| w.target1_int_ena().clear_bit());

WAKERS[1].wake();
}

#[interrupt]
fn SYSTIMER_TARGET2() {
unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena
.modify(|_, w| w.target2_int_ena().clear_bit());

WAKERS[2].wake();
}
}
16 changes: 8 additions & 8 deletions esp32c2-hal/examples/systimer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ fn main() -> ! {
println!("SYSTIMER Current value = {}", SystemTimer::now());

let alarm0 = syst.alarm0.into_periodic();
alarm0.set_period(1u32.Hz());
alarm0.clear_interrupt();
alarm0.interrupt_enable(true);
alarm0.set_period(1u32.secs());
alarm0.interrupt_clear();
alarm0.enable_interrupt(true);

let alarm1 = syst.alarm1;
alarm1.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 2));
alarm1.interrupt_enable(true);
alarm1.enable_interrupt(true);

let alarm2 = syst.alarm2;
alarm2.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 3));
alarm2.interrupt_enable(true);
alarm2.enable_interrupt(true);

critical_section::with(|cs| {
ALARM0.borrow_ref_mut(cs).replace(alarm0);
Expand Down Expand Up @@ -85,7 +85,7 @@ fn SYSTIMER_TARGET0() {
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
.interrupt_clear()
});
}

Expand All @@ -97,7 +97,7 @@ fn SYSTIMER_TARGET1() {
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
.interrupt_clear()
});
}

Expand All @@ -109,6 +109,6 @@ fn SYSTIMER_TARGET2() {
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
.interrupt_clear()
});
}
16 changes: 8 additions & 8 deletions esp32c3-hal/examples/systimer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ fn main() -> ! {
println!("SYSTIMER Current value = {}", SystemTimer::now());

let alarm0 = syst.alarm0.into_periodic();
alarm0.set_period(1u32.Hz());
alarm0.clear_interrupt();
alarm0.interrupt_enable(true);
alarm0.set_period(1u32.secs());
alarm0.interrupt_clear();
alarm0.enable_interrupt(true);

let alarm1 = syst.alarm1;
alarm1.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 2));
alarm1.interrupt_enable(true);
alarm1.enable_interrupt(true);

let alarm2 = syst.alarm2;
alarm2.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 3));
alarm2.interrupt_enable(true);
alarm2.enable_interrupt(true);

critical_section::with(|cs| {
ALARM0.borrow_ref_mut(cs).replace(alarm0);
Expand Down Expand Up @@ -85,7 +85,7 @@ fn SYSTIMER_TARGET0() {
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
.interrupt_clear()
});
}

Expand All @@ -97,7 +97,7 @@ fn SYSTIMER_TARGET1() {
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
.interrupt_clear()
});
}

Expand All @@ -109,6 +109,6 @@ fn SYSTIMER_TARGET2() {
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
.interrupt_clear()
});
}
16 changes: 8 additions & 8 deletions esp32c6-hal/examples/systimer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ fn main() -> ! {
println!("SYSTIMER Current value = {}", SystemTimer::now());

let alarm0 = syst.alarm0.into_periodic();
alarm0.set_period(1u32.Hz());
alarm0.clear_interrupt();
alarm0.interrupt_enable(true);
alarm0.set_period(1u32.secs());
alarm0.interrupt_clear();
alarm0.enable_interrupt(true);

let alarm1 = syst.alarm1;
alarm1.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 2));
alarm1.interrupt_enable(true);
alarm1.enable_interrupt(true);

let alarm2 = syst.alarm2;
alarm2.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 3));
alarm2.interrupt_enable(true);
alarm2.enable_interrupt(true);

critical_section::with(|cs| {
ALARM0.borrow_ref_mut(cs).replace(alarm0);
Expand Down Expand Up @@ -85,7 +85,7 @@ fn SYSTIMER_TARGET0() {
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
.interrupt_clear()
});
}

Expand All @@ -97,7 +97,7 @@ fn SYSTIMER_TARGET1() {
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
.interrupt_clear()
});
}

Expand All @@ -109,6 +109,6 @@ fn SYSTIMER_TARGET2() {
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
.interrupt_clear()
});
}
Loading

0 comments on commit b91b3b1

Please sign in to comment.