aboutsummaryrefslogtreecommitdiff
path: root/src/rtc.rs
diff options
context:
space:
mode:
authorFelipe Balbi <[email protected]>2025-11-07 11:00:15 -0800
committerGitHub <[email protected]>2025-11-07 11:00:15 -0800
commit5632acec18cc5906b1625a8facf530db56c73300 (patch)
treeabf2897f4b2f9814069c64611896be2d42cf2ce8 /src/rtc.rs
parent47e383545f4aac3bfaec0563429cc721540e665a (diff)
parent9590d94ee9ba016f65a13100c429fc56ffe58e40 (diff)
Merge pull request #1 from bogdan-petru/import/mcxa276-initial
feat(mcxa276): initial HAL import
Diffstat (limited to 'src/rtc.rs')
-rw-r--r--src/rtc.rs284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/rtc.rs b/src/rtc.rs
new file mode 100644
index 000000000..d62da1f0a
--- /dev/null
+++ b/src/rtc.rs
@@ -0,0 +1,284 @@
1//! RTC DateTime driver.
2use core::sync::atomic::{AtomicBool, Ordering};
3
4use crate::pac;
5use crate::pac::rtc0::cr::Um;
6
7type Regs = pac::rtc0::RegisterBlock;
8
9static ALARM_TRIGGERED: AtomicBool = AtomicBool::new(false);
10
11// Token-based instance pattern like embassy-imxrt
12pub trait Instance {
13 fn ptr() -> *const Regs;
14}
15
16/// Token for RTC0
17pub type Rtc0 = crate::peripherals::RTC0;
18impl Instance for crate::peripherals::RTC0 {
19 #[inline(always)]
20 fn ptr() -> *const Regs {
21 pac::Rtc0::ptr()
22 }
23}
24
25// Also implement Instance for the Peri wrapper type
26impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::RTC0> {
27 #[inline(always)]
28 fn ptr() -> *const Regs {
29 pac::Rtc0::ptr()
30 }
31}
32
33const DAYS_IN_A_YEAR: u32 = 365;
34const SECONDS_IN_A_DAY: u32 = 86400;
35const SECONDS_IN_A_HOUR: u32 = 3600;
36const SECONDS_IN_A_MINUTE: u32 = 60;
37const YEAR_RANGE_START: u16 = 1970;
38
39#[derive(Debug, Clone, Copy)]
40pub struct RtcDateTime {
41 pub year: u16,
42 pub month: u8,
43 pub day: u8,
44 pub hour: u8,
45 pub minute: u8,
46 pub second: u8,
47}
48#[derive(Copy, Clone)]
49pub struct RtcConfig {
50 #[allow(dead_code)]
51 wakeup_select: bool,
52 update_mode: Um,
53 #[allow(dead_code)]
54 supervisor_access: bool,
55 compensation_interval: u8,
56 compensation_time: u8,
57}
58
59#[derive(Copy, Clone)]
60pub struct RtcInterruptEnable;
61impl RtcInterruptEnable {
62 pub const RTC_TIME_INVALID_INTERRUPT_ENABLE: u32 = 1 << 0;
63 pub const RTC_TIME_OVERFLOW_INTERRUPT_ENABLE: u32 = 1 << 1;
64 pub const RTC_ALARM_INTERRUPT_ENABLE: u32 = 1 << 2;
65 pub const RTC_SECONDS_INTERRUPT_ENABLE: u32 = 1 << 4;
66}
67
68pub fn convert_datetime_to_seconds(datetime: &RtcDateTime) -> u32 {
69 let month_days: [u16; 13] = [0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
70
71 let mut seconds = (datetime.year as u32 - 1970) * DAYS_IN_A_YEAR;
72 seconds += (datetime.year as u32 / 4) - (1970 / 4);
73 seconds += month_days[datetime.month as usize] as u32;
74 seconds += datetime.day as u32 - 1;
75
76 if (datetime.year & 3 == 0) && (datetime.month <= 2) {
77 seconds -= 1;
78 }
79
80 seconds = seconds * SECONDS_IN_A_DAY
81 + (datetime.hour as u32 * SECONDS_IN_A_HOUR)
82 + (datetime.minute as u32 * SECONDS_IN_A_MINUTE)
83 + datetime.second as u32;
84
85 seconds
86}
87
88pub fn convert_seconds_to_datetime(seconds: u32) -> RtcDateTime {
89 let mut seconds_remaining = seconds;
90 let mut days = seconds_remaining / SECONDS_IN_A_DAY + 1;
91 seconds_remaining %= SECONDS_IN_A_DAY;
92
93 let hour = (seconds_remaining / SECONDS_IN_A_HOUR) as u8;
94 seconds_remaining %= SECONDS_IN_A_HOUR;
95 let minute = (seconds_remaining / SECONDS_IN_A_MINUTE) as u8;
96 let second = (seconds_remaining % SECONDS_IN_A_MINUTE) as u8;
97
98 let mut year = YEAR_RANGE_START;
99 let mut days_in_year = DAYS_IN_A_YEAR;
100
101 while days > days_in_year {
102 days -= days_in_year;
103 year += 1;
104
105 days_in_year = if year % 4 == 0 {
106 DAYS_IN_A_YEAR + 1
107 } else {
108 DAYS_IN_A_YEAR
109 };
110 }
111
112 let mut days_per_month = [0u8, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
113 if year % 4 == 0 {
114 days_per_month[2] = 29;
115 }
116
117 let mut month = 1;
118 for m in 1..=12 {
119 if days <= days_per_month[m] as u32 {
120 month = m;
121 break;
122 } else {
123 days -= days_per_month[m] as u32;
124 }
125 }
126
127 let day = days as u8;
128
129 RtcDateTime {
130 year,
131 month: month as u8,
132 day,
133 hour,
134 minute,
135 second,
136 }
137}
138
139pub fn get_default_config() -> RtcConfig {
140 RtcConfig {
141 wakeup_select: false,
142 update_mode: Um::Um0,
143 supervisor_access: false,
144 compensation_interval: 0,
145 compensation_time: 0,
146 }
147}
148/// Minimal RTC handle for a specific instance I (store the zero-sized token like embassy)
149pub struct Rtc<I: Instance> {
150 _inst: core::marker::PhantomData<I>,
151}
152
153impl<I: Instance> Rtc<I> {
154 /// initialize RTC
155 pub fn new(_inst: impl Instance, config: RtcConfig) -> Self {
156 let rtc = unsafe { &*I::ptr() };
157
158 /* RTC reset */
159 rtc.cr().modify(|_, w| w.swr().set_bit());
160 rtc.cr().modify(|_, w| w.swr().clear_bit());
161 rtc.tsr().write(|w| unsafe { w.bits(1) });
162
163 rtc.cr().modify(|_, w| w.um().variant(config.update_mode));
164
165 rtc.tcr().modify(|_, w| unsafe {
166 w.cir()
167 .bits(config.compensation_interval)
168 .tcr()
169 .bits(config.compensation_time)
170 });
171
172 Self {
173 _inst: core::marker::PhantomData,
174 }
175 }
176
177 pub fn set_datetime(&self, datetime: RtcDateTime) {
178 let rtc = unsafe { &*I::ptr() };
179 let seconds = convert_datetime_to_seconds(&datetime);
180 rtc.tsr().write(|w| unsafe { w.bits(seconds) });
181 }
182
183 pub fn get_datetime(&self) -> RtcDateTime {
184 let rtc = unsafe { &*I::ptr() };
185 let seconds = rtc.tsr().read().bits();
186 convert_seconds_to_datetime(seconds)
187 }
188
189 pub fn set_alarm(&self, alarm: RtcDateTime) {
190 let rtc = unsafe { &*I::ptr() };
191 let seconds = convert_datetime_to_seconds(&alarm);
192
193 rtc.tar().write(|w| unsafe { w.bits(0) });
194 let mut timeout = 10000;
195 while rtc.tar().read().bits() != 0 && timeout > 0 {
196 timeout -= 1;
197 }
198
199 rtc.tar().write(|w| unsafe { w.bits(seconds) });
200
201 let mut timeout = 10000;
202 while rtc.tar().read().bits() != seconds && timeout > 0 {
203 timeout -= 1;
204 }
205 }
206
207 pub fn get_alarm(&self) -> RtcDateTime {
208 let rtc = unsafe { &*I::ptr() };
209 let alarm_seconds = rtc.tar().read().bits();
210 convert_seconds_to_datetime(alarm_seconds)
211 }
212
213 pub fn start(&self) {
214 let rtc = unsafe { &*I::ptr() };
215 rtc.sr().modify(|_, w| w.tce().set_bit());
216 }
217
218 pub fn stop(&self) {
219 let rtc = unsafe { &*I::ptr() };
220 rtc.sr().modify(|_, w| w.tce().clear_bit());
221 }
222
223 pub fn set_interrupt(&self, mask: u32) {
224 let rtc = unsafe { &*I::ptr() };
225
226 if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 {
227 rtc.ier().modify(|_, w| w.tiie().tiie_1());
228 }
229 if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 {
230 rtc.ier().modify(|_, w| w.toie().toie_1());
231 }
232 if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 {
233 rtc.ier().modify(|_, w| w.taie().taie_1());
234 }
235 if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 {
236 rtc.ier().modify(|_, w| w.tsie().tsie_1());
237 }
238
239 ALARM_TRIGGERED.store(false, Ordering::SeqCst);
240 }
241
242 pub fn disable_interrupt(&self, mask: u32) {
243 let rtc = unsafe { &*I::ptr() };
244
245 if (RtcInterruptEnable::RTC_TIME_INVALID_INTERRUPT_ENABLE & mask) != 0 {
246 rtc.ier().modify(|_, w| w.tiie().tiie_0());
247 }
248 if (RtcInterruptEnable::RTC_TIME_OVERFLOW_INTERRUPT_ENABLE & mask) != 0 {
249 rtc.ier().modify(|_, w| w.toie().toie_0());
250 }
251 if (RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE & mask) != 0 {
252 rtc.ier().modify(|_, w| w.taie().taie_0());
253 }
254 if (RtcInterruptEnable::RTC_SECONDS_INTERRUPT_ENABLE & mask) != 0 {
255 rtc.ier().modify(|_, w| w.tsie().tsie_0());
256 }
257 }
258
259 pub fn clear_alarm_flag(&self) {
260 let rtc = unsafe { &*I::ptr() };
261 rtc.ier().modify(|_, w| w.taie().clear_bit());
262 }
263
264 pub fn is_alarm_triggered(&self) -> bool {
265 ALARM_TRIGGERED.load(Ordering::Relaxed)
266 }
267}
268
269pub fn on_interrupt() {
270 let rtc = unsafe { &*pac::Rtc0::ptr() };
271 // Check if this is actually a time alarm interrupt
272 let sr = rtc.sr().read();
273 if sr.taf().bit_is_set() {
274 rtc.ier().modify(|_, w| w.taie().clear_bit());
275 ALARM_TRIGGERED.store(true, Ordering::SeqCst);
276 }
277}
278
279pub struct RtcHandler;
280impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::RTC> for RtcHandler {
281 unsafe fn on_interrupt() {
282 on_interrupt();
283 }
284}