nrf52_hal_common/timer.rs
1//! HAL interface to the TIMER peripheral
2//!
3//! See product specification, chapter 24.
4
5use core::ops::Deref;
6
7use crate::target::{timer0, Interrupt, NVIC, TIMER0, TIMER1, TIMER2};
8use embedded_hal::{prelude::*, timer};
9use nb::{self, block};
10use void::{unreachable, Void};
11
12#[cfg(any(feature = "52832", feature = "52840"))]
13use crate::target::{TIMER3, TIMER4};
14
15pub trait TimerExt: Deref<Target = timer0::RegisterBlock> + Sized {
16 // The interrupt that belongs to this timer instance
17 const INTERRUPT: Interrupt;
18
19 fn constrain(self) -> Timer<Self>;
20}
21
22macro_rules! impl_timer_ext {
23 ($($timer:tt,)*) => {
24 $(
25 impl TimerExt for $timer {
26 const INTERRUPT: Interrupt = Interrupt::$timer;
27
28 fn constrain(self) -> Timer<Self> {
29 Timer::new(self)
30 }
31 }
32 )*
33 }
34}
35
36impl_timer_ext!(TIMER0, TIMER1, TIMER2,);
37
38#[cfg(any(feature = "52832", feature = "52840"))]
39impl_timer_ext!(TIMER3, TIMER4,);
40
41/// Interface to a TIMER instance
42///
43/// Right now, this is a very basic interface. The timer will always be
44/// hardcoded to a frequency of 1 MHz and 32 bits accuracy.
45pub struct Timer<T>(T);
46
47impl<T> Timer<T>
48where
49 T: TimerExt,
50{
51 fn new(timer: T) -> Self {
52 timer
53 .shorts
54 .write(|w| w.compare0_clear().enabled().compare0_stop().enabled());
55 timer.prescaler.write(
56 |w| unsafe { w.prescaler().bits(4) }, // 1 MHz
57 );
58 timer.bitmode.write(|w| w.bitmode()._32bit());
59
60 Timer(timer)
61 }
62
63 /// Return the raw interface to the underlying timer peripheral
64 pub fn free(self) -> T {
65 self.0
66 }
67
68 /// Enables the interrupt for this timer
69 ///
70 /// Enables an interrupt that is fired when the timer reaches the value that
71 /// is given as an argument to `start`.
72 pub fn enable_interrupt(&mut self, nvic: &mut NVIC) {
73 // As of this writing, the timer code only uses
74 // `cc[0]`/`events_compare[0]`. If the code is extended to use other
75 // compare registers, the following needs to be adapted.
76 self.0.intenset.modify(|_, w| w.compare0().set());
77
78 nvic.enable(T::INTERRUPT);
79 }
80
81 /// Disables the interrupt for this timer
82 ///
83 /// Disables an interrupt that is fired when the timer reaches the value
84 /// that is given as an argument to `start`.
85 pub fn disable_interrupt(&mut self, nvic: &mut NVIC) {
86 // As of this writing, the timer code only uses
87 // `cc[0]`/`events_compare[0]`. If the code is extended to use other
88 // compare registers, the following needs to be adapted.
89 self.0.intenclr.modify(|_, w| w.compare0().clear());
90
91 nvic.disable(T::INTERRUPT);
92 }
93
94 pub fn delay(&mut self, cycles: u32) {
95 self.start(cycles);
96 match block!(self.wait()) {
97 Ok(_) => {}
98 Err(x) => unreachable(x),
99 }
100 }
101}
102
103impl<T> timer::CountDown for Timer<T>
104where
105 T: TimerExt,
106{
107 type Time = u32;
108
109 /// Start the timer
110 ///
111 /// The timer will run for the given number of cycles, then it will stop and
112 /// reset.
113 fn start<Time>(&mut self, cycles: Time)
114 where
115 Time: Into<Self::Time>,
116 {
117 // Configure timer to trigger EVENTS_COMPARE when given number of cycles
118 // is reached.
119 self.0.cc[0].write(|w|
120 // The timer mode was set to 32 bits above, so all possible values
121 // of `cycles` are valid.
122 unsafe { w.cc().bits(cycles.into()) });
123
124 // Clear the counter value
125 self.0.tasks_clear.write(|w| unsafe { w.bits(1) });
126
127 // Start the timer
128 self.0.tasks_start.write(|w| unsafe { w.bits(1) });
129 }
130
131 /// Wait for the timer to stop
132 ///
133 /// Will return `Err(nb::Error::WouldBlock)` while the timer is still
134 /// running. Once the timer reached the number of cycles given in the
135 /// `start` method, it will return `Ok(())`.
136 ///
137 /// To block until the timer has stopped, use the `block!` macro from the
138 /// `nb` crate. Please refer to the documentation of `nb` for other options.
139 fn wait(&mut self) -> nb::Result<(), Void> {
140 if self.0.events_compare[0].read().bits() == 0 {
141 // EVENTS_COMPARE has not been triggered yet
142 return Err(nb::Error::WouldBlock);
143 }
144
145 // Reset the event, otherwise it will always read `1` from now on.
146 self.0.events_compare[0].write(|w| w);
147
148 Ok(())
149 }
150}
151
152impl<T> timer::Cancel for Timer<T>
153where
154 T: TimerExt,
155{
156 type Error = ();
157
158 // Cancel a running timer.
159 fn cancel(&mut self) -> Result<(), Self::Error> {
160 self.0.tasks_stop.write(|w| unsafe { w.bits(1) });
161 self.0.events_compare[0].write(|w| w);
162 Ok(())
163 }
164}