aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-09-02 13:39:55 +0200
committerGitHub <[email protected]>2021-09-02 13:39:55 +0200
commitd0c87493996cd5a80ad02533a888eef47fb94ba3 (patch)
treed7d1fd8c291862c567a1536435483e93934e45b7
parentdb3cb02032fd6b861b2c39a0a354767cc72af1df (diff)
parent34c66fa78d700fa5ca324dd043dc0861694ea693 (diff)
Merge pull request #382 from fnafnio/typestate_nrf_timer
Typestate nrf timer
-rw-r--r--embassy-nrf/src/buffered_uarte.rs5
-rw-r--r--embassy-nrf/src/timer.rs113
-rw-r--r--embassy-nrf/src/uarte.rs5
-rw-r--r--examples/nrf/src/bin/awaitable_timer.rs29
4 files changed, 103 insertions, 49 deletions
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 048c36d39..90ce49582 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -15,9 +15,8 @@ use crate::gpio::sealed::Pin as _;
15use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin}; 15use crate::gpio::{OptionalPin as GpioOptionalPin, Pin as GpioPin};
16use crate::pac; 16use crate::pac;
17use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 17use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
18use crate::timer::Frequency;
19use crate::timer::Instance as TimerInstance; 18use crate::timer::Instance as TimerInstance;
20use crate::timer::Timer; 19use crate::timer::{Frequency, Timer};
21use crate::uarte::{Config, Instance as UarteInstance}; 20use crate::uarte::{Config, Instance as UarteInstance};
22 21
23// Re-export SVD variants to allow user to directly set values 22// 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> {
85 84
86 let r = U::regs(); 85 let r = U::regs();
87 86
88 let mut timer = Timer::new_irqless(timer); 87 let mut timer = Timer::new(timer);
89 88
90 rxd.conf().write(|w| w.input().connect().drive().h0h1()); 89 rxd.conf().write(|w| w.input().connect().drive().h0h1());
91 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); 90 r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) });
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index eab9a1416..638fd8229 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -27,6 +27,8 @@ pub(crate) mod sealed {
27 fn waker(n: usize) -> &'static AtomicWaker; 27 fn waker(n: usize) -> &'static AtomicWaker;
28 } 28 }
29 pub trait ExtendedInstance {} 29 pub trait ExtendedInstance {}
30
31 pub trait TimerType {}
30} 32}
31 33
32pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static + Send { 34pub trait Instance: Unborrow<Target = Self> + sealed::Instance + 'static + Send {
@@ -84,12 +86,23 @@ pub enum Frequency {
84/// 86///
85/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter 87/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter
86/// or trigger an event when the counter reaches a certain value. 88/// or trigger an event when the counter reaches a certain value.
87pub struct Timer<'d, T: Instance> { 89
88 phantom: PhantomData<&'d mut T>, 90pub trait TimerType: sealed::TimerType {}
91
92pub enum Awaitable {}
93pub enum NotAwaitable {}
94
95impl sealed::TimerType for Awaitable {}
96impl sealed::TimerType for NotAwaitable {}
97impl TimerType for Awaitable {}
98impl TimerType for NotAwaitable {}
99
100pub struct Timer<'d, T: Instance, I: TimerType = NotAwaitable> {
101 phantom: PhantomData<(&'d mut T, I)>,
89} 102}
90 103
91impl<'d, T: Instance> Timer<'d, T> { 104impl<'d, T: Instance> Timer<'d, T, Awaitable> {
92 pub fn new( 105 pub fn new_awaitable(
93 timer: impl Unborrow<Target = T> + 'd, 106 timer: impl Unborrow<Target = T> + 'd,
94 irq: impl Unborrow<Target = T::Interrupt> + 'd, 107 irq: impl Unborrow<Target = T::Interrupt> + 'd,
95 ) -> Self { 108 ) -> Self {
@@ -101,11 +114,22 @@ impl<'d, T: Instance> Timer<'d, T> {
101 114
102 Self::new_irqless(timer) 115 Self::new_irqless(timer)
103 } 116 }
117}
118impl<'d, T: Instance> Timer<'d, T, NotAwaitable> {
119 /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
120 ///
121 /// This can be useful for triggering tasks via PPI
122 /// `Uarte` uses this internally.
123 pub fn new(timer: impl Unborrow<Target = T> + 'd) -> Self {
124 Self::new_irqless(timer)
125 }
126}
104 127
128impl<'d, T: Instance, I: TimerType> Timer<'d, T, I> {
105 /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work. 129 /// Create a `Timer` without an interrupt, meaning `Cc::wait` won't work.
106 /// 130 ///
107 /// This is used by `Uarte` internally. 131 /// This is used by the public constructors.
108 pub(crate) fn new_irqless(_timer: impl Unborrow<Target = T> + 'd) -> Self { 132 fn new_irqless(_timer: impl Unborrow<Target = T> + 'd) -> Self {
109 let regs = T::regs(); 133 let regs = T::regs();
110 134
111 let mut this = Self { 135 let mut this = Self {
@@ -208,7 +232,7 @@ impl<'d, T: Instance> Timer<'d, T> {
208 /// 232 ///
209 /// # Panics 233 /// # Panics
210 /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). 234 /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
211 pub fn cc(&mut self, n: usize) -> Cc<T> { 235 pub fn cc(&mut self, n: usize) -> Cc<T, I> {
212 if n >= T::CCS { 236 if n >= T::CCS {
213 panic!( 237 panic!(
214 "Cannot get CC register {} of timer with {} CC registers.", 238 "Cannot get CC register {} of timer with {} CC registers.",
@@ -230,12 +254,48 @@ impl<'d, T: Instance> Timer<'d, T> {
230/// 254///
231/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. 255/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register.
232/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register 256/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register
233pub struct Cc<'a, T: Instance> { 257pub struct Cc<'a, T: Instance, I: TimerType = NotAwaitable> {
234 n: usize, 258 n: usize,
235 phantom: PhantomData<&'a mut T>, 259 phantom: PhantomData<(&'a mut T, I)>,
260}
261
262impl<'a, T: Instance> Cc<'a, T, Awaitable> {
263 /// Wait until the timer's counter reaches the value stored in this register.
264 ///
265 /// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`.
266 pub async fn wait(&mut self) {
267 let regs = T::regs();
268
269 // Enable the interrupt for this CC's COMPARE event.
270 regs.intenset
271 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
272
273 // Disable the interrupt if the future is dropped.
274 let on_drop = OnDrop::new(|| {
275 regs.intenclr
276 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
277 });
278
279 poll_fn(|cx| {
280 T::waker(self.n).register(cx.waker());
281
282 if regs.events_compare[self.n].read().bits() != 0 {
283 // Reset the register for next time
284 regs.events_compare[self.n].reset();
285 Poll::Ready(())
286 } else {
287 Poll::Pending
288 }
289 })
290 .await;
291
292 // The interrupt was already disabled in the interrupt handler, so there's no need to disable it again.
293 on_drop.defuse();
294 }
236} 295}
296impl<'a, T: Instance> Cc<'a, T, NotAwaitable> {}
237 297
238impl<'a, T: Instance> Cc<'a, T> { 298impl<'a, T: Instance, I: TimerType> Cc<'a, T, I> {
239 /// Get the current value stored in the register. 299 /// Get the current value stored in the register.
240 pub fn read(&self) -> u32 { 300 pub fn read(&self) -> u32 {
241 T::regs().cc[self.n].read().cc().bits() 301 T::regs().cc[self.n].read().cc().bits()
@@ -304,37 +364,4 @@ impl<'a, T: Instance> Cc<'a, T> {
304 .shorts 364 .shorts
305 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) }) 365 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) })
306 } 366 }
307
308 /// Wait until the timer's counter reaches the value stored in this register.
309 ///
310 /// This requires a mutable reference so that this task's waker cannot be overwritten by a second call to `wait`.
311 pub async fn wait(&mut self) {
312 let regs = T::regs();
313
314 // Enable the interrupt for this CC's COMPARE event.
315 regs.intenset
316 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
317
318 // Disable the interrupt if the future is dropped.
319 let on_drop = OnDrop::new(|| {
320 regs.intenclr
321 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (16 + self.n))) });
322 });
323
324 poll_fn(|cx| {
325 T::waker(self.n).register(cx.waker());
326
327 if regs.events_compare[self.n].read().bits() != 0 {
328 // Reset the register for next time
329 regs.events_compare[self.n].reset();
330 Poll::Ready(())
331 } else {
332 Poll::Pending
333 }
334 })
335 .await;
336
337 // The interrupt was already disabled in the interrupt handler, so there's no need to disable it again.
338 on_drop.defuse();
339 }
340} 367}
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index b2b298661..a6909be68 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -18,9 +18,8 @@ use crate::gpio::{self, OptionalPin as GpioOptionalPin, Pin as GpioPin};
18use crate::interrupt::Interrupt; 18use crate::interrupt::Interrupt;
19use crate::pac; 19use crate::pac;
20use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 20use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
21use crate::timer::Frequency;
22use crate::timer::Instance as TimerInstance; 21use crate::timer::Instance as TimerInstance;
23use crate::timer::Timer; 22use crate::timer::{Frequency, Timer};
24 23
25// Re-export SVD variants to allow user to directly set values. 24// Re-export SVD variants to allow user to directly set values.
26pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 25pub 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> {
318 ) -> Self { 317 ) -> Self {
319 let baudrate = config.baudrate; 318 let baudrate = config.baudrate;
320 let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config); 319 let uarte = Uarte::new(uarte, irq, rxd, txd, cts, rts, config);
321 let mut timer = Timer::new_irqless(timer); 320 let mut timer = Timer::new(timer);
322 321
323 unborrow!(ppi_ch1, ppi_ch2); 322 unborrow!(ppi_ch1, ppi_ch2);
324 323
diff --git a/examples/nrf/src/bin/awaitable_timer.rs b/examples/nrf/src/bin/awaitable_timer.rs
new file mode 100644
index 000000000..289a33c71
--- /dev/null
+++ b/examples/nrf/src/bin/awaitable_timer.rs
@@ -0,0 +1,29 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4#![allow(incomplete_features)]
5
6#[path = "../example_common.rs"]
7mod example_common;
8use embassy_nrf::interrupt;
9use embassy_nrf::timer::Timer;
10use embassy_nrf::Peripherals;
11use example_common::info;
12
13use embassy::executor::Spawner;
14
15#[embassy::main]
16async fn main(_spawner: Spawner, p: Peripherals) {
17 let mut t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0));
18 // default frequency is 1MHz, so this triggers every second
19 t.cc(0).write(1_000_000);
20 // clear the timer value on cc[0] compare match
21 t.cc(0).short_compare_clear();
22 t.start();
23
24 loop {
25 // wait for compare match
26 t.cc(0).wait().await;
27 info!("hardware timer tick");
28 }
29}