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