Skip to main content

ws63_hal/
rtc.rs

1//! Real-Time Clock (RTC) driver for WS63.
2//!
3//! The WS63 RTC is a 48-bit free-running counter that can operate in
4//! free-running or periodic mode. It can generate interrupts when the
5//! counter matches a programmed load value.
6//!
7//! # Clock source
8//!
9//! The RTC runs from a 32.768 kHz clock.
10
11use crate::peripherals::Rtc;
12
13/// RTC operating mode.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum RtcMode {
16    /// Free-running mode: counter runs continuously.
17    FreeRunning,
18    /// Periodic mode: counter resets when it reaches the load value.
19    Periodic,
20}
21
22/// Real-Time Clock driver.
23pub struct RtcDriver<'d> {
24    _rtc: Rtc<'d>,
25}
26
27/// RTC clock frequency (32.768 kHz).
28pub const RTC_CLOCK_HZ: u32 = 32_768;
29
30impl<'d> RtcDriver<'d> {
31    /// Create a new RTC driver from the RTC peripheral.
32    pub fn new(rtc: Rtc<'d>) -> Self {
33        Self { _rtc: rtc }
34    }
35
36    fn regs(&self) -> &'static ws63_pac::rtc::RegisterBlock {
37        // SAFETY: PAC peripheral pointer is a static physical MMIO address, always valid
38        unsafe { &*Rtc::ptr() }
39    }
40
41    /// Configure the RTC.
42    ///
43    /// # Arguments
44    ///
45    /// * `mode` - Operating mode (free-running or periodic).
46    /// * `load_value` - In periodic mode, the counter resets when reaching this value.
47    pub fn configure(&mut self, mode: RtcMode, load_value: u32) {
48        unsafe {
49            self.regs().rtc_load_count().write(|w| w.bits(load_value));
50        }
51
52        let mut ctrl: u32 = 0;
53        ctrl |= 0x01; // enable
54        if matches!(mode, RtcMode::Periodic) {
55            ctrl |= 1 << 1; // mode = periodic
56        }
57        ctrl |= 1 << 2; // int_mask = masked initially
58
59        unsafe {
60            self.regs().rtc_control().write(|w| w.bits(ctrl));
61        }
62    }
63
64    /// Enable the RTC counter.
65    pub fn enable(&mut self) {
66        let ctrl = self.regs().rtc_control().read().bits();
67        unsafe {
68            self.regs().rtc_control().write(|w| w.bits(ctrl | 0x01));
69        }
70    }
71
72    /// Disable the RTC counter.
73    pub fn disable(&mut self) {
74        let ctrl = self.regs().rtc_control().read().bits();
75        unsafe {
76            self.regs().rtc_control().write(|w| w.bits(ctrl & !0x01));
77        }
78    }
79
80    /// Set the load (alarm) value.
81    pub fn set_load(&mut self, load_value: u32) {
82        unsafe {
83            self.regs().rtc_load_count().write(|w| w.bits(load_value));
84        }
85    }
86
87    /// Read the current counter value (lower 32 bits of the 48-bit counter).
88    pub fn current_value(&self) -> u32 {
89        self.regs().rtc_current_value().read().bits()
90    }
91
92    /// Enable RTC interrupt (unmask).
93    pub fn enable_interrupt(&mut self) {
94        let ctrl = self.regs().rtc_control().read().bits();
95        unsafe {
96            self.regs().rtc_control().write(|w| w.bits(ctrl & !(1 << 2)));
97        }
98    }
99
100    /// Disable RTC interrupt (mask).
101    pub fn disable_interrupt(&mut self) {
102        let ctrl = self.regs().rtc_control().read().bits();
103        unsafe {
104            self.regs().rtc_control().write(|w| w.bits(ctrl | (1 << 2)));
105        }
106    }
107
108    /// Check if an RTC interrupt is pending.
109    pub fn interrupt_pending(&self) -> bool {
110        self.regs().rtc_int_status().read().bits() & 0x01 != 0
111    }
112
113    /// Clear the RTC interrupt.
114    pub fn clear_interrupt(&self) {
115        let _ = self.regs().rtc_eoi().read().bits();
116    }
117}