1use atsamd_hal_macros::{hal_cfg, hal_macro_helper};
3use fugit::NanosDurationU32;
4
5use crate::ehal_02;
6use crate::pac;
7use crate::pac::rtc::{Mode0, Mode2};
8use crate::time::{Hertz, Nanoseconds};
9use crate::timer_traits::InterruptDrivenTimer;
10use crate::typelevel::Sealed;
11use core::convert::Infallible;
12use core::marker::PhantomData;
13
14#[cfg(feature = "sdmmc")]
15use embedded_sdmmc::{TimeSource, Timestamp};
16
17#[cfg(feature = "rtic")]
18mod modes;
19
20#[cfg(feature = "rtic")]
21pub mod rtic;
22
23#[hal_cfg("rtc-d5x")]
25use crate::pac::{
26 rtc::mode0::ctrla::Prescalerselect, rtc::mode0::Ctrla as Mode0CtrlA,
27 rtc::mode2::Ctrla as Mode2CtrlA, Mclk as Pm,
28};
29
30#[hal_cfg(any("rtc-d11", "rtc-d21"))]
32use crate::pac::{
33 rtc::mode0::ctrl::Prescalerselect, rtc::mode0::Ctrl as Mode0CtrlA,
34 rtc::mode2::Ctrl as Mode2CtrlA, Pm,
35};
36
37#[derive(Debug, Clone, Copy)]
39pub struct Datetime {
40 pub seconds: u8,
41 pub minutes: u8,
42 pub hours: u8,
43 pub day: u8,
44 pub month: u8,
45 pub year: u8,
46}
47
48type ClockR = crate::pac::rtc::mode2::clock::R;
49
50impl From<ClockR> for Datetime {
51 fn from(clock: ClockR) -> Datetime {
52 Datetime {
53 seconds: clock.second().bits(),
54 minutes: clock.minute().bits(),
55 hours: clock.hour().bits(),
56 day: clock.day().bits(),
57 month: clock.month().bits(),
58 year: clock.year().bits(),
59 }
60 }
61}
62
63pub trait RtcMode: Sealed {}
65
66pub enum ClockMode {}
68
69impl RtcMode for ClockMode {}
70impl Sealed for ClockMode {}
71
72pub enum Count32Mode {}
78
79impl RtcMode for Count32Mode {}
80impl Sealed for Count32Mode {}
81
82#[cfg(feature = "sdmmc")]
83impl From<Datetime> for Timestamp {
84 fn from(clock: Datetime) -> Timestamp {
85 Timestamp {
86 year_since_1970: clock.year,
87 zero_indexed_month: clock.month,
88 zero_indexed_day: clock.day,
89 hours: clock.hours,
90 minutes: clock.minutes,
91 seconds: clock.seconds,
92 }
93 }
94}
95
96pub struct Rtc<Mode: RtcMode> {
98 rtc: pac::Rtc,
99 rtc_clock_freq: Hertz,
100 _mode: PhantomData<Mode>,
101}
102
103impl<Mode: RtcMode> Rtc<Mode> {
104 #[inline]
106 fn mode0(&self) -> &Mode0 {
107 self.rtc.mode0()
108 }
109
110 #[inline]
111 fn mode2(&self) -> &Mode2 {
112 self.rtc.mode2()
113 }
114
115 #[inline]
116 #[hal_macro_helper]
117 fn mode0_ctrla(&self) -> &Mode0CtrlA {
118 #[hal_cfg("rtc-d5x")]
119 return self.mode0().ctrla();
120 #[hal_cfg(any("rtc-d11", "rtc-d21"))]
121 return self.mode0().ctrl();
122 }
123
124 #[inline]
125 #[hal_macro_helper]
126 fn mode2_ctrla(&self) -> &Mode2CtrlA {
127 #[hal_cfg("rtc-d5x")]
128 return self.mode2().ctrla();
129 #[hal_cfg(any("rtc-d11", "rtc-d21"))]
130 return self.mode2().ctrl();
131 }
132
133 #[inline]
134 #[hal_macro_helper]
135 fn sync(&self) {
136 #[hal_cfg("rtc-d5x")]
137 while self.mode2().syncbusy().read().bits() != 0 {}
138 #[hal_cfg(any("rtc-d11", "rtc-d21"))]
139 while self.mode2().status().read().syncbusy().bit_is_set() {}
140 }
141
142 #[inline]
143 fn reset(&mut self) {
144 self.mode0_ctrla().modify(|_, w| w.swrst().set_bit());
145 self.sync();
146 }
147
148 #[inline]
149 fn enable(&mut self, enable: bool) {
150 if enable {
151 self.mode0_ctrla().modify(|_, w| w.enable().set_bit());
152 } else {
153 self.mode0_ctrla().modify(|_, w| w.enable().clear_bit());
154 }
155 self.sync();
156 }
157
158 fn create(rtc: pac::Rtc, rtc_clock_freq: Hertz) -> Self {
159 Self {
160 rtc,
161 rtc_clock_freq,
162 _mode: PhantomData,
163 }
164 }
165
166 fn into_mode<M: RtcMode>(self) -> Rtc<M> {
167 Rtc::create(self.rtc, self.rtc_clock_freq)
168 }
169
170 #[hal_macro_helper]
172 pub fn into_count32_mode(mut self) -> Rtc<Count32Mode> {
173 self.enable(false);
174 self.sync();
175 self.mode0_ctrla().modify(|_, w| {
176 w.mode().count32() .matchclr().clear_bit()
178 .prescaler().div1() });
180 self.sync();
181
182 #[hal_cfg("rtc-d5x")]
184 {
185 self.mode2_ctrla().modify(|_, w| {
186 w.clocksync().set_bit() });
188
189 self.sync();
190 }
191
192 self.enable(true);
193 self.into_mode()
194 }
195
196 #[hal_macro_helper]
199 pub fn into_clock_mode(mut self) -> Rtc<ClockMode> {
200 assert_eq!(
202 self.rtc_clock_freq.to_Hz(),
203 1024_u32,
204 "RTC clk not 1024 Hz!"
205 );
206
207 self.sync();
208 self.enable(false);
209 self.sync();
210 self.mode2_ctrla().modify(|_, w| {
211 w.mode().clock() .clkrep().clear_bit()
213 .matchclr().clear_bit()
214 .prescaler().div1024() });
216
217 #[hal_cfg("rtc-d5x")]
219 {
220 self.mode2_ctrla().modify(|_, w| {
221 w.clocksync().set_bit() });
223
224 self.sync();
225 }
226
227 self.sync();
228 self.enable(true);
229 self.into_mode()
230 }
231
232 pub fn free(self) -> pac::Rtc {
234 self.rtc
235 }
236}
237
238impl Rtc<Count32Mode> {
239 pub fn count32_mode(rtc: pac::Rtc, rtc_clock_freq: Hertz, pm: &mut Pm) -> Self {
242 pm.apbamask().modify(|_, w| w.rtc_().set_bit());
243
244 let mut new_rtc = Self {
249 rtc,
250 rtc_clock_freq,
251 _mode: PhantomData,
252 };
253
254 new_rtc.reset();
255 new_rtc.enable(true);
256 new_rtc
257 }
258
259 #[inline]
261 #[hal_macro_helper]
262 pub fn count32(&self) -> u32 {
263 #[hal_cfg(any("rtc-d11", "rtc-d21"))]
265 {
266 self.mode0().readreq().modify(|_, w| w.rcont().set_bit());
267 self.sync();
268 }
269 self.mode0().count().read().bits()
270 }
271
272 #[inline]
274 pub fn set_count32(&mut self, count: u32) {
275 self.sync();
276 self.enable(false);
277
278 self.sync();
279 self.mode0()
280 .count()
281 .write(|w| unsafe { w.count().bits(count) });
282
283 self.sync();
284 self.enable(true);
285 }
286
287 pub fn reset_and_compute_prescaler<T: Into<<Self as ehal_02::timer::CountDown>::Time>>(
291 &mut self,
292 timeout: T,
293 ) -> &Self {
294 let params = TimerParams::new_us(timeout, self.rtc_clock_freq);
295 let divider = params.divider;
296
297 self.sync();
299 self.enable(false);
300
301 self.sync();
304 self.reset();
305
306 while self.mode0_ctrla().read().swrst().bit_is_set() {}
307
308 self.mode0_ctrla().modify(|_, w| {
309 w.prescaler().variant(divider);
311 w.enable().set_bit()
313 });
314 self
315 }
316}
317
318impl Rtc<ClockMode> {
319 pub fn clock_mode(rtc: pac::Rtc, rtc_clock_freq: Hertz, pm: &mut Pm) -> Self {
320 Rtc::count32_mode(rtc, rtc_clock_freq, pm).into_clock_mode()
321 }
322
323 #[hal_macro_helper]
325 pub fn current_time(&self) -> Datetime {
326 #[hal_cfg(any("rtc-d11", "rtc-d21"))]
328 {
329 self.mode2().readreq().modify(|_, w| w.rcont().set_bit());
330 self.sync();
331 }
332 self.mode2().clock().read().into()
333 }
334
335 pub fn set_time(&mut self, time: Datetime) {
337 self.mode2().clock().write(|w| unsafe {
338 w.second()
339 .bits(time.seconds)
340 .minute()
341 .bits(time.minutes)
342 .hour()
343 .bits(time.hours)
344 .day()
345 .bits(time.day)
346 .month()
347 .bits(time.month)
348 .year()
349 .bits(time.year)
350 });
351 self.sync();
352 }
353}
354
355impl ehal_02::timer::Periodic for Rtc<Count32Mode> {}
358impl ehal_02::timer::CountDown for Rtc<Count32Mode> {
359 type Time = Nanoseconds;
360
361 fn start<T>(&mut self, timeout: T)
362 where
363 T: Into<Self::Time>,
364 {
365 <Self as InterruptDrivenTimer>::start(self, timeout);
366 }
367
368 fn wait(&mut self) -> nb::Result<(), void::Void> {
369 <Self as InterruptDrivenTimer>::wait(self).unwrap();
371 Ok(())
372 }
373}
374
375impl InterruptDrivenTimer for Rtc<Count32Mode> {
376 fn enable_interrupt(&mut self) {
381 self.mode0().intenset().write(|w| w.cmp0().set_bit());
382 }
383
384 fn start<T>(&mut self, timeout: T)
385 where
386 T: Into<NanosDurationU32>,
387 {
388 let params = TimerParams::new_us(timeout, self.rtc_clock_freq);
389 let divider = params.divider;
390 let cycles = params.cycles;
391
392 self.enable(false);
394
395 self.reset();
398 while self.mode0_ctrla().read().swrst().bit_is_set() {}
399
400 self.mode0()
402 .comp(0)
403 .write(|w| unsafe { w.comp().bits(cycles) });
404 self.mode0_ctrla().modify(|_, w| {
405 w.prescaler().variant(divider);
407 w.matchclr().set_bit();
409 w.enable().set_bit()
411 });
412 }
413
414 fn wait(&mut self) -> nb::Result<(), Infallible> {
415 if self.mode0().intflag().read().cmp0().bit_is_set() {
416 self.mode0().intflag().modify(|_, w| w.cmp0().set_bit());
418 Ok(())
419 } else {
420 Err(nb::Error::WouldBlock)
421 }
422 }
423
424 fn disable_interrupt(&mut self) {
429 self.mode0().intenclr().write(|w| w.cmp0().set_bit());
430 }
431}
432
433#[cfg(feature = "sdmmc")]
434impl TimeSource for Rtc<ClockMode> {
435 fn get_timestamp(&self) -> Timestamp {
436 self.current_time().into()
437 }
438}
439
440#[derive(Debug, Clone, Copy)]
442pub struct TimerParams {
443 pub divider: Prescalerselect,
444 pub cycles: u32,
445}
446
447impl TimerParams {
448 pub fn new(timeout: impl Into<Hertz>, src_freq: impl Into<Hertz>) -> Self {
451 let timeout = timeout.into();
452 let src_freq = src_freq.into();
453 let ticks: u32 = src_freq.to_Hz() / timeout.to_Hz().max(1);
454 Self::new_from_ticks(ticks)
455 }
456
457 pub fn new_us(timeout: impl Into<Nanoseconds>, src_freq: impl Into<Hertz>) -> Self {
459 let timeout = timeout.into();
460 let src_freq = src_freq.into();
461 let ticks: u32 =
462 (timeout.to_nanos() as u64 * src_freq.to_Hz() as u64 / 1_000_000_000_u64) as u32;
463 Self::new_from_ticks(ticks)
464 }
465
466 fn new_from_ticks(ticks: u32) -> Self {
469 let divider_value = ((ticks >> 16) + 1).next_power_of_two();
470 let divider = match divider_value {
471 1 => Prescalerselect::Div1,
472 2 => Prescalerselect::Div2,
473 4 => Prescalerselect::Div4,
474 8 => Prescalerselect::Div8,
475 16 => Prescalerselect::Div16,
476 32 => Prescalerselect::Div32,
477 64 => Prescalerselect::Div64,
478 128 => Prescalerselect::Div128,
479 256 => Prescalerselect::Div256,
480 512 => Prescalerselect::Div512,
481 1024 => Prescalerselect::Div1024,
482 _ => Prescalerselect::Div1024, };
485
486 let cycles: u32 = ticks / divider_value;
487
488 TimerParams { divider, cycles }
489 }
490}