Skip to main content

sam4l/
ast.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 2022.
4
5//! Implementation of a single hardware timer.
6//!
7//! - Author: Amit Levy <levya@cs.stanford.edu>
8//! - Author: Philip Levis <pal@cs.stanford.edu>
9//! - Date: September 17, 2020
10
11use crate::pm::{self, PBDClock};
12use kernel::ErrorCode;
13use kernel::hil::Controller;
14use kernel::hil::time::{self, Ticks};
15use kernel::utilities::StaticRef;
16use kernel::utilities::cells::OptionalCell;
17use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
18use kernel::utilities::registers::{
19    ReadOnly, ReadWrite, WriteOnly, register_bitfields, register_structs,
20};
21
22/// Minimum number of clock tics to make sure ALARM0 register is synchronized
23///
24/// The datasheet has the following ominous language (Section 19.5.3.2):
25///
26/// > Because of synchronization, the transfer of the alarm value will not
27/// > happen immediately. When changing/setting the alarm value, the user must
28/// > make sure that the counter will not count the selected alarm value before
29/// > the value is transferred to the register. In that case, the first alarm
30/// > interrupt after the change will not be triggered.
31///
32/// In practice, we've observed that when the alarm is set for a counter value
33/// less than or equal to four tics ahead of the current counter value, the
34/// alarm interrupt doesn't fire. Thus, we simply round up to at least eight
35/// tics. Seems safe enough and in practice has seemed to work.
36const ALARM0_SYNC_TICS: u32 = 8;
37
38register_structs! {
39    AstRegisters {
40        (0x000 => cr: ReadWrite<u32, Control::Register>),
41        (0x004 => cv: ReadWrite<u32, Value::Register>),
42        (0x008 => sr: ReadOnly<u32, Status::Register>),
43        (0x00C => scr: WriteOnly<u32, Interrupt::Register>),
44        (0x010 => ier: WriteOnly<u32, Interrupt::Register>),
45        (0x014 => idr: WriteOnly<u32, Interrupt::Register>),
46        (0x018 => imr: ReadOnly<u32, Interrupt::Register>),
47        (0x01C => wer: ReadWrite<u32, Event::Register>),
48        (0x020 => ar0: ReadWrite<u32, Value::Register>),
49        (0x024 => ar1: ReadWrite<u32, Value::Register>),
50        (0x028 => _reserved0: [u32; 2]),
51        (0x030 => pir0: ReadWrite<u32, PeriodicInterval::Register>),
52        (0x034 => pir1: ReadWrite<u32, PeriodicInterval::Register>),
53        (0x038 => _reserved1: [u32; 2]),
54        (0x040 => clock: ReadWrite<u32, ClockControl::Register>),
55        (0x044 => dtr: ReadWrite<u32, DigitalTuner::Register>),
56        (0x048 => eve: WriteOnly<u32, Event::Register>),
57        (0x04C => evd: WriteOnly<u32, Event::Register>),
58        (0x050 => evm: ReadOnly<u32, Event::Register>),
59        (0x054 => calv: ReadWrite<u32, Calendar::Register>),
60        (0x058 => @END),
61    }
62}
63
64register_bitfields![u32,
65    Control [
66        /// Prescalar Select
67        PSEL OFFSET(16) NUMBITS(5) [],
68        /// Clear on Alarm 1
69        CA1  OFFSET(9) NUMBITS(1) [
70            NoClearCounter = 0,
71            ClearCounter = 1
72        ],
73        /// Clear on Alarm 0
74        CA0  OFFSET(8) NUMBITS(1) [
75            NoClearCounter = 0,
76            ClearCounter = 1
77        ],
78        /// Calendar Mode
79        CAL  OFFSET(2) NUMBITS(1) [
80            CounterMode = 0,
81            CalendarMode = 1
82        ],
83        /// Prescalar Clear
84        PCLR OFFSET(1) NUMBITS(1) [],
85        /// Enable
86        EN   OFFSET(0) NUMBITS(1) [
87            Disable = 0,
88            Enable = 1
89        ]
90    ],
91
92    Value [
93        VALUE OFFSET(0) NUMBITS(32) []
94    ],
95
96    Status [
97        /// Clock Ready
98        CLKRDY 29,
99        /// Clock Busy
100        CLKBUSY 28,
101        /// AST Ready
102        READY 25,
103        /// AST Busy
104        BUSY 24,
105        /// Periodic 0
106        PER0 16,
107        /// Alarm 0
108        ALARM0 8,
109        /// Overflow
110        OVF 0
111    ],
112
113    Interrupt [
114        /// Clock Ready
115        CLKRDY 29,
116        /// AST Ready
117        READY 25,
118        /// Periodic 0
119        PER0 16,
120        /// Alarm 0
121        ALARM0 8,
122        /// Overflow
123        OVF 0
124    ],
125
126    Event [
127        /// Periodic 0
128        PER0 16,
129        /// Alarm 0
130        ALARM0 8,
131        /// Overflow
132        OVF 0
133    ],
134
135    PeriodicInterval [
136        /// Interval Select
137        INSEL OFFSET(0) NUMBITS(5) []
138    ],
139
140    ClockControl [
141        /// Clock Source Selection
142        CSSEL OFFSET(8) NUMBITS(3) [
143            RCSYS = 0,
144            OSC32 = 1,
145            APBClock = 2,
146            GCLK = 3,
147            Clk1k = 4
148        ],
149        /// Clock Enable
150        CEN   OFFSET(0) NUMBITS(1) [
151            Disable = 0,
152            Enable = 1
153        ]
154    ],
155
156    DigitalTuner [
157        VALUE OFFSET(8) NUMBITS(8) [],
158        ADD   OFFSET(5) NUMBITS(1) [],
159        EXP   OFFSET(0) NUMBITS(5) []
160    ],
161
162    Calendar [
163        YEAR  OFFSET(26) NUMBITS(6) [],
164        MONTH OFFSET(22) NUMBITS(4) [],
165        DAY   OFFSET(17) NUMBITS(5) [],
166        HOUR  OFFSET(12) NUMBITS(5) [],
167        MIN   OFFSET( 6) NUMBITS(6) [],
168        SEC   OFFSET( 0) NUMBITS(6) []
169    ]
170];
171
172const AST_ADDRESS: StaticRef<AstRegisters> =
173    unsafe { StaticRef::new(0x400F0800 as *const AstRegisters) };
174
175pub struct Ast<'a> {
176    registers: StaticRef<AstRegisters>,
177    callback: OptionalCell<&'a dyn time::AlarmClient>,
178}
179
180impl Ast<'_> {
181    pub const fn new() -> Self {
182        Self {
183            registers: AST_ADDRESS,
184            callback: OptionalCell::empty(),
185        }
186    }
187}
188
189impl Controller for Ast<'_> {
190    type Config = &'static dyn time::AlarmClient;
191
192    fn configure(&self, client: Self::Config) {
193        self.callback.set(client);
194
195        pm::enable_clock(pm::Clock::PBD(PBDClock::AST));
196        self.select_clock(Clock::ClockOsc32);
197        self.disable();
198        self.disable_alarm_irq();
199        self.set_prescalar(0); // 32KHz / (2^(0 + 1)) = 16KHz
200        self.enable_alarm_wake();
201
202        self.clear_alarm();
203    }
204}
205
206#[repr(usize)]
207#[allow(dead_code)]
208enum Clock {
209    ClockRCSys = 0,
210    ClockOsc32 = 1,
211    ClockAPB = 2,
212    ClockGclk2 = 3,
213    Clock1K = 4,
214}
215
216impl Ast<'_> {
217    fn clock_busy(&self) -> bool {
218        self.registers.sr.is_set(Status::CLKBUSY)
219    }
220
221    fn busy(&self) -> bool {
222        self.registers.sr.is_set(Status::BUSY)
223    }
224
225    /// Clears the alarm bit in the status register (indicating the alarm value
226    /// has been reached).
227    fn clear_alarm(&self) {
228        while self.busy() {}
229        self.registers.scr.write(Interrupt::ALARM0::SET);
230        while self.busy() {}
231    }
232
233    // Configure the clock to use to drive the AST
234    fn select_clock(&self, clock: Clock) {
235        // Disable clock by setting first bit to zero
236        while self.clock_busy() {}
237        self.registers.clock.modify(ClockControl::CEN::CLEAR);
238        while self.clock_busy() {}
239
240        // Select clock
241        self.registers
242            .clock
243            .write(ClockControl::CSSEL.val(clock as u32));
244        while self.clock_busy() {}
245
246        // Re-enable clock
247        self.registers.clock.modify(ClockControl::CEN::SET);
248        while self.clock_busy() {}
249    }
250
251    /// Enables the AST registers
252    fn enable(&self) {
253        while self.busy() {}
254        self.registers.cr.modify(Control::EN::SET);
255        while self.busy() {}
256    }
257
258    /// Disable the AST registers
259    fn disable(&self) {
260        while self.busy() {}
261        self.registers.cr.modify(Control::EN::CLEAR);
262        while self.busy() {}
263    }
264
265    fn is_enabled(&self) -> bool {
266        let regs: &AstRegisters = &self.registers;
267        while self.busy() {}
268        regs.cr.is_set(Control::EN)
269    }
270
271    /// Returns if an alarm is currently set
272    fn is_alarm_enabled(&self) -> bool {
273        while self.busy() {}
274        self.registers.sr.is_set(Status::ALARM0)
275    }
276
277    fn set_prescalar(&self, val: u8) {
278        while self.busy() {}
279        self.registers.cr.modify(Control::PSEL.val(val as u32));
280        while self.busy() {}
281    }
282
283    fn enable_alarm_irq(&self) {
284        self.registers.ier.write(Interrupt::ALARM0::SET);
285    }
286
287    fn disable_alarm_irq(&self) {
288        self.registers.idr.write(Interrupt::ALARM0::SET);
289    }
290
291    fn enable_alarm_wake(&self) {
292        while self.busy() {}
293        self.registers.wer.modify(Event::ALARM0::SET);
294        while self.busy() {}
295    }
296
297    fn get_counter(&self) -> u32 {
298        while self.busy() {}
299        self.registers.cv.read(Value::VALUE)
300    }
301
302    fn set_counter(&self, val: u32) {
303        let regs: &AstRegisters = &self.registers;
304        while self.busy() {}
305        regs.cv.set(val);
306    }
307
308    pub fn handle_interrupt(&self) {
309        self.clear_alarm();
310        self.callback.map(|cb| {
311            cb.alarm();
312        });
313    }
314}
315
316impl time::Time for Ast<'_> {
317    type Frequency = time::Freq16KHz;
318    type Ticks = time::Ticks32;
319
320    fn now(&self) -> Self::Ticks {
321        Self::Ticks::from(self.get_counter())
322    }
323}
324
325impl<'a> time::Counter<'a> for Ast<'a> {
326    fn start(&self) -> Result<(), ErrorCode> {
327        self.enable();
328        Ok(())
329    }
330
331    fn stop(&self) -> Result<(), ErrorCode> {
332        self.disable();
333        Ok(())
334    }
335
336    fn reset(&self) -> Result<(), ErrorCode> {
337        self.set_counter(0);
338        Ok(())
339    }
340
341    fn is_running(&self) -> bool {
342        self.is_enabled()
343    }
344}
345
346impl<'a> time::Alarm<'a> for Ast<'a> {
347    fn set_alarm_client(&self, client: &'a dyn time::AlarmClient) {
348        self.callback.set(client);
349    }
350
351    fn set_alarm(&self, reference: Self::Ticks, dt: Self::Ticks) {
352        let now = Self::Ticks::from(self.get_counter());
353        let mut expire = reference.wrapping_add(dt);
354        if !now.within_range(reference, expire) {
355            // We have already passed when: just fire ASAP
356            // Note this will also trigger the increment below
357            expire = now;
358        }
359
360        // Firing is too close in the future, delay it a bit
361        // to make sure we don't miss the tick
362        if expire.wrapping_sub(now).into_u32() <= ALARM0_SYNC_TICS {
363            expire = now.wrapping_add(Self::Ticks::from(ALARM0_SYNC_TICS));
364        }
365
366        // Clear any alarm event that may be pending before setting new alarm.
367        self.clear_alarm();
368
369        while self.busy() {}
370        self.registers
371            .ar0
372            .write(Value::VALUE.val(expire.into_u32()));
373
374        while self.busy() {}
375        self.enable_alarm_irq();
376        self.enable();
377    }
378
379    fn get_alarm(&self) -> Self::Ticks {
380        while self.busy() {}
381        Self::Ticks::from(self.registers.ar0.read(Value::VALUE))
382    }
383
384    fn disarm(&self) -> Result<(), ErrorCode> {
385        // After disabling the IRQ and clearing the alarm bit in the
386        // status register, the NVIC bit is also guaranteed to be clear.
387        self.disable_alarm_irq();
388        self.clear_alarm();
389        Ok(())
390    }
391
392    fn is_armed(&self) -> bool {
393        self.is_alarm_enabled()
394    }
395
396    fn minimum_dt(&self) -> Self::Ticks {
397        Self::Ticks::from(ALARM0_SYNC_TICS)
398    }
399}