Skip to content

Commit 1f799bd

Browse files
authored
Merge pull request #377 from apeng2012/rtcclk
RTC clock source can be selected
2 parents e790b27 + 761b66b commit 1f799bd

File tree

5 files changed

+110
-8
lines changed

5 files changed

+110
-8
lines changed

CHANGELOG.md

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

1818
### Added
1919

20+
- RTC clock source can be selected.
2021
- `rcc::Config` with prescalers for direct setting of clocks without calculating
2122
- `From<Bps>` for `serial::Config`
2223
- `From<Into<Hertz>>` for `i2c::Mode`

examples/blinky_rtc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn main() -> ! {
3232
// Enable writes to the backup domain
3333
let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut pwr);
3434
// Start the RTC
35-
let mut rtc = Rtc::rtc(dp.RTC, &mut backup_domain);
35+
let mut rtc = Rtc::new(dp.RTC, &mut backup_domain);
3636

3737
let mut led_on = false;
3838
loop {

examples/blinky_rtcalarm_irq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ fn main() -> ! {
9696
// Enable writes to the backup domain
9797
let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut pwr);
9898
// Start the RTC
99-
let mut rtc = Rtc::rtc(dp.RTC, &mut backup_domain);
99+
let mut rtc = Rtc::new(dp.RTC, &mut backup_domain);
100100
rtc.set_time(0);
101101
rtc.set_alarm(TOGGLE_INTERVAL_SECONDS);
102102
rtc.listen_alarm();

examples/rtc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn main() -> ! {
1919
let rcc = p.RCC.constrain();
2020
let mut backup_domain = rcc.bkp.constrain(p.BKP, &mut pwr);
2121

22-
let rtc = Rtc::rtc(p.RTC, &mut backup_domain);
22+
let rtc = Rtc::new(p.RTC, &mut backup_domain);
2323

2424
loop {
2525
hprintln!("time: {}", rtc.current_time()).unwrap();

src/rtc.rs

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,18 @@ use crate::backup_domain::BackupDomain;
77
use crate::time::Hertz;
88

99
use core::convert::Infallible;
10+
use core::marker::PhantomData;
1011

1112
// The LSE runs at at 32 768 hertz unless an external clock is provided
1213
const LSE_HERTZ: u32 = 32_768;
14+
const LSI_HERTZ: u32 = 40_000;
15+
16+
/// RTC clock source HSE clock divided by 128 (type state)
17+
pub struct RtcClkHseDiv128;
18+
/// RTC clock source LSE oscillator clock (type state)
19+
pub struct RtcClkLse;
20+
/// RTC clock source LSI oscillator clock (type state)
21+
pub struct RtcClkLsi;
1322

1423
/**
1524
Real time clock
@@ -28,11 +37,12 @@ const LSE_HERTZ: u32 = 32_768;
2837
[examples/blinky_rtc.rs]: https://github.com/stm32-rs/stm32f1xx-hal/blob/v0.7.0/examples/blinky_rtc.rs
2938
*/
3039

31-
pub struct Rtc {
40+
pub struct Rtc<CS = RtcClkLse> {
3241
regs: RTC,
42+
_clock_source: PhantomData<CS>,
3343
}
3444

35-
impl Rtc {
45+
impl Rtc<RtcClkLse> {
3646
/**
3747
Initialises the RTC. The `BackupDomain` struct is created by
3848
`Rcc.bkp.constrain()`.
@@ -43,10 +53,13 @@ impl Rtc {
4353
power cycles where (VBAT) still has power. Use [set_time](#method.set_time) if you want to
4454
reset the counter.
4555
*/
46-
pub fn rtc(regs: RTC, bkp: &mut BackupDomain) -> Self {
47-
let mut result = Rtc { regs };
56+
pub fn new(regs: RTC, bkp: &mut BackupDomain) -> Self {
57+
let mut result = Rtc {
58+
regs,
59+
_clock_source: PhantomData,
60+
};
4861

49-
Rtc::enable_rtc(bkp);
62+
Self::enable_rtc(bkp);
5063

5164
// Set the prescaler to make it count up once every second.
5265
let prl = LSE_HERTZ - 1;
@@ -77,7 +90,95 @@ impl Rtc {
7790
.lse()
7891
})
7992
}
93+
}
94+
95+
impl Rtc<RtcClkLsi> {
96+
pub fn rtc(regs: RTC, bkp: &mut BackupDomain) -> Self {
97+
let mut result = Rtc {
98+
regs,
99+
_clock_source: PhantomData,
100+
};
101+
102+
Self::enable_rtc(bkp);
103+
104+
// Set the prescaler to make it count up once every second.
105+
let prl = LSI_HERTZ - 1;
106+
assert!(prl < 1 << 20);
107+
result.perform_write(|s| {
108+
s.regs.prlh.write(|w| unsafe { w.bits(prl >> 16) });
109+
s.regs.prll.write(|w| unsafe { w.bits(prl as u16 as u32) });
110+
});
111+
112+
result
113+
}
114+
115+
/// Enables the RTC device with the lsi as the clock
116+
fn enable_rtc(_bkp: &mut BackupDomain) {
117+
// NOTE: Safe RCC access because we are only accessing bdcr
118+
// and we have a &mut on BackupDomain
119+
let rcc = unsafe { &*RCC::ptr() };
120+
rcc.csr.modify(|_, w| {
121+
w
122+
// start the LSI oscillator
123+
.lsion()
124+
.set_bit()
125+
});
126+
rcc.bdcr.modify(|_, w| {
127+
w
128+
// Enable the RTC
129+
.rtcen()
130+
.set_bit()
131+
// Set the source of the RTC to LSI
132+
.rtcsel()
133+
.lsi()
134+
})
135+
}
136+
}
137+
138+
impl Rtc<RtcClkHseDiv128> {
139+
pub fn rtc<F>(regs: RTC, bkp: &mut BackupDomain, hse: F) -> Self
140+
where
141+
F: Into<Hertz>,
142+
{
143+
let mut result = Rtc {
144+
regs,
145+
_clock_source: PhantomData,
146+
};
147+
148+
Self::enable_rtc(bkp);
149+
150+
// Set the prescaler to make it count up once every second.
151+
let prl = hse.into().0 / 128 - 1;
152+
assert!(prl < 1 << 20);
153+
result.perform_write(|s| {
154+
s.regs.prlh.write(|w| unsafe { w.bits(prl >> 16) });
155+
s.regs.prll.write(|w| unsafe { w.bits(prl as u16 as u32) });
156+
});
157+
158+
result
159+
}
160+
161+
/// Enables the RTC device with the lsi as the clock
162+
fn enable_rtc(_bkp: &mut BackupDomain) {
163+
// NOTE: Safe RCC access because we are only accessing bdcr
164+
// and we have a &mut on BackupDomain
165+
let rcc = unsafe { &*RCC::ptr() };
166+
if rcc.cr.read().hserdy().bit_is_clear() {
167+
panic!("HSE oscillator not ready");
168+
}
169+
rcc.bdcr.modify(|_, w| {
170+
w
171+
// Enable the RTC
172+
.rtcen()
173+
.set_bit()
174+
// Set the source of the RTC to HSE/128
175+
.rtcsel()
176+
.hse()
177+
})
178+
}
179+
}
80180

181+
impl<CS> Rtc<CS> {
81182
/// Selects the frequency of the RTC Timer
82183
/// NOTE: Maximum frequency of 16384 Hz using the internal LSE
83184
pub fn select_frequency(&mut self, timeout: impl Into<Hertz>) {

0 commit comments

Comments
 (0)