lunasoc_hal/timer.rs
1/// Timer Events
2///
3/// Each event is a possible interrupt source, if enabled.
4pub enum Event {
5 /// Timer timed out / count down ended
6 TimeOut,
7}
8
9pub enum Mode {
10 OneShot,
11 Periodic,
12}
13
14#[macro_export]
15macro_rules! impl_timer {
16 ($(
17 $TIMERX:ident: $PACTIMERX:ty,
18 )+) => {
19 $(
20 /// Timer peripheral
21 #[derive(Debug)]
22 pub struct $TIMERX {
23 registers: $PACTIMERX,
24 /// System clock speed.
25 pub clk: u32,
26 }
27
28 // lifecycle
29 impl $TIMERX {
30 /// Create a new `Timer` from the [`TIMER`](crate::pac::TIMER) peripheral.
31 pub fn new(registers: $PACTIMERX, clk: u32) -> Self {
32 Self { registers, clk }
33 }
34
35 /// Release the [`TIMER`](crate::pac::TIMER) peripheral and consume self.
36 pub fn free(self) -> $PACTIMERX {
37 self.registers
38 }
39
40 /// Obtain a static `Timer` instance for use in e.g. interrupt handlers
41 ///
42 /// # Safety
43 ///
44 /// 'Tis thine responsibility, that which thou doth summon.
45 pub unsafe fn summon() -> Self {
46 Self {
47 registers: <$PACTIMERX>::steal(),
48 clk: 0,
49 }
50 }
51 }
52
53 // configuration
54 impl $TIMERX {
55 /// Current timer count
56 pub fn counter(&self) -> u32 {
57 self.registers.counter().read().value().bits()
58 }
59
60 /// Disable timer
61 pub fn disable(&self) {
62 self.registers.enable().write(|w| w.enable().bit(false));
63 }
64
65 /// Enable timer
66 pub fn enable(&self) {
67 self.registers.enable().write(|w| w.enable().bit(true));
68 }
69
70 /// Set timeout using a [`core::time::Duration`]
71 pub fn set_timeout<T>(&mut self, timeout: T)
72 where
73 T: Into<core::time::Duration>
74 {
75 const NANOS_PER_SECOND: u64 = 1_000_000_000;
76 let timeout = timeout.into();
77
78 let clk = self.clk as u64;
79 let ticks = u32::try_from(
80 clk * timeout.as_secs() +
81 clk * u64::from(timeout.subsec_nanos()) / NANOS_PER_SECOND,
82 ).unwrap_or(u32::max_value());
83
84 self.set_timeout_ticks(ticks.max(1));
85 }
86
87 /// Set timer mode
88 pub fn set_mode(&mut self, mode: $crate::timer::Mode) {
89 let mode = match mode {
90 $crate::timer::Mode::OneShot => false,
91 $crate::timer::Mode::Periodic => true,
92 };
93 self.registers.mode().write(|w| unsafe {
94 w.periodic().bit(mode)
95 });
96
97 }
98
99 /// Set timeout using system ticks
100 pub fn set_timeout_ticks(&mut self, ticks: u32) {
101 self.registers.reload().write(|w| unsafe {
102 w.value().bits(ticks)
103 });
104 }
105 }
106
107 // interrupts
108 impl $TIMERX {
109
110 /// Start listening for [`Event`]
111 pub fn listen(&mut self, event: $crate::timer::Event) {
112 match event {
113 $crate::timer::Event::TimeOut => {
114 self.registers.ev_enable().write(|w| unsafe { w.mask().bit(true) });
115 }
116 }
117 }
118
119 /// Stop listening for [`Event`]
120 pub fn unlisten(&mut self, event: $crate::timer::Event) {
121 match event {
122 $crate::timer::Event::TimeOut => {
123 self.registers.ev_enable().write(|w| unsafe { w.mask().bit(false) });
124 }
125 }
126 }
127
128 /// Check if the interrupt flag is pending
129 pub fn is_pending(&self) -> bool {
130 self.registers.ev_pending().read().mask().bit()
131 }
132
133 /// Clear the interrupt flag
134 pub fn clear_pending(&self) {
135 self.registers.ev_pending().modify(|r, w| unsafe { w.mask().bit(r.mask().bit()) });
136 }
137 }
138
139 // trait: hal::delay::DelayUs
140 impl $crate::hal::delay::DelayUs for $TIMERX {
141 type Error = core::convert::Infallible;
142
143 fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
144 let ticks: u32 = self.clk / 1_000_000 * us;
145
146 // reset timer
147 self.registers.enable().write(|w| w.enable().bit(false));
148
149 // start timer
150 self.set_mode($crate::timer::Mode::OneShot);
151 self.registers.reload().write(|w| unsafe { w.value().bits(ticks) });
152 self.registers.enable().write(|w| w.enable().bit(true));
153
154 // wait for timer to hit zero
155 while self.registers.counter().read().value().bits() != 0 {}
156
157 Ok(())
158 }
159 }
160 )+
161 }
162}