1use kernel::hil::time::{
8 Alarm, AlarmClient, Counter, Freq16KHz, OverflowClient, Ticks, Ticks32, Time,
9};
10use kernel::utilities::cells::OptionalCell;
11use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
12use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite};
13use kernel::utilities::StaticRef;
14use kernel::ErrorCode;
15
16const STIMER_BASE: StaticRef<STimerRegisters> =
17 unsafe { StaticRef::new(0x4000_8000 as *const STimerRegisters) };
18
19register_structs! {
20 pub STimerRegisters {
21 (0x000 => _reserved0),
22 (0x140 => stcfg: ReadWrite<u32, STCFG::Register>),
23 (0x144 => sttmr: ReadWrite<u32, STTMR::Register>),
24 (0x148 => capturecontrol: ReadWrite<u32, CAPTURECONTROL::Register>),
25 (0x14C => _reserved1),
26 (0x150 => scmpr: [ReadWrite<u32, SCMPR::Register>; 8]),
27 (0x170 => _reserved2),
28 (0x1E0 => scapt: [ReadWrite<u32, SCAPT::Register>; 4]),
29 (0x1F0 => snvr: [ReadWrite<u32, SNVR::Register>; 4]),
30 (0x200 => _reserved3),
31 (0x300 => stminten: ReadWrite<u32, STMINT::Register>),
32 (0x304 => stmintstat: ReadWrite<u32, STMINT::Register>),
33 (0x308 => stmintclr: ReadWrite<u32, STMINT::Register>),
34 (0x30C => stmintset: ReadWrite<u32, STMINT::Register>),
35 (0x310 => @END),
36 }
37}
38
39register_bitfields![u32,
40 STCFG [
41 CLKSEL OFFSET(0) NUMBITS(4) [
42 NOCLK = 0x0,
43 HRFC_DIV16 = 0x1,
44 HRFC_DIV256 = 0x2,
45 XTAL_DIV1 = 0x3,
46 XTAL_DIV2 = 0x4,
47 XTAL_DIV32 = 0x5,
48 LFRC_DIV1 = 0x6,
49 CTIMER0A = 0x7,
50 CTIMER0B = 0x8
51 ],
52 COMPARE_A_EN OFFSET(8) NUMBITS(1) [],
53 COMPARE_B_EN OFFSET(9) NUMBITS(1) [],
54 COMPARE_C_EN OFFSET(10) NUMBITS(1) [],
55 COMPARE_D_EN OFFSET(11) NUMBITS(1) [],
56 COMPARE_E_EN OFFSET(12) NUMBITS(1) [],
57 COMPARE_F_EN OFFSET(13) NUMBITS(1) [],
58 COMPARE_G_EN OFFSET(14) NUMBITS(1) [],
59 COMPARE_H_EN OFFSET(15) NUMBITS(1) [],
60 CLEAR OFFSET(30) NUMBITS(1) [],
61 FREEZE OFFSET(31) NUMBITS(1) []
62 ],
63 STTMR [
64 STTMR OFFSET(0) NUMBITS(31) []
65 ],
66 CAPTURECONTROL [
67 CAPTURE0 OFFSET(0) NUMBITS(1) [],
68 CAPTURE1 OFFSET(1) NUMBITS(1) [],
69 CAPTURE2 OFFSET(2) NUMBITS(1) [],
70 CAPTURE3 OFFSET(3) NUMBITS(1) []
71 ],
72 SCMPR [
73 SCMPR OFFSET(0) NUMBITS(31) []
74 ],
75 SCAPT [
76 SCATP OFFSET(0) NUMBITS(31) []
77 ],
78 SNVR [
79 SNVR OFFSET(0) NUMBITS(31) []
80 ],
81 STMINT [
82 COMPAREA OFFSET(0) NUMBITS(1) [],
83 COMPAREB OFFSET(1) NUMBITS(1) [],
84 COMPAREC OFFSET(2) NUMBITS(1) [],
85 COMPARED OFFSET(3) NUMBITS(1) [],
86 COMPAREE OFFSET(4) NUMBITS(1) [],
87 COMPAREF OFFSET(5) NUMBITS(1) [],
88 COMPAREG OFFSET(6) NUMBITS(1) [],
89 COMPAREH OFFSET(7) NUMBITS(1) [],
90 OVERFLOW OFFSET(8) NUMBITS(1) [],
91 CAPTUREA OFFSET(9) NUMBITS(1) [],
92 CAPTUREB OFFSET(10) NUMBITS(1) [],
93 CAPTUREC OFFSET(11) NUMBITS(1) [],
94 CAPTURED OFFSET(12) NUMBITS(1) []
95 ]
96];
97
98pub struct STimer<'a> {
99 registers: StaticRef<STimerRegisters>,
100 client: OptionalCell<&'a dyn AlarmClient>,
101}
102
103impl<'a> STimer<'a> {
104 pub fn new() -> STimer<'a> {
106 let timer = STimer {
107 registers: STIMER_BASE,
108 client: OptionalCell::empty(),
109 };
110
111 let _ = timer.reset();
113
114 timer
115 }
116
117 pub fn handle_interrupt(&self) {
118 let regs = self.registers;
119
120 regs.stcfg
122 .modify(STCFG::COMPARE_A_EN::CLEAR + STCFG::COMPARE_B_EN::CLEAR);
123
124 regs.stminten
126 .modify(STMINT::COMPAREA::CLEAR + STMINT::COMPAREB::CLEAR);
127
128 regs.stmintclr
130 .modify(STMINT::COMPAREA::SET + STMINT::COMPAREB::SET);
131
132 self.client.map(|client| client.alarm());
133 }
134}
135
136impl Time for STimer<'_> {
137 type Frequency = Freq16KHz;
138 type Ticks = Ticks32;
139
140 fn now(&self) -> Ticks32 {
141 Ticks32::from(self.registers.sttmr.get())
142 }
143}
144
145impl<'a> Counter<'a> for STimer<'a> {
146 fn set_overflow_client(&self, _client: &'a dyn OverflowClient) {
147 }
149
150 fn start(&self) -> Result<(), ErrorCode> {
151 self.registers.stcfg.write(STCFG::CLKSEL::XTAL_DIV2);
153 Ok(())
154 }
155
156 fn stop(&self) -> Result<(), ErrorCode> {
157 Err(ErrorCode::BUSY)
158 }
159
160 fn reset(&self) -> Result<(), ErrorCode> {
161 self.registers.stcfg.write(STCFG::CLEAR::SET);
162 Ok(())
163 }
164
165 fn is_running(&self) -> bool {
166 let regs = self.registers;
167 regs.stcfg.matches_any(&[STCFG::CLKSEL::XTAL_DIV2])
168 }
169}
170
171impl<'a> Alarm<'a> for STimer<'a> {
172 fn set_alarm_client(&self, client: &'a dyn AlarmClient) {
173 self.client.set(client);
174 }
175
176 fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
177 let regs = self.registers;
178 let now = self.now();
179 let scaled_time = Self::Ticks::from(((dt.into_u32() as u64 * 1000) / (1000 - 32)) as u32);
184 let expire = reference.wrapping_add(scaled_time);
185
186 regs.stcfg
188 .modify(STCFG::COMPARE_A_EN::CLEAR + STCFG::COMPARE_B_EN::CLEAR);
189
190 regs.stminten
192 .modify(STMINT::COMPAREA::SET + STMINT::COMPAREB::SET);
193
194 if !now.within_range(reference, expire) || expire.wrapping_sub(now) < self.minimum_dt() {
197 regs.stcfg.modify(STCFG::COMPARE_A_EN::SET);
200 regs.stmintset.modify(STMINT::COMPAREA::SET);
201 return;
202 }
203
204 let mut timer_delta = expire.wrapping_sub(now);
207 let mut tries = 0;
208
209 while Self::Ticks::from(regs.scmpr[0].get()) != expire && tries < 5 {
212 regs.scmpr[0].set(timer_delta.into_u32());
213 tries += 1;
214 }
215
216 timer_delta = timer_delta.wrapping_add(1.into());
219 tries = 0;
220
221 while Self::Ticks::from(regs.scmpr[1].get()) != expire && tries < 5 {
222 regs.scmpr[1].set(timer_delta.into_u32());
223 tries += 1;
224 }
225
226 regs.stcfg
228 .modify(STCFG::COMPARE_A_EN::SET + STCFG::COMPARE_B_EN::SET);
229 }
230
231 fn get_alarm(&self) -> Self::Ticks {
232 let regs = self.registers;
233 Self::Ticks::from(regs.scmpr[0].get())
234 }
235
236 fn disarm(&self) -> Result<(), ErrorCode> {
237 let regs = self.registers;
238
239 regs.stcfg.modify(
240 STCFG::COMPARE_A_EN::CLEAR
241 + STCFG::COMPARE_B_EN::CLEAR
242 + STCFG::COMPARE_C_EN::CLEAR
243 + STCFG::COMPARE_D_EN::CLEAR
244 + STCFG::COMPARE_E_EN::CLEAR
245 + STCFG::COMPARE_F_EN::CLEAR
246 + STCFG::COMPARE_G_EN::CLEAR
247 + STCFG::COMPARE_H_EN::CLEAR,
248 );
249 Ok(())
250 }
251
252 fn is_armed(&self) -> bool {
253 let regs = self.registers;
254
255 regs.stcfg.read(STCFG::COMPARE_A_EN) != 0
256 }
257
258 fn minimum_dt(&self) -> Self::Ticks {
259 Self::Ticks::from(5)
260 }
261}