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