nrf52_hal_common/
rtc.rs

1//! A high level interface for RTC peripherals
2
3use core::ops::Deref;
4
5use crate::target::{rtc0, Interrupt, NVIC, RTC0, RTC1};
6
7#[cfg(not(feature = "52810"))]
8use crate::target::RTC2;
9
10// Zero Size Type State structs
11
12/// The RTC has been stopped
13pub struct Stopped;
14/// The RTC has been started
15pub struct Started;
16
17/// An opaque high level interface to an RTC peripheral
18pub struct Rtc<T, M> {
19    periph: T,
20    _mode: M,
21}
22
23/// An extension trait for constructing the high level interface
24pub trait RtcExt: Deref<Target = rtc0::RegisterBlock> + Sized {
25    // The interrupt that belongs to this RTC instance.
26    const INTERRUPT: Interrupt;
27
28    fn constrain(self) -> Rtc<Self, Stopped>;
29}
30
31macro_rules! impl_rtc_ext {
32    ($($rtc:ident,)*) => {
33        $(
34            impl RtcExt for $rtc {
35                const INTERRUPT: Interrupt = Interrupt::$rtc;
36
37                fn constrain(self) -> Rtc<$rtc, Stopped> {
38                    Rtc {
39                        periph: self,
40                        _mode: Stopped,
41                    }
42                }
43            }
44        )+
45    }
46}
47
48impl_rtc_ext!(RTC0, RTC1,);
49
50#[cfg(not(feature = "52810"))]
51impl_rtc_ext!(RTC2,);
52
53/// Interrupts/Events that can be generated by the RTCn peripheral
54pub enum RtcInterrupt {
55    Tick,
56    Overflow,
57    Compare0,
58    Compare1,
59    Compare2,
60    Compare3,
61}
62
63/// Compare registers available on the RTCn
64pub enum RtcCompareReg {
65    Compare0,
66    Compare1,
67    Compare2,
68    Compare3,
69}
70
71impl<T, M> Rtc<T, M>
72where
73    T: RtcExt,
74{
75    /// Enable/start the Real Time Counter
76    pub fn enable_counter(self) -> Rtc<T, Started> {
77        unsafe {
78            self.periph.tasks_start.write(|w| w.bits(1));
79        }
80        Rtc {
81            periph: self.periph,
82            _mode: Started,
83        }
84    }
85
86    /// Disable/stop the Real Time Counter
87    pub fn disable_counter(self) -> Rtc<T, Stopped> {
88        unsafe {
89            self.periph.tasks_stop.write(|w| w.bits(1));
90        }
91        Rtc {
92            periph: self.periph,
93            _mode: Stopped,
94        }
95    }
96
97    /// Enable the generation of a hardware interrupt from a given stimulus
98    pub fn enable_interrupt(&mut self, int: RtcInterrupt, nvic: &mut NVIC) {
99        match int {
100            RtcInterrupt::Tick => self.periph.intenset.write(|w| w.tick().set()),
101            RtcInterrupt::Overflow => self.periph.intenset.write(|w| w.ovrflw().set()),
102            RtcInterrupt::Compare0 => self.periph.intenset.write(|w| w.compare0().set()),
103            RtcInterrupt::Compare1 => self.periph.intenset.write(|w| w.compare1().set()),
104            RtcInterrupt::Compare2 => self.periph.intenset.write(|w| w.compare2().set()),
105            RtcInterrupt::Compare3 => self.periph.intenset.write(|w| w.compare3().set()),
106        }
107        nvic.enable(T::INTERRUPT);
108    }
109
110    /// Disable the generation of a hardware interrupt from a given stimulus
111    pub fn disable_interrupt(&mut self, int: RtcInterrupt, nvic: &mut NVIC) {
112        match int {
113            RtcInterrupt::Tick => self.periph.intenclr.write(|w| w.tick().clear()),
114            RtcInterrupt::Overflow => self.periph.intenclr.write(|w| w.ovrflw().clear()),
115            RtcInterrupt::Compare0 => self.periph.intenclr.write(|w| w.compare0().clear()),
116            RtcInterrupt::Compare1 => self.periph.intenclr.write(|w| w.compare1().clear()),
117            RtcInterrupt::Compare2 => self.periph.intenclr.write(|w| w.compare2().clear()),
118            RtcInterrupt::Compare3 => self.periph.intenclr.write(|w| w.compare3().clear()),
119        }
120        nvic.disable(T::INTERRUPT);
121    }
122
123    /// Enable the generation of a hardware event from a given stimulus
124    pub fn enable_event(&mut self, evt: RtcInterrupt) {
125        match evt {
126            RtcInterrupt::Tick => self.periph.evtenset.write(|w| w.tick().set()),
127            RtcInterrupt::Overflow => self.periph.evtenset.write(|w| w.ovrflw().set()),
128            RtcInterrupt::Compare0 => self.periph.evtenset.write(|w| w.compare0().set()),
129            RtcInterrupt::Compare1 => self.periph.evtenset.write(|w| w.compare1().set()),
130            RtcInterrupt::Compare2 => self.periph.evtenset.write(|w| w.compare2().set()),
131            RtcInterrupt::Compare3 => self.periph.evtenset.write(|w| w.compare3().set()),
132        }
133    }
134
135    /// Disables the generation of a hardware event from a given stimulus
136    pub fn disable_event(&mut self, evt: RtcInterrupt) {
137        match evt {
138            RtcInterrupt::Tick => self.periph.evtenclr.write(|w| w.tick().clear()),
139            RtcInterrupt::Overflow => self.periph.evtenclr.write(|w| w.ovrflw().clear()),
140            RtcInterrupt::Compare0 => self.periph.evtenclr.write(|w| w.compare0().clear()),
141            RtcInterrupt::Compare1 => self.periph.evtenclr.write(|w| w.compare1().clear()),
142            RtcInterrupt::Compare2 => self.periph.evtenclr.write(|w| w.compare2().clear()),
143            RtcInterrupt::Compare3 => self.periph.evtenclr.write(|w| w.compare3().clear()),
144        }
145    }
146
147    /// Obtain the state of a given interrupt/event, and optionally clear the event
148    /// if it is set
149    pub fn get_event_triggered(&mut self, evt: RtcInterrupt, clear_on_read: bool) -> bool {
150        let mut orig = 0;
151        let set_val = if clear_on_read { 0 } else { 1 };
152        match evt {
153            RtcInterrupt::Tick => self.periph.events_tick.modify(|r, w| {
154                orig = r.bits();
155                unsafe { w.bits(set_val) }
156            }),
157            RtcInterrupt::Overflow => self.periph.events_ovrflw.modify(|r, w| {
158                orig = r.bits();
159                unsafe { w.bits(set_val) }
160            }),
161            RtcInterrupt::Compare0 => self.periph.events_compare[0].modify(|r, w| {
162                orig = r.bits();
163                unsafe { w.bits(set_val) }
164            }),
165            RtcInterrupt::Compare1 => self.periph.events_compare[1].modify(|r, w| {
166                orig = r.bits();
167                unsafe { w.bits(set_val) }
168            }),
169            RtcInterrupt::Compare2 => self.periph.events_compare[2].modify(|r, w| {
170                orig = r.bits();
171                unsafe { w.bits(set_val) }
172            }),
173            RtcInterrupt::Compare3 => self.periph.events_compare[3].modify(|r, w| {
174                orig = r.bits();
175                unsafe { w.bits(set_val) }
176            }),
177        };
178
179        orig == 1
180    }
181
182    /// Set the compare value of a given register. The compare registers have a width
183    /// of 24 bits
184    pub fn set_compare(&mut self, reg: RtcCompareReg, val: u32) -> Result<(), Error> {
185        if val >= (1 << 24) {
186            return Err(Error::CompareOutOfRange);
187        }
188
189        let reg = match reg {
190            RtcCompareReg::Compare0 => 0,
191            RtcCompareReg::Compare1 => 1,
192            RtcCompareReg::Compare2 => 2,
193            RtcCompareReg::Compare3 => 3,
194        };
195
196        unsafe {
197            self.periph.cc[reg].write(|w| w.bits(val));
198        }
199
200        Ok(())
201    }
202
203    /// Obtain the current value of the Real Time Counter, 24 bits of range
204    pub fn get_counter(&self) -> u32 {
205        self.periph.counter.read().bits()
206    }
207
208    /// Destructure the high level interface. Does not reset any configuration made
209    /// to the given RTC peripheral
210    pub fn release(self) -> T {
211        self.periph
212    }
213}
214
215/// Error types associated with the RTC peripheral interface
216#[derive(Debug, PartialEq, Eq)]
217pub enum Error {
218    PrescalerOutOfRange,
219    CompareOutOfRange,
220}
221
222impl<T> Rtc<T, Stopped>
223where
224    T: RtcExt,
225{
226    /// Set the prescaler for the RTC peripheral. 12 bits of range.
227    /// fRTC = 32_768 / (`prescaler` + 1 )
228    pub fn set_prescaler(&mut self, prescaler: u32) -> Result<(), Error> {
229        if prescaler >= (1 << 12) {
230            return Err(Error::PrescalerOutOfRange);
231        }
232
233        unsafe { self.periph.prescaler.write(|w| w.bits(prescaler)) };
234
235        Ok(())
236    }
237}