Merge pull request #382 from fnafnio/typestate_nrf_timer
Typestate nrf timer
This commit is contained in:
commit
d0c8749399
@ -15,9 +15,8 @@ use crate::gpio::sealed::Pin as _;
|
|||||||
use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin};
|
use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin};
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
||||||
use crate::timer::Frequency;
|
|
||||||
use crate::timer::Instance as TimerInstance;
|
use crate::timer::Instance as TimerInstance;
|
||||||
use crate::timer::Timer;
|
use crate::timer::{Frequency, Timer};
|
||||||
use crate::uarte::{Config, Instance as UarteInstance};
|
use crate::uarte::{Config, Instance as UarteInstance};
|
||||||
|
|
||||||
// Re-export SVD variants to allow user to directly set values
|
// Re-export SVD variants to allow user to directly set values
|
||||||
@ -85,7 +84,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
|
|
||||||
let r = U::regs();
|
let r = U::regs();
|
||||||
|
|
||||||
let mut timer = Timer::new_irqless(timer);
|
let mut timer = Timer::new(timer);
|
||||||
|
|
||||||
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
rxd.conf().write(|w| w.input().connect().drive().h0h1());
|
||||||
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
|
||||||
|
@ -27,6 +27,8 @@ pub(crate) mod sealed {
|
|||||||
fn waker(n: usize) -> &'static AtomicWaker;
|
fn waker(n: usize) -> &'static AtomicWaker;
|
||||||
}
|
}
|
||||||
pub trait ExtendedInstance {}
|
pub trait ExtendedInstance {}
|
||||||
|
|
||||||
|
pub trait TimerType {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static + Send {
|
pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static + Send {
|
||||||
@ -84,12 +86,23 @@ pub enum Frequency {
|
|||||||
///
|
///
|
||||||
/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter
|
/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter
|
||||||
/// or trigger an event when the counter reaches a certain value.
|
/// or trigger an event when the counter reaches a certain value.
|
||||||
pub struct Timer<'d, T: Instance> {
|
|
||||||
phantom: PhantomData<&'d mut T>,
|
pub trait TimerType: sealed::TimerType {}
|
||||||
|
|
||||||
|
pub enum Awaitable {}
|
||||||
|
pub enum NotAwaitable {}
|
||||||
|
|
||||||
|
impl sealed::TimerType for Awaitable {}
|
||||||
|
impl sealed::TimerType for NotAwaitable {}
|
||||||
|
impl TimerType for Awaitable {}
|
||||||
|
impl TimerType for NotAwaitable {}
|
||||||
|
|
||||||
|
pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> {
|
||||||
|
phantom: PhantomData<(&'d mut T, I)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Timer<'d, T> {
|
impl<'d, T: Instance> Timer<'d, T, Awaitable> {
|
||||||
pub fn new(
|
pub fn new_awaitable(
|
||||||
timer: impl Unborrow<Target = T> + 'd,
|
timer: impl Unborrow<Target = T> + 'd,
|
||||||
irq: impl Unborrow<Target = T::Interrupt> + 'd,
|
irq: impl Unborrow<Target = T::Interrupt> + 'd,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -101,11 +114,22 @@ impl<'d, T: Instance> Timer<'d, T> {
|
|||||||
|
|
||||||
Self::new_irqless(timer)
|
Self::new_irqless(timer)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
impl<'d, T: Instance> Timer<'d, T, NotAwaitable> {
|
||||||
/// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
|
/// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
|
||||||
///
|
///
|
||||||
/// This is used by `Uarte` internally.
|
/// This can be useful for triggering tasks via PPI
|
||||||
pub(crate) fn new_irqless(_timer: impl Unborrow<Target = T> + 'd) -> Self {
|
/// `Uarte` uses this internally.
|
||||||
|
pub fn new(timer: impl Unborrow<Target = T> + 'd) -> Self {
|
||||||
|
Self::new_irqless(timer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
|
||||||
|
/// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
|
||||||
|
///
|
||||||
|
/// This is used by the public constructors.
|
||||||
|
fn new_irqless(_timer: impl Unborrow<Target = T> + 'd) -> Self {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
@ -208,7 +232,7 @@ impl<'d, T: Instance> Timer<'d, T> {
|
|||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
|
/// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
|
||||||
pub fn cc(&mut self, n: usize) -> Cc<T> {
|
pub fn cc(&mut self, n: usize) -> Cc<T, I> {
|
||||||
if n >= T::CCS {
|
if n >= T::CCS {
|
||||||
panic!(
|
panic!(
|
||||||
"Cannot get CC register {} of timer with {} CC registers.",
|
"Cannot get CC register {} of timer with {} CC registers.",
|
||||||
@ -230,12 +254,48 @@ impl<'d, T: Instance> Timer<'d, T> {
|
|||||||
///
|
///
|
||||||
/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register.
|
/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register.
|
||||||
/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register
|
/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register
|
||||||
pub struct Cc<'a, T: Instance> {
|
pub struct Cc<'a, T: Instance, I: TimerType = NotAwaitable> {
|
||||||
n: usize,
|
n: usize,
|
||||||
phantom: PhantomData<&'a mut T>,
|
phantom: PhantomData<(&'a mut T, I)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Instance> Cc<'a, T> {
|
impl<'a, T: Instance> Cc<'a, T, Awaitable> {
|
||||||
|
/// Wait until the timer's counter reaches the value stored in this register.
|
||||||
|
///
|
||||||
|
/// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`.
|
||||||
|
pub async fn wait(&mut self) {
|
||||||
|
let regs = T::regs();
|
||||||
|
|
||||||
|
// Enable the interrupt for this CC's COMPARE event.
|
||||||
|
regs.intenset
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
|
||||||
|
|
||||||
|
// Disable the interrupt if the future is dropped.
|
||||||
|
let on_drop = OnDrop::new(|| {
|
||||||
|
regs.intenclr
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
|
||||||
|
});
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
T::waker(self.n).register(cx.waker());
|
||||||
|
|
||||||
|
if regs.events_compare[self.n].read().bits() != 0 {
|
||||||
|
// Reset the register for next time
|
||||||
|
regs.events_compare[self.n].reset();
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// The interrupt was already disabled in the interrupt handler, so there's no need to disable it again.
|
||||||
|
on_drop.defuse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, T: Instance> Cc<'a, T, NotAwaitable> {}
|
||||||
|
|
||||||
|
impl<'a, T: Instance, I: TimerType> Cc<'a, T, I> {
|
||||||
/// Get the current value stored in the register.
|
/// Get the current value stored in the register.
|
||||||
pub fn read(&self) -> u32 {
|
pub fn read(&self) -> u32 {
|
||||||
T::regs().cc[self.n].read().cc().bits()
|
T::regs().cc[self.n].read().cc().bits()
|
||||||
@ -304,37 +364,4 @@ impl<'a, T: Instance> Cc<'a, T> {
|
|||||||
.shorts
|
.shorts
|
||||||
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) })
|
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait until the timer's counter reaches the value stored in this register.
|
|
||||||
///
|
|
||||||
/// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`.
|
|
||||||
pub async fn wait(&mut self) {
|
|
||||||
let regs = T::regs();
|
|
||||||
|
|
||||||
// Enable the interrupt for this CC's COMPARE event.
|
|
||||||
regs.intenset
|
|
||||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
|
|
||||||
|
|
||||||
// Disable the interrupt if the future is dropped.
|
|
||||||
let on_drop = OnDrop::new(|| {
|
|
||||||
regs.intenclr
|
|
||||||
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
|
|
||||||
});
|
|
||||||
|
|
||||||
poll_fn(|cx| {
|
|
||||||
T::waker(self.n).register(cx.waker());
|
|
||||||
|
|
||||||
if regs.events_compare[self.n].read().bits() != 0 {
|
|
||||||
// Reset the register for next time
|
|
||||||
regs.events_compare[self.n].reset();
|
|
||||||
Poll::Ready(())
|
|
||||||
} else {
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
// The interrupt was already disabled in the interrupt handler, so there's no need to disable it again.
|
|
||||||
on_drop.defuse();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,8 @@ use crate::gpio::{self, OptionalPin as GpioOptionalPin, Pin as GpioPin};
|
|||||||
use crate::interrupt::Interrupt;
|
use crate::interrupt::Interrupt;
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
||||||
use crate::timer::Frequency;
|
|
||||||
use crate::timer::Instance as TimerInstance;
|
use crate::timer::Instance as TimerInstance;
|
||||||
use crate::timer::Timer;
|
use crate::timer::{Frequency, Timer};
|
||||||
|
|
||||||
// Re-export SVD variants to allow user to directly set values.
|
// Re-export SVD variants to allow user to directly set values.
|
||||||
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
|
||||||
@ -318,7 +317,7 @@ impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let baudrate = config.baudrate;
|
let baudrate = config.baudrate;
|
||||||
let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config);
|
let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config);
|
||||||
let mut timer = Timer::new_irqless(timer);
|
let mut timer = Timer::new(timer);
|
||||||
|
|
||||||
unborrow!(ppi_ch1, ppi_ch2);
|
unborrow!(ppi_ch1, ppi_ch2);
|
||||||
|
|
||||||
|
29
examples/nrf/src/bin/awaitable_timer.rs
Normal file
29
examples/nrf/src/bin/awaitable_timer.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
#[path = "../example_common.rs"]
|
||||||
|
mod example_common;
|
||||||
|
use embassy_nrf::interrupt;
|
||||||
|
use embassy_nrf::timer::Timer;
|
||||||
|
use embassy_nrf::Peripherals;
|
||||||
|
use example_common::info;
|
||||||
|
|
||||||
|
use embassy::executor::Spawner;
|
||||||
|
|
||||||
|
#[embassy::main]
|
||||||
|
async fn main(_spawner: Spawner, p: Peripherals) {
|
||||||
|
let mut t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0));
|
||||||
|
// default frequency is 1MHz, so this triggers every second
|
||||||
|
t.cc(0).write(1_000_000);
|
||||||
|
// clear the timer value on cc[0] compare match
|
||||||
|
t.cc(0).short_compare_clear();
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// wait for compare match
|
||||||
|
t.cc(0).wait().await;
|
||||||
|
info!("hardware timer tick");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user