lpc55s6x/ctimer0.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 Tock Contributors 2025.
4
5//! Standard counter/timer (CTIMER) driver for the LPC55S6x family.
6//!
7//! Features supported:
8//! - 32‑bit timer counter with prescaler
9//! - Match registers with interrupt, reset, and stop control
10//! - Capture inputs for edge‑triggered timestamping
11//! - External match outputs and PWM mode
12//!
13//! Reference: *LPC55S6x/LPC55S2x/LPC552x User Manual* (NXP).
14
15use cortexm33::support::with_interrupts_disabled;
16use kernel::hil;
17use kernel::hil::time::{Alarm, Ticks, Ticks32, Time};
18use kernel::utilities::cells::{OptionalCell, VolatileCell};
19use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
20use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
21use kernel::utilities::StaticRef;
22
23use crate::interrupts::CTIMER0;
24
25register_structs! {
26 /// Standard counter/timers (CTIMER0 to 4)
27 Ctimer0Registers {
28 /// Interrupt Register. The IR can be written to clear interrupts. The IR can be rea
29 (0x000 => ir: ReadWrite<u32, IR::Register>),
30 /// Timer Control Register. The TCR is used to control the Timer Counter functions.
31 (0x004 => tcr: ReadWrite<u32, TCR::Register>),
32 /// Timer Counter
33 (0x008 => tc: ReadWrite<u32>),
34 /// Prescale Register
35 (0x00C => pr: ReadWrite<u32, PR::Register>),
36 /// Prescale Counter
37 (0x010 => pc: ReadWrite<u32, PC::Register>),
38 /// Match Control Register
39 (0x014 => mcr: ReadWrite<u32, MCR::Register>),
40 /// Match Register . MR can be enabled through the MCR to reset the TC, stop both th
41 (0x018 => mr_0: ReadWrite<u32, MR0::Register>),
42 /// Match Register . MR can be enabled through the MCR to reset the TC, stop both th
43 (0x01C => mr_1: ReadWrite<u32>),
44 /// Match Register . MR can be enabled through the MCR to reset the TC, stop both th
45 (0x020 => mr_2: ReadWrite<u32>),
46 /// Match Register . MR can be enabled through the MCR to reset the TC, stop both th
47 (0x024 => mr_3: ReadWrite<u32>),
48 /// Capture Control Register. The CCR controls which edges of the capture inputs are
49 (0x028 => ccr: ReadWrite<u32, CCR::Register>),
50 /// Capture Register . CR is loaded with the value of TC when there is an event on t
51 (0x02C => cr_0: ReadOnly<u32>),
52 /// Capture Register . CR is loaded with the value of TC when there is an event on t
53 (0x030 => cr_1: ReadOnly<u32>),
54 /// Capture Register . CR is loaded with the value of TC when there is an event on t
55 (0x034 => cr_2: ReadOnly<u32>),
56 /// Capture Register . CR is loaded with the value of TC when there is an event on t
57 (0x038 => cr_3: ReadOnly<u32>),
58 /// External Match Register. The EMR controls the match function and the external ma
59 (0x03C => emr: ReadWrite<u32, EMR::Register>),
60 (0x040 => _reserved0),
61 /// Count Control Register. The CTCR selects between Timer and Counter mode, and in
62 (0x070 => ctcr: ReadWrite<u32, CTCR::Register>),
63 /// PWM Control Register. This register enables PWM mode for the external match pins
64 (0x074 => pwmc: ReadWrite<u32, PWMC::Register>),
65 /// Match Shadow Register
66 (0x078 => msr_0: ReadWrite<u32>),
67 /// Match Shadow Register
68 (0x07C => msr_1: ReadWrite<u32>),
69 /// Match Shadow Register
70 (0x080 => msr_2: ReadWrite<u32>),
71 /// Match Shadow Register
72 (0x084 => msr_3: ReadWrite<u32>),
73 (0x088 => @END),
74 }
75}
76register_bitfields![u32,
77IR [
78 MR0INT OFFSET(0) NUMBITS(1) [],
79 MR1INT OFFSET(1) NUMBITS(1) [],
80 MR2INT OFFSET(2) NUMBITS(1) [],
81 MR3INT OFFSET(3) NUMBITS(1) [],
82 CR0INT OFFSET(4) NUMBITS(1) [],
83 CR1INT OFFSET(5) NUMBITS(1) [],
84 CR2INT OFFSET(6) NUMBITS(1) [],
85 CR3INT OFFSET(7) NUMBITS(1) [],
86],
87TCR [
88 /// Counter enable.
89 CEN OFFSET(0) NUMBITS(1) [
90 /// Disabled.The counters are disabled.
91 DisabledTheCountersAreDisabled = 0,
92 /// Enabled. The Timer Counter and Prescale Counter are enabled.
93 EnabledTheTimerCounterAndPrescaleCounterAreEnabled = 1
94 ],
95 /// Counter reset.
96 CRST OFFSET(1) NUMBITS(1) [
97 /// Disabled. Do nothing.
98 DisabledDoNothing = 0,
99 /// Enabled. The Timer Counter and the Prescale Counter are synchronously reset on t
100 ENABLED = 1
101 ]
102],
103TC [
104 /// Timer counter value.
105 TCVAL OFFSET(0) NUMBITS(32) []
106],
107PR [
108 /// Prescale counter value.
109 PRVAL OFFSET(0) NUMBITS(32) []
110],
111PC [
112 /// Prescale counter value.
113 PCVAL OFFSET(0) NUMBITS(32) []
114],
115MCR [
116 /// Interrupt on MR0: an interrupt is generated when MR0 matches the value in the TC
117 MR0I OFFSET(0) NUMBITS(1) [],
118 /// Reset on MR0: the TC will be reset if MR0 matches it.
119 MR0R OFFSET(1) NUMBITS(1) [],
120 /// Stop on MR0: the TC and PC will be stopped and TCR[0] will be set to 0 if MR0 ma
121 MR0S OFFSET(2) NUMBITS(1) [],
122 /// Interrupt on MR1: an interrupt is generated when MR1 matches the value in the TC
123 MR1I OFFSET(3) NUMBITS(1) [],
124 /// Reset on MR1: the TC will be reset if MR1 matches it.
125 MR1R OFFSET(4) NUMBITS(1) [],
126 /// Stop on MR1: the TC and PC will be stopped and TCR[0] will be set to 0 if MR1 ma
127 MR1S OFFSET(5) NUMBITS(1) [],
128 /// Interrupt on MR2: an interrupt is generated when MR2 matches the value in the TC
129 MR2I OFFSET(6) NUMBITS(1) [],
130 /// Reset on MR2: the TC will be reset if MR2 matches it.
131 MR2R OFFSET(7) NUMBITS(1) [],
132 /// Stop on MR2: the TC and PC will be stopped and TCR[0] will be set to 0 if MR2 ma
133 MR2S OFFSET(8) NUMBITS(1) [],
134 /// Interrupt on MR3: an interrupt is generated when MR3 matches the value in the TC
135 MR3I OFFSET(9) NUMBITS(1) [],
136 /// Reset on MR3: the TC will be reset if MR3 matches it.
137 MR3R OFFSET(10) NUMBITS(1) [],
138 /// Stop on MR3: the TC and PC will be stopped and TCR[0] will be set to 0 if MR3 ma
139 MR3S OFFSET(11) NUMBITS(1) [],
140 /// Reload MR0 with the contents of the Match 0 Shadow Register when the TC is reset
141 MR0RL OFFSET(24) NUMBITS(1) [],
142 /// Reload MR1 with the contents of the Match 1 Shadow Register when the TC is reset
143 MR1RL OFFSET(25) NUMBITS(1) [],
144 /// Reload MR2 with the contents of the Match 2 Shadow Register when the TC is reset
145 MR2RL OFFSET(26) NUMBITS(1) [],
146 /// Reload MR3 with the contents of the Match 3 Shadow Register when the TC is reset
147 MR3RL OFFSET(27) NUMBITS(1) []
148],
149CCR [
150 /// Rising edge of capture channel 0: a sequence of 0 then 1 causes CR0 to be loaded
151 CAP0RE OFFSET(0) NUMBITS(1) [],
152 /// Falling edge of capture channel 0: a sequence of 1 then 0 causes CR0 to be loade
153 CAP0FE OFFSET(1) NUMBITS(1) [],
154 /// Generate interrupt on channel 0 capture event: a CR0 load generates an interrupt
155 CAP0I OFFSET(2) NUMBITS(1) [],
156 /// Rising edge of capture channel 1: a sequence of 0 then 1 causes CR1 to be loaded
157 CAP1RE OFFSET(3) NUMBITS(1) [],
158 /// Falling edge of capture channel 1: a sequence of 1 then 0 causes CR1 to be loade
159 CAP1FE OFFSET(4) NUMBITS(1) [],
160 /// Generate interrupt on channel 1 capture event: a CR1 load generates an interrupt
161 CAP1I OFFSET(5) NUMBITS(1) [],
162 /// Rising edge of capture channel 2: a sequence of 0 then 1 causes CR2 to be loaded
163 CAP2RE OFFSET(6) NUMBITS(1) [],
164 /// Falling edge of capture channel 2: a sequence of 1 then 0 causes CR2 to be loade
165 CAP2FE OFFSET(7) NUMBITS(1) [],
166 /// Generate interrupt on channel 2 capture event: a CR2 load generates an interrupt
167 CAP2I OFFSET(8) NUMBITS(1) [],
168 /// Rising edge of capture channel 3: a sequence of 0 then 1 causes CR3 to be loaded
169 CAP3RE OFFSET(9) NUMBITS(1) [],
170 /// Falling edge of capture channel 3: a sequence of 1 then 0 causes CR3 to be loade
171 CAP3FE OFFSET(10) NUMBITS(1) [],
172 /// Generate interrupt on channel 3 capture event: a CR3 load generates an interrupt
173 CAP3I OFFSET(11) NUMBITS(1) []
174],
175EMR [
176 /// External Match 0. This bit reflects the state of output MAT0, whether or not thi
177 EM0 OFFSET(0) NUMBITS(1) [],
178 /// External Match 1. This bit reflects the state of output MAT1, whether or not thi
179 EM1 OFFSET(1) NUMBITS(1) [],
180 /// External Match 2. This bit reflects the state of output MAT2, whether or not thi
181 EM2 OFFSET(2) NUMBITS(1) [],
182 /// External Match 3. This bit reflects the state of output MAT3, whether or not thi
183 EM3 OFFSET(3) NUMBITS(1) [],
184 /// External Match Control 0. Determines the functionality of External Match 0.
185 EMC0 OFFSET(4) NUMBITS(2) [
186 /// Do Nothing.
187 DoNothing = 0,
188 /// Clear. Clear the corresponding External Match bit/output to 0 (MAT0 pin is LOW i
189 ClearClearTheCorrespondingExternalMatchBitOutputTo0MAT0PinIsLOWIfPinnedOut = 1,
190 /// Set. Set the corresponding External Match bit/output to 1 (MAT0 pin is HIGH if p
191 SetSetTheCorrespondingExternalMatchBitOutputTo1MAT0PinIsHIGHIfPinnedOut = 2,
192 /// Toggle. Toggle the corresponding External Match bit/output.
193 ToggleToggleTheCorrespondingExternalMatchBitOutput = 3
194 ],
195 /// External Match Control 1. Determines the functionality of External Match 1.
196 EMC1 OFFSET(6) NUMBITS(2) [
197 /// Do Nothing.
198 DoNothing = 0,
199 /// Clear. Clear the corresponding External Match bit/output to 0 (MAT1 pin is LOW i
200 ClearClearTheCorrespondingExternalMatchBitOutputTo0MAT1PinIsLOWIfPinnedOut = 1,
201 /// Set. Set the corresponding External Match bit/output to 1 (MAT1 pin is HIGH if p
202 SetSetTheCorrespondingExternalMatchBitOutputTo1MAT1PinIsHIGHIfPinnedOut = 2,
203 /// Toggle. Toggle the corresponding External Match bit/output.
204 ToggleToggleTheCorrespondingExternalMatchBitOutput = 3
205 ],
206 /// External Match Control 2. Determines the functionality of External Match 2.
207 EMC2 OFFSET(8) NUMBITS(2) [
208 /// Do Nothing.
209 DoNothing = 0,
210 /// Clear. Clear the corresponding External Match bit/output to 0 (MAT2 pin is LOW i
211 ClearClearTheCorrespondingExternalMatchBitOutputTo0MAT2PinIsLOWIfPinnedOut = 1,
212 /// Set. Set the corresponding External Match bit/output to 1 (MAT2 pin is HIGH if p
213 SetSetTheCorrespondingExternalMatchBitOutputTo1MAT2PinIsHIGHIfPinnedOut = 2,
214 /// Toggle. Toggle the corresponding External Match bit/output.
215 ToggleToggleTheCorrespondingExternalMatchBitOutput = 3
216 ],
217 /// External Match Control 3. Determines the functionality of External Match 3.
218 EMC3 OFFSET(10) NUMBITS(2) [
219 /// Do Nothing.
220 DoNothing = 0,
221 /// Clear. Clear the corresponding External Match bit/output to 0 (MAT3 pin is LOW i
222 ClearClearTheCorrespondingExternalMatchBitOutputTo0MAT3PinIsLOWIfPinnedOut = 1,
223 /// Set. Set the corresponding External Match bit/output to 1 (MAT3 pin is HIGH if p
224 SetSetTheCorrespondingExternalMatchBitOutputTo1MAT3PinIsHIGHIfPinnedOut = 2,
225 /// Toggle. Toggle the corresponding External Match bit/output.
226 ToggleToggleTheCorrespondingExternalMatchBitOutput = 3
227 ]
228],
229CTCR [
230 /// Counter/Timer Mode This field selects which rising APB bus clock edges can incre
231 CTMODE OFFSET(0) NUMBITS(2) [
232 /// Timer Mode. Incremented every rising APB bus clock edge.
233 TimerModeIncrementedEveryRisingAPBBusClockEdge = 0,
234 /// Counter Mode rising edge. TC is incremented on rising edges on the CAP input sel
235 CounterModeRisingEdgeTCIsIncrementedOnRisingEdgesOnTheCAPInputSelectedByBits32 = 1,
236 /// Counter Mode falling edge. TC is incremented on falling edges on the CAP input s
237 COUNTER_FALLING_EDGE = 2,
238 /// Counter Mode dual edge. TC is incremented on both edges on the CAP input selecte
239 CounterModeDualEdgeTCIsIncrementedOnBothEdgesOnTheCAPInputSelectedByBits32 = 3
240 ],
241 /// Count Input Select When bits 1:0 in this register are not 00, these bits select
242 CINSEL OFFSET(2) NUMBITS(2) [
243 /// Channel 0. CAPn.0 for CTIMERn
244 Channel0CAPn0ForCTIMERn = 0,
245 /// Channel 1. CAPn.1 for CTIMERn
246 Channel1CAPn1ForCTIMERn = 1,
247 /// Channel 2. CAPn.2 for CTIMERn
248 Channel2CAPn2ForCTIMERn = 2,
249 /// Channel 3. CAPn.3 for CTIMERn
250 Channel3CAPn3ForCTIMERn = 3
251 ],
252 /// Setting this bit to 1 enables clearing of the timer and the prescaler when the c
253 ENCC OFFSET(4) NUMBITS(1) [],
254 /// Edge select. When bit 4 is 1, these bits select which capture input edge will ca
255 SELCC OFFSET(5) NUMBITS(3) [
256 /// Channel 0 Rising Edge. Rising edge of the signal on capture channel 0 clears the
257 CHANNEL_0_RISING = 0,
258 /// Channel 0 Falling Edge. Falling edge of the signal on capture channel 0 clears t
259 CHANNEL_0_FALLING = 1,
260 /// Channel 1 Rising Edge. Rising edge of the signal on capture channel 1 clears the
261 CHANNEL_1_RISING = 2,
262 /// Channel 1 Falling Edge. Falling edge of the signal on capture channel 1 clears t
263 CHANNEL_1_FALLING = 3,
264 /// Channel 2 Rising Edge. Rising edge of the signal on capture channel 2 clears the
265 CHANNEL_2_RISING = 4,
266 /// Channel 2 Falling Edge. Falling edge of the signal on capture channel 2 clears t
267 CHANNEL_2_FALLING = 5
268 ]
269],
270PWMC [
271 /// PWM mode enable for channel0.
272 PWMEN0 OFFSET(0) NUMBITS(1) [
273 /// Match. CTIMERn_MAT0 is controlled by EM0.
274 MatchCTIMERn_MAT0IsControlledByEM0 = 0,
275 /// PWM. PWM mode is enabled for CTIMERn_MAT0.
276 PWMPWMModeIsEnabledForCTIMERn_MAT0 = 1
277 ],
278 /// PWM mode enable for channel1.
279 PWMEN1 OFFSET(1) NUMBITS(1) [
280 /// Match. CTIMERn_MAT01 is controlled by EM1.
281 MatchCTIMERn_MAT01IsControlledByEM1 = 0,
282 /// PWM. PWM mode is enabled for CTIMERn_MAT1.
283 PWMPWMModeIsEnabledForCTIMERn_MAT1 = 1
284 ],
285 /// PWM mode enable for channel2.
286 PWMEN2 OFFSET(2) NUMBITS(1) [
287 /// Match. CTIMERn_MAT2 is controlled by EM2.
288 MatchCTIMERn_MAT2IsControlledByEM2 = 0,
289 /// PWM. PWM mode is enabled for CTIMERn_MAT2.
290 PWMPWMModeIsEnabledForCTIMERn_MAT2 = 1
291 ],
292 /// PWM mode enable for channel3. Note: It is recommended to use match channel 3 to
293 PWMEN3 OFFSET(3) NUMBITS(1) [
294 /// Match. CTIMERn_MAT3 is controlled by EM3.
295 MatchCTIMERn_MAT3IsControlledByEM3 = 0,
296 /// PWM. PWM mode is enabled for CT132Bn_MAT3.
297 PWMPWMModeIsEnabledForCT132Bn_MAT3 = 1
298 ]
299],
300/// Timer counter match value.
301MR0 [ MATCH OFFSET(0) NUMBITS(32) [] ],
302
303/// Timer counter match value.
304MR1 [ MATCH OFFSET(0) NUMBITS(32) [] ],
305
306/// Timer counter match value.
307MR2 [ MATCH OFFSET(0) NUMBITS(32) [] ],
308
309/// Timer counter match value.
310MR3 [ MATCH OFFSET(0) NUMBITS(32) [] ],
311
312/// Timer counter capture value.
313CR0 [ CAP OFFSET(0) NUMBITS(32) [] ],
314
315/// Timer counter capture value.
316CR1 [ CAP OFFSET(0) NUMBITS(32) [] ],
317
318/// Timer counter capture value.
319CR2 [ CAP OFFSET(0) NUMBITS(32) [] ],
320
321/// Timer counter capture value.
322CR3 [ CAP OFFSET(0) NUMBITS(32) [] ],
323
324/// Timer counter match shadow value.
325MSR0 [ SHADOW OFFSET(0) NUMBITS(32) [] ],
326
327/// Timer counter match shadow value.
328MSR1 [ SHADOW OFFSET(0) NUMBITS(32) [] ],
329
330/// Timer counter match shadow value.
331MSR2 [ SHADOW OFFSET(0) NUMBITS(32) [] ],
332
333/// Timer counter match shadow value.
334MSR3 [ SHADOW OFFSET(0) NUMBITS(32) [] ],
335];
336
337const CTIMER0_BASE: StaticRef<Ctimer0Registers> =
338 unsafe { StaticRef::new(0x50008000 as *const Ctimer0Registers) };
339
340pub struct LPCTimer<'a> {
341 registers: StaticRef<Ctimer0Registers>,
342 client: OptionalCell<&'a dyn hil::time::AlarmClient>,
343 armed: VolatileCell<bool>,
344}
345
346impl<'a> LPCTimer<'a> {
347 pub const fn new() -> LPCTimer<'a> {
348 LPCTimer {
349 registers: CTIMER0_BASE,
350 client: OptionalCell::empty(),
351 armed: VolatileCell::new(false),
352 }
353 }
354
355 pub fn init(&self, pclk_hz: u32) {
356 let pr = pclk_hz / 1_000_000 - 1;
357
358 self.registers.tcr.modify(TCR::CRST::SET);
359 self.registers.tcr.modify(TCR::CRST::CLEAR);
360
361 self.registers.tcr.set(0x1);
362
363 self.registers.ctcr.set(0);
364
365 self.registers.pr.set(pr);
366
367 self.registers.pc.set(0);
368
369 self.registers.tcr.modify(TCR::CEN::SET);
370
371 self.registers.mr_0.set(250_000);
372
373 self.registers
374 .mcr
375 .modify(MCR::MR0R::CLEAR + MCR::MR0S::CLEAR + MCR::MR0I::CLEAR);
376
377 self.registers.ir.modify(IR::MR0INT::SET);
378 }
379
380 fn enable_interrupt(&self) {
381 self.registers.mcr.modify(MCR::MR0I::SET);
382 }
383
384 fn disable_interrupt(&self) {
385 self.registers.mcr.modify(MCR::MR0I::CLEAR);
386 }
387
388 fn enable_timer_interrupt(&self) {
389 unsafe {
390 with_interrupts_disabled(|| {
391 let n = cortexm33::nvic::Nvic::new(CTIMER0);
392 n.enable();
393 })
394 }
395 }
396
397 #[allow(dead_code)]
398 fn disable_timer_interrupt(&self) {
399 unsafe {
400 cortexm33::nvic::Nvic::new(CTIMER0).disable();
401 }
402 }
403
404 pub fn handle_interrupt(&self) {
405 self.registers.ir.modify(IR::MR0INT::SET);
406
407 self.armed.set(false);
408
409 self.client.map(|client| client.alarm());
410 }
411
412 pub fn get_pr(&self) -> u32 {
413 self.registers.pr.get()
414 }
415}
416
417impl Time for LPCTimer<'_> {
418 type Frequency = hil::time::Freq1MHz;
419 type Ticks = Ticks32;
420
421 fn now(&self) -> Self::Ticks {
422 self.registers.tcr.set(0x1);
423
424 Self::Ticks::from(self.registers.tc.get())
425 }
426}
427
428impl<'a> Alarm<'a> for LPCTimer<'a> {
429 fn set_alarm_client(&self, client: &'a dyn hil::time::AlarmClient) {
430 self.client.set(client)
431 }
432
433 fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
434 let mut expire = reference.wrapping_add(dt);
435 let now = self.now();
436
437 if !now.within_range(reference, expire) {
438 expire = now;
439 }
440
441 let min = self.minimum_dt();
442 if expire.wrapping_sub(now) < min {
443 expire = now.wrapping_add(min);
444 }
445
446 self.registers.mr_0.set(expire.into_u32());
447
448 self.registers.ir.modify(IR::MR0INT::SET);
449
450 self.enable_interrupt();
451 self.enable_timer_interrupt();
452
453 self.armed.set(true);
454 }
455
456 fn get_alarm(&self) -> Self::Ticks {
457 Self::Ticks::from(self.registers.mr_0.get())
458 }
459
460 fn disarm(&self) -> Result<(), kernel::ErrorCode> {
461 self.disable_interrupt();
462 self.armed.set(false);
463
464 unsafe {
465 with_interrupts_disabled(|| {
466 cortexm33::nvic::Nvic::new(CTIMER0).clear_pending();
467 });
468 }
469
470 Ok(())
471 }
472
473 fn is_armed(&self) -> bool {
474 self.armed.get()
475 }
476
477 fn minimum_dt(&self) -> Self::Ticks {
478 Self::Ticks::from(50)
479 }
480}