atsamd_hal/rtc/
mod.rs
1use atsamd_hal_macros::hal_cfg;
3use fugit::ExtU32;
4
5use crate::ehal;
6use crate::ehal_02;
7use crate::pac;
8use crate::time::{Hertz, Nanoseconds};
9use crate::timer_traits::InterruptDrivenTimer;
10use crate::typelevel::Sealed;
11use core::convert::Infallible;
12use core::marker::PhantomData;
13use modes::{
14 RtcMode as _,
15 mode0::{Compare0, RtcMode0},
16 mode2::RtcMode2,
17};
18
19#[cfg(feature = "sdmmc")]
20use embedded_sdmmc::{TimeSource, Timestamp};
21
22mod modes;
23
24#[cfg(feature = "rtic")]
25pub mod rtic;
26
27#[hal_cfg("rtc-d5x")]
29use crate::pac::{Mclk as Pm, rtc::mode0::ctrla::Prescalerselect};
30
31#[hal_cfg(any("rtc-d11", "rtc-d21"))]
33use crate::pac::{Pm, rtc::mode0::ctrl::Prescalerselect};
34
35pub use modes::mode2::Datetime;
36
37pub trait RtcMode: Sealed {}
39
40pub enum ClockMode {}
42
43impl RtcMode for ClockMode {}
44impl Sealed for ClockMode {}
45
46pub enum Count32Mode {}
52
53impl RtcMode for Count32Mode {}
54impl Sealed for Count32Mode {}
55
56#[cfg(feature = "sdmmc")]
57impl From<Datetime> for Timestamp {
58 fn from(clock: Datetime) -> Timestamp {
59 Timestamp {
60 year_since_1970: clock.year,
61 zero_indexed_month: clock.month,
62 zero_indexed_day: clock.day,
63 hours: clock.hours,
64 minutes: clock.minutes,
65 seconds: clock.seconds,
66 }
67 }
68}
69
70pub struct Rtc<Mode: RtcMode> {
72 rtc: pac::Rtc,
73 rtc_clock_freq: Hertz,
74 _mode: PhantomData<Mode>,
75}
76
77impl<Mode: RtcMode> Rtc<Mode> {
78 fn set_count32_mode(rtc: &pac::Rtc) {
79 RtcMode0::disable(rtc);
80 RtcMode0::reset(rtc);
81 RtcMode0::set_mode(rtc);
82 RtcMode0::start_and_initialize(rtc);
83 }
84
85 fn set_clock_mode(rtc: &pac::Rtc, rtc_clock_freq: Hertz) {
86 let divider = TimerParams::prescaler_from_divider(rtc_clock_freq.raw() as u64)
87 .unwrap_or_else(|| {
88 panic!("cannot use clock mode with an RTC clock rate of {rtc_clock_freq}")
89 });
90
91 RtcMode2::disable(rtc);
92 RtcMode2::reset(rtc);
93 RtcMode2::set_mode(rtc);
94 RtcMode2::set_prescaler(rtc, divider);
95 RtcMode2::start_and_initialize(rtc);
96 }
97
98 fn create(rtc: pac::Rtc, rtc_clock_freq: Hertz) -> Self {
99 Self {
100 rtc,
101 rtc_clock_freq,
102 _mode: PhantomData,
103 }
104 }
105
106 fn into_mode<M: RtcMode>(self) -> Rtc<M> {
107 Rtc::create(self.rtc, self.rtc_clock_freq)
108 }
109
110 pub fn into_count32_mode(self) -> Rtc<Count32Mode> {
113 Self::set_count32_mode(&self.rtc);
114 self.into_mode()
115 }
116
117 pub fn into_clock_mode(self) -> Rtc<ClockMode> {
120 Self::set_clock_mode(&self.rtc, self.rtc_clock_freq);
121 self.into_mode()
122 }
123
124 pub fn free(self) -> pac::Rtc {
126 self.rtc
127 }
128}
129
130impl Rtc<Count32Mode> {
131 pub fn count32_mode(rtc: pac::Rtc, rtc_clock_freq: Hertz, pm: &mut Pm) -> Self {
134 RtcMode0::disable(&rtc);
135
136 pm.apbamask().modify(|_, w| w.rtc_().set_bit());
140
141 Self::set_count32_mode(&rtc);
142
143 Self {
144 rtc,
145 rtc_clock_freq,
146 _mode: PhantomData,
147 }
148 }
149
150 #[inline]
152 pub fn count32(&self) -> u32 {
153 RtcMode0::count(&self.rtc)
154 }
155
156 #[inline]
158 pub fn set_count32(&mut self, count: u32) {
159 RtcMode0::disable(&self.rtc);
160 RtcMode0::set_count(&self.rtc, count);
161 RtcMode0::enable(&self.rtc);
162 }
163
164 fn reset_and_set_prescaler(&mut self, divider: Prescalerselect) {
167 RtcMode0::disable(&self.rtc);
168 RtcMode0::reset(&self.rtc);
169 RtcMode0::set_mode(&self.rtc);
170 RtcMode0::set_prescaler(&self.rtc, divider);
171 }
172
173 pub fn reset_and_compute_prescaler<T: Into<Nanoseconds>>(&mut self, timeout: T) -> &Self {
177 let params = TimerParams::new_us(timeout, self.rtc_clock_freq);
178 let divider = params.divider;
179
180 self.reset_and_set_prescaler(divider);
181 RtcMode0::start_and_initialize(&self.rtc);
182
183 self
184 }
185}
186
187impl Rtc<ClockMode> {
188 pub fn clock_mode(rtc: pac::Rtc, rtc_clock_freq: Hertz, pm: &mut Pm) -> Self {
189 Rtc::count32_mode(rtc, rtc_clock_freq, pm).into_clock_mode()
190 }
191
192 pub fn current_time(&self) -> Datetime {
194 RtcMode2::count(&self.rtc)
195 }
196
197 pub fn set_time(&mut self, time: Datetime) {
199 RtcMode2::set_count(&self.rtc, time);
200 }
201}
202
203impl ehal_02::timer::Periodic for Rtc<Count32Mode> {}
205impl ehal_02::timer::CountDown for Rtc<Count32Mode> {
206 type Time = Nanoseconds;
207
208 fn start<T>(&mut self, timeout: T)
212 where
213 T: Into<Self::Time>,
214 {
215 <Self as InterruptDrivenTimer>::start(self, timeout);
216 }
217
218 fn wait(&mut self) -> nb::Result<(), void::Void> {
219 <Self as InterruptDrivenTimer>::wait(self).map_err(|e| e.map(|_| panic!()))
220 }
221}
222
223impl ehal::delay::DelayNs for Rtc<Count32Mode> {
224 fn delay_ns(&mut self, ns: u32) {
225 <Self as InterruptDrivenTimer>::start(self, ns.nanos());
226 let _ = nb::block!(<Self as InterruptDrivenTimer>::wait(self));
228 }
229}
230
231impl InterruptDrivenTimer for Rtc<Count32Mode> {
232 fn enable_interrupt(&mut self) {
237 RtcMode0::enable_interrupt::<Compare0>(&self.rtc);
238 }
239
240 fn start<T>(&mut self, timeout: T)
244 where
245 T: Into<Nanoseconds>,
246 {
247 let params = TimerParams::new_us(timeout, self.rtc_clock_freq);
248 let divider = params.divider;
249 let cycles = params.cycles;
250
251 self.reset_and_set_prescaler(divider);
253 RtcMode0::set_compare(&self.rtc, 0, cycles);
255 RtcMode0::set_match_clear(&self.rtc, true);
257
258 RtcMode0::start_and_initialize(&self.rtc);
260 }
261
262 fn wait(&mut self) -> nb::Result<(), Infallible> {
263 if RtcMode0::check_interrupt_flag::<Compare0>(&self.rtc) {
264 RtcMode0::clear_interrupt_flag::<Compare0>(&self.rtc);
266 Ok(())
267 } else {
268 Err(nb::Error::WouldBlock)
269 }
270 }
271
272 fn disable_interrupt(&mut self) {
277 RtcMode0::disable_interrupt::<Compare0>(&self.rtc);
278 }
279}
280
281#[cfg(feature = "sdmmc")]
282impl TimeSource for Rtc<ClockMode> {
283 fn get_timestamp(&self) -> Timestamp {
284 self.current_time().into()
285 }
286}
287
288#[derive(Debug, Clone, Copy)]
290pub struct TimerParams {
291 pub divider: Prescalerselect,
292 pub cycles: u32,
293}
294
295impl TimerParams {
296 fn prescaler_from_divider(divider_value: u64) -> Option<Prescalerselect> {
297 match divider_value {
298 1 => Some(Prescalerselect::Div1),
299 2 => Some(Prescalerselect::Div2),
300 4 => Some(Prescalerselect::Div4),
301 8 => Some(Prescalerselect::Div8),
302 16 => Some(Prescalerselect::Div16),
303 32 => Some(Prescalerselect::Div32),
304 64 => Some(Prescalerselect::Div64),
305 128 => Some(Prescalerselect::Div128),
306 256 => Some(Prescalerselect::Div256),
307 512 => Some(Prescalerselect::Div512),
308 1024 => Some(Prescalerselect::Div1024),
309 _ => None,
310 }
311 }
312
313 pub fn new(timeout: impl Into<Hertz>, src_freq: impl Into<Hertz>) -> Self {
316 let timeout = timeout.into();
317 let src_freq = src_freq.into();
318 let ticks = src_freq.to_Hz() / timeout.to_Hz().max(1);
319 Self::new_from_ticks(ticks as u64)
320 }
321
322 pub fn new_us(timeout: impl Into<Nanoseconds>, src_freq: impl Into<Hertz>) -> Self {
324 let timeout = timeout.into();
325 let src_freq = src_freq.into();
326 let ticks = timeout.to_nanos() as u64 * src_freq.to_Hz() as u64 / 1_000_000_000;
327 Self::new_from_ticks(ticks)
328 }
329
330 fn new_from_ticks(ticks: u64) -> Self {
333 let mut divider_value = ((ticks >> 16) + 1).next_power_of_two();
334 let divider = Self::prescaler_from_divider(divider_value).unwrap_or_else(|| {
335 divider_value = 1024;
336
337 Prescalerselect::Div1024
338 });
339
340 let cycles: u32 = (ticks / divider_value)
341 .try_into()
342 .expect("cannot achieve the timeout even with the maximum RTC prescaler");
343
344 TimerParams { divider, cycles }
345 }
346}