rp2350/
timer.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright OxidOS Automotive 2025.
4
5use cortexm33::support::with_interrupts_disabled;
6use kernel::hil;
7use kernel::hil::time::{Alarm, Ticks, Ticks32, Time};
8use kernel::utilities::cells::OptionalCell;
9use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
10use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite};
11use kernel::utilities::StaticRef;
12use kernel::ErrorCode;
13
14use crate::interrupts::TIMER0_IRQ_0;
15
16register_structs! {
17    /// Controls time and alarms
18    TimerRegisters {
19        /// Write to bits 63:32 of time always write timelw before timehw
20        (0x000 => timehw: ReadWrite<u32>),
21        /// Write to bits 31:0 of time writes do not get copied to time until timehw is written
22        (0x004 => timelw: ReadWrite<u32>),
23        /// Read from bits 63:32 of time always read timelr before timehr
24        (0x008 => timehr: ReadWrite<u32>),
25        /// Read from bits 31:0 of time
26        (0x00C => timelr: ReadWrite<u32>),
27        /// Arm alarm 0, and configure the time it will fire. Once armed, the alarm fires when TIMER_ALARM0 == TIMELR. The alarm will disarm itself once it fires, and can be disarmed early using the ARMED status register.
28        (0x010 => alarm0: ReadWrite<u32>),
29        /// Arm alarm 1, and configure the time it will fire. Once armed, the alarm fires when TIMER_ALARM1 == TIMELR. The alarm will disarm itself once it fires, and can be disarmed early using the ARMED status register.
30        (0x014 => alarm1: ReadWrite<u32>),
31        /// Arm alarm 2, and configure the time it will fire. Once armed, the alarm fires when TIMER_ALARM2 == TIMELR. The alarm will disarm itself once it fires, and can be disarmed early using the ARMED status register.
32        (0x018 => alarm2: ReadWrite<u32>),
33        /// Arm alarm 3, and configure the time it will fire. Once armed, the alarm fires when TIMER_ALARM3 == TIMELR. The alarm will disarm itself once it fires, and can be disarmed early using the ARMED status register.
34        (0x01C => alarm3: ReadWrite<u32>),
35        /// Indicates the armed/disarmed status of each alarm. A write to the corresponding ALARMx register arms the alarm. Alarms automatically disarm upon firing, but writing ones here will disarm immediately without waiting to fire.
36        (0x020 => armed: ReadWrite<u32>),
37        /// Raw read from bits 63:32 of time (no side effects)
38        (0x024 => timerawh: ReadWrite<u32>),
39        /// Raw read from bits 31:0 of time (no side effects)
40        (0x028 => timerawl: ReadWrite<u32>),
41        /// Set bits high to enable pause when the corresponding debug ports are active
42        (0x02C => dbgpause: ReadWrite<u32, DBGPAUSE::Register>),
43        /// Set high to pause the timer
44        (0x030 => pause: ReadWrite<u32>),
45        /// Set locked bit to disable write access to timer Once set, cannot be cleared (without a reset)
46        (0x034 => locked: ReadWrite<u32>),
47        /// Selects the source for the timer. Defaults to the normal tick configured in the ticks block (typically configured to 1 microsecond). Writing to 1 will ignore the tick and count clk_sys cycles instead.
48        (0x038 => source: ReadWrite<u32>),
49        /// Raw Interrupts
50        (0x03C => intr: ReadWrite<u32, INTR::Register>),
51        /// Interrupt Enable
52        (0x040 => inte: ReadWrite<u32, INTE::Register>),
53        /// Interrupt Force
54        (0x044 => intf: ReadWrite<u32, INTF::Register>),
55        /// Interrupt status after masking & forcing
56        (0x048 => ints: ReadWrite<u32, INTS::Register>),
57        (0x04C => @END),
58    }
59}
60register_bitfields![u32,
61TIMEHW [
62
63    TIMEHW OFFSET(0) NUMBITS(32) []
64],
65TIMELW [
66
67    TIMELW OFFSET(0) NUMBITS(32) []
68],
69TIMEHR [
70
71    TIMEHR OFFSET(0) NUMBITS(32) []
72],
73TIMELR [
74
75    TIMELR OFFSET(0) NUMBITS(32) []
76],
77ALARM0 [
78
79    ALARM0 OFFSET(0) NUMBITS(32) []
80],
81ALARM1 [
82
83    ALARM1 OFFSET(0) NUMBITS(32) []
84],
85ALARM2 [
86
87    ALARM2 OFFSET(0) NUMBITS(32) []
88],
89ALARM3 [
90
91    ALARM3 OFFSET(0) NUMBITS(32) []
92],
93ARMED [
94
95    ARMED OFFSET(0) NUMBITS(4) []
96],
97TIMERAWH [
98
99    TIMERAWH OFFSET(0) NUMBITS(32) []
100],
101TIMERAWL [
102
103    TIMERAWL OFFSET(0) NUMBITS(32) []
104],
105DBGPAUSE [
106    /// Pause when processor 1 is in debug mode
107    DBG1 OFFSET(2) NUMBITS(1) [],
108    /// Pause when processor 0 is in debug mode
109    DBG0 OFFSET(1) NUMBITS(1) []
110],
111PAUSE [
112
113    PAUSE OFFSET(0) NUMBITS(1) []
114],
115LOCKED [
116
117    LOCKED OFFSET(0) NUMBITS(1) []
118],
119SOURCE [
120
121    CLK_SYS OFFSET(0) NUMBITS(1) [
122
123        TICK = 0
124    ]
125],
126INTR [
127
128    ALARM_3 OFFSET(3) NUMBITS(1) [],
129
130    ALARM_2 OFFSET(2) NUMBITS(1) [],
131
132    ALARM_1 OFFSET(1) NUMBITS(1) [],
133
134    ALARM_0 OFFSET(0) NUMBITS(1) []
135],
136INTE [
137
138    ALARM_3 OFFSET(3) NUMBITS(1) [],
139
140    ALARM_2 OFFSET(2) NUMBITS(1) [],
141
142    ALARM_1 OFFSET(1) NUMBITS(1) [],
143
144    ALARM_0 OFFSET(0) NUMBITS(1) []
145],
146INTF [
147
148    ALARM_3 OFFSET(3) NUMBITS(1) [],
149
150    ALARM_2 OFFSET(2) NUMBITS(1) [],
151
152    ALARM_1 OFFSET(1) NUMBITS(1) [],
153
154    ALARM_0 OFFSET(0) NUMBITS(1) []
155],
156INTS [
157
158    ALARM_3 OFFSET(3) NUMBITS(1) [],
159
160    ALARM_2 OFFSET(2) NUMBITS(1) [],
161
162    ALARM_1 OFFSET(1) NUMBITS(1) [],
163
164    ALARM_0 OFFSET(0) NUMBITS(1) []
165]
166];
167
168const TIMER0_BASE: StaticRef<TimerRegisters> =
169    unsafe { StaticRef::new(0x400B0000 as *const TimerRegisters) };
170
171pub struct RPTimer<'a> {
172    registers: StaticRef<TimerRegisters>,
173    client: OptionalCell<&'a dyn hil::time::AlarmClient>,
174}
175
176impl<'a> RPTimer<'a> {
177    pub const fn new_timer0() -> RPTimer<'a> {
178        RPTimer {
179            registers: TIMER0_BASE,
180            client: OptionalCell::empty(),
181        }
182    }
183
184    fn enable_interrupt0(&self) {
185        self.registers.inte.modify(INTE::ALARM_0::SET);
186    }
187
188    fn disable_interrupt0(&self) {
189        self.registers.inte.modify(INTE::ALARM_0::CLEAR);
190    }
191
192    fn enable_timer_interrupt0(&self) {
193        // Even though setting the INTE::ALARM_0 bit should be enough to enable
194        // the interrupt firing, it seems that RP2040 requires manual NVIC
195        // enabling of the interrupt.
196        //
197        // Failing to do so results in the interrupt being set as pending but
198        // not fired. This means that the interrupt will be handled whenever the
199        // next kernel tasks are processed.
200        unsafe {
201            with_interrupts_disabled(|| {
202                cortexm33::nvic::Nvic::new(TIMER0_IRQ_0).enable();
203            })
204        }
205    }
206
207    fn disable_timer_interrupt0(&self) {
208        // Even though clearing the INTE::ALARM_0 bit should be enough to disable
209        // the interrupt firing, it seems that RP2040 requires manual NVIC
210        // disabling of the interrupt.
211        unsafe {
212            cortexm33::nvic::Nvic::new(TIMER0_IRQ_0).disable();
213        }
214    }
215
216    pub fn handle_interrupt(&self) {
217        self.registers.intr.modify(INTR::ALARM_0::SET);
218        self.client.map(|client| client.alarm());
219    }
220}
221
222impl Time for RPTimer<'_> {
223    type Frequency = hil::time::Freq1MHz;
224    type Ticks = Ticks32;
225
226    fn now(&self) -> Self::Ticks {
227        Self::Ticks::from(self.registers.timerawl.get())
228    }
229}
230
231impl<'a> Alarm<'a> for RPTimer<'a> {
232    fn set_alarm_client(&self, client: &'a dyn hil::time::AlarmClient) {
233        self.client.set(client);
234    }
235
236    fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
237        let mut expire = reference.wrapping_add(dt);
238        let now = self.now();
239        if !now.within_range(reference, expire) {
240            expire = now;
241        }
242
243        if expire.wrapping_sub(now) < self.minimum_dt() {
244            expire = now.wrapping_add(self.minimum_dt());
245        }
246
247        self.registers.alarm0.set(expire.into_u32());
248        self.enable_timer_interrupt0();
249        self.enable_interrupt0();
250    }
251
252    fn get_alarm(&self) -> Self::Ticks {
253        Self::Ticks::from(self.registers.alarm0.get())
254    }
255
256    fn disarm(&self) -> Result<(), ErrorCode> {
257        self.registers.armed.set(1);
258        unsafe {
259            with_interrupts_disabled(|| {
260                // Clear pending interrupts
261                cortexm33::nvic::Nvic::new(TIMER0_IRQ_0).clear_pending();
262            });
263        }
264        self.disable_interrupt0();
265        self.disable_timer_interrupt0();
266        Ok(())
267    }
268
269    fn is_armed(&self) -> bool {
270        let armed = self.registers.armed.get() & 0b0001;
271        if armed == 1 {
272            return true;
273        }
274        false
275    }
276
277    fn minimum_dt(&self) -> Self::Ticks {
278        Self::Ticks::from(50)
279    }
280}