Skip to content

Commit 2dbb0dc

Browse files
committed
RTC: ClockSource enum instead of generic
1 parent fb847b9 commit 2dbb0dc

File tree

2 files changed

+44
-69
lines changed

2 files changed

+44
-69
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2222

2323
### Changed
2424

25+
- RTC: `ClockSource` enum instead of generic
2526
- Bump MSRV to 1.62
2627
- Use `stm32f4-staging` until `stm32f4` is released [#706]
2728
- use GPIO pac fields instead of raw write

src/rtc.rs

Lines changed: 43 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use crate::pac::rtc::{dr, tr};
77
use crate::pac::{self, rcc::RegisterBlock, PWR, RCC, RTC};
88
use crate::rcc::Enable;
99
use core::fmt;
10-
use core::marker::PhantomData;
1110
use fugit::RateExtU32;
1211
use time::{Date, PrimitiveDateTime, Time, Weekday};
1312

@@ -67,27 +66,33 @@ pub struct Lse;
6766
/// RTC clock source LSI oscillator clock (type state)
6867
pub struct Lsi;
6968

70-
pub trait FrequencySource {
71-
fn frequency() -> fugit::Hertz<u32>;
69+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
71+
pub enum ClockSource {
72+
Lse(LSEClockMode),
73+
Lsi,
7274
}
7375

74-
impl FrequencySource for Lse {
75-
fn frequency() -> fugit::Hertz<u32> {
76-
32_768u32.Hz()
76+
impl From<LSEClockMode> for ClockSource {
77+
fn from(value: LSEClockMode) -> Self {
78+
Self::Lse(value)
7779
}
7880
}
7981

80-
impl FrequencySource for Lsi {
81-
fn frequency() -> fugit::Hertz<u32> {
82-
32_000u32.Hz()
82+
impl ClockSource {
83+
pub fn frequency(self) -> fugit::Hertz<u32> {
84+
match self {
85+
Self::Lse(_) => 32_768_u32.Hz(),
86+
Self::Lsi => 32.kHz(),
87+
}
8388
}
8489
}
8590

8691
/// Real Time Clock peripheral
87-
pub struct Rtc<CS: FrequencySource = Lse> {
92+
pub struct Rtc {
8893
/// RTC Peripheral register
8994
pub regs: RTC,
90-
_clock_source: PhantomData<CS>,
95+
clock_source: ClockSource,
9196
}
9297

9398
#[cfg(feature = "defmt")]
@@ -114,31 +119,30 @@ pub enum LSEClockMode {
114119
Bypass,
115120
}
116121

117-
impl Rtc<Lse> {
122+
impl Rtc {
118123
/// Create and enable a new RTC with external crystal or ceramic resonator and default prescalers.
119124
pub fn new(regs: RTC, pwr: &mut PWR) -> Self {
120125
Self::with_config(regs, pwr, LSEClockMode::Oscillator, 255, 127)
121126
}
122-
123127
/// Create and enable a new RTC, and configure its clock source and prescalers.
124128
///
125-
/// From AN3371, Table 3, when using the LSE,
126-
/// set `prediv_s` to 255, and `prediv_a` to 127 to get a calendar clock of 1Hz.
129+
/// From AN3371, Table 3,
130+
/// set `prediv_s` to 255 (249 for LSI), and `prediv_a` to 127 to get a calendar clock of 1Hz.
127131
pub fn with_config(
128132
regs: RTC,
129133
pwr: &mut PWR,
130-
mode: LSEClockMode,
134+
clock_source: impl Into<ClockSource>,
131135
prediv_s: u16,
132136
prediv_a: u8,
133137
) -> Self {
134138
let mut result = Self {
135139
regs,
136-
_clock_source: PhantomData,
140+
clock_source: clock_source.into(),
137141
};
138142

139143
// Steps:
140144
// Enable PWR and DBP
141-
// Enable LSE (if needed)
145+
// Enable LSE/LSI (if needed)
142146
// Enable RTC Clock
143147
// Disable Write Protect
144148
// Enter Init
@@ -151,12 +155,24 @@ impl Rtc<Lse> {
151155
let rcc = &(*RCC::ptr());
152156
// As per the sample code, unlock comes first. (Enable PWR and DBP)
153157
result.unlock(rcc, pwr);
154-
// If necessary, enable the LSE.
155-
if rcc.bdcr().read().lserdy().bit_is_clear() {
156-
result.enable_lse(rcc, mode);
158+
match result.clock_source {
159+
ClockSource::Lse(mode) => {
160+
// If necessary, enable the LSE.
161+
if rcc.bdcr().read().lserdy().bit_is_clear() {
162+
result.enable_lse(rcc, mode);
163+
}
164+
// Set clock source to LSE.
165+
rcc.bdcr().modify(|_, w| w.rtcsel().lse());
166+
}
167+
ClockSource::Lsi => {
168+
// If necessary, enable the LSE.
169+
if rcc.csr().read().lsirdy().bit_is_clear() {
170+
result.enable_lsi(rcc);
171+
}
172+
// Set clock source to LSI.
173+
rcc.bdcr().modify(|_, w| w.rtcsel().lsi());
174+
}
157175
}
158-
// Set clock source to LSE.
159-
rcc.bdcr().modify(|_, w| w.rtcsel().lse());
160176
result.enable(rcc);
161177
}
162178

@@ -191,59 +207,18 @@ impl Rtc<Lse> {
191207
while rcc.bdcr().read().lserdy().bit_is_clear() {}
192208
}
193209
}
194-
}
195210

196-
impl Rtc<Lsi> {
197211
/// Create and enable a new RTC with internal crystal and default prescalers.
198212
pub fn new_lsi(regs: RTC, pwr: &mut PWR) -> Self {
199-
Self::lsi_with_config(regs, pwr, 249, 127)
213+
Self::with_config(regs, pwr, ClockSource::Lsi, 249, 127)
200214
}
201215

202216
/// Create and enable a new RTC, and configure its clock source and prescalers.
203217
///
204218
/// From AN3371, Table 3, when using the LSI,
205219
/// set `prediv_s` to 249, and `prediv_a` to 127 to get a calendar clock of 1Hz.
206220
pub fn lsi_with_config(regs: RTC, pwr: &mut PWR, prediv_s: u16, prediv_a: u8) -> Self {
207-
let mut result = Self {
208-
regs,
209-
_clock_source: PhantomData,
210-
};
211-
212-
// Steps:
213-
// Enable PWR and DBP
214-
// Enable LSI (if needed)
215-
// Enable RTC Clock
216-
// Disable Write Protect
217-
// Enter Init
218-
// Configure 24 hour format
219-
// Set prescalers
220-
// Exit Init
221-
// Enable write protect
222-
223-
unsafe {
224-
let rcc = &(*RCC::ptr());
225-
// As per the sample code, unlock comes first. (Enable PWR and DBP)
226-
result.unlock(rcc, pwr);
227-
// If necessary, enable the LSE.
228-
if rcc.csr().read().lsirdy().bit_is_clear() {
229-
result.enable_lsi(rcc);
230-
}
231-
// Set clock source to LSI.
232-
rcc.bdcr().modify(|_, w| w.rtcsel().lsi());
233-
result.enable(rcc);
234-
}
235-
236-
result.modify(true, |regs| {
237-
// Set 24 Hour
238-
regs.cr().modify(|_, w| w.fmt().clear_bit());
239-
// Set prescalers
240-
regs.prer().modify(|_, w| {
241-
w.prediv_s().set(prediv_s);
242-
w.prediv_a().set(prediv_a)
243-
})
244-
});
245-
246-
result
221+
Self::with_config(regs, pwr, ClockSource::Lsi, prediv_s, prediv_a)
247222
}
248223

249224
fn enable_lsi(&mut self, rcc: &RegisterBlock) {
@@ -253,9 +228,7 @@ impl Rtc<Lsi> {
253228
rcc.csr().modify(|_, w| w.lsion().on());
254229
while rcc.csr().read().lsirdy().is_not_ready() {}
255230
}
256-
}
257231

258-
impl<CS: FrequencySource> Rtc<CS> {
259232
fn unlock(&mut self, rcc: &RegisterBlock, pwr: &mut PWR) {
260233
// Enable the backup interface
261234
// Set APB1 - Bit 28 (PWREN)
@@ -543,6 +516,7 @@ impl<CS: FrequencySource> Rtc<CS> {
543516
///
544517
/// Panics if interval is greater than 2¹⁷-1 seconds.
545518
pub fn enable_wakeup(&mut self, interval: fugit::MicrosDurationU64) {
519+
let clock_source = self.clock_source;
546520
self.modify(false, |regs| {
547521
regs.cr().modify(|_, w| w.wute().clear_bit());
548522
regs.isr().modify(|_, w| w.wutf().clear_bit());
@@ -551,7 +525,7 @@ impl<CS: FrequencySource> Rtc<CS> {
551525
use crate::pac::rtc::cr::WUCKSEL;
552526
if interval < fugit::MicrosDurationU64::secs(32) {
553527
// Use RTCCLK as the wakeup timer clock source
554-
let frequency: fugit::Hertz<u64> = (CS::frequency() / 2).into();
528+
let frequency: fugit::Hertz<u64> = (clock_source.frequency() / 2).into();
555529
let freq_duration: fugit::MicrosDurationU64 = frequency.into_duration();
556530
let ticks_per_interval = interval / freq_duration;
557531

0 commit comments

Comments
 (0)