Skip to content

Commit 05c875b

Browse files
bors[bot]burrbull
andauthored
Merge #438
438: Add LSI support for Rtc r=therealprof a=burrbull Co-authored-by: Andrey Zgarbul <[email protected]>
2 parents 9adda35 + 22293de commit 05c875b

File tree

2 files changed

+86
-14
lines changed

2 files changed

+86
-14
lines changed

CHANGELOG.md

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

1010
### Changed
1111

12+
- Add LSI support for `Rtc` [#438]
1213
- Use `time` for `Rtc` instead of `rtcc`, add `rtc` example [#436]
1314
- Move `i2c` `embedded-hal` trait impls to `I2c` methods [#431]
1415
- Reexport pins in `gpio` module
@@ -42,6 +43,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
4243
[#432]: https://github.com/stm32-rs/stm32f4xx-hal/pull/432
4344
[#434]: https://github.com/stm32-rs/stm32f4xx-hal/pull/434
4445
[#436]: https://github.com/stm32-rs/stm32f4xx-hal/pull/436
46+
[#438]: https://github.com/stm32-rs/stm32f4xx-hal/pull/438
4547

4648
### Changed
4749

src/rtc.rs

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::pac::{rcc::RegisterBlock, PWR, RCC, RTC};
88
use crate::rcc::Enable;
99
use core::convert::TryInto;
1010
use core::fmt;
11+
use core::marker::PhantomData;
1112
use time::{Date, PrimitiveDateTime, Time};
1213

1314
/// Invalid input error
@@ -17,12 +18,16 @@ pub enum Error {
1718
InvalidInputData,
1819
}
1920

20-
pub const LSE_BITS: u8 = 0b01;
21+
/// RTC clock source LSE oscillator clock (type state)
22+
pub struct Lse;
23+
/// RTC clock source LSI oscillator clock (type state)
24+
pub struct Lsi;
2125

2226
/// Real Time Clock peripheral
23-
pub struct Rtc {
27+
pub struct Rtc<CS = Lse> {
2428
/// RTC Peripheral register
2529
pub regs: RTC,
30+
_clock_source: PhantomData<CS>,
2631
}
2732

2833
#[cfg(feature = "defmt")]
@@ -49,27 +54,27 @@ pub enum LSEClockMode {
4954
Bypass,
5055
}
5156

52-
impl Rtc {
57+
impl Rtc<Lse> {
5358
/// Create and enable a new RTC with external crystal or ceramic resonator and default prescalers.
5459
pub fn new(regs: RTC, pwr: &mut PWR) -> Self {
55-
Self::with_source(regs, pwr, LSEClockMode::Oscillator, 255, 127)
60+
Self::with_config(regs, pwr, LSEClockMode::Oscillator, 255, 127)
5661
}
5762

5863
/// Create and enable a new RTC, and configure its clock source and prescalers.
5964
///
60-
/// From AN4759, Table 7, when using the LSE (The only clock source this module
61-
/// supports currently), set `prediv_s` to 255, and `prediv_a` to 127 to get a
62-
/// calendar clock of 1Hz.
63-
/// The `bypass` argument is `true` if you're using an external oscillator that
64-
/// doesn't connect to `OSC32_IN`, such as a MEMS resonator.
65-
pub fn with_source(
65+
/// From AN3371, Table 3, when using the LSE,
66+
/// set `prediv_s` to 255, and `prediv_a` to 127 to get a calendar clock of 1Hz.
67+
pub fn with_config(
6668
regs: RTC,
6769
pwr: &mut PWR,
6870
mode: LSEClockMode,
6971
prediv_s: u16,
7072
prediv_a: u8,
7173
) -> Self {
72-
let mut result = Self { regs };
74+
let mut result = Self {
75+
regs,
76+
_clock_source: PhantomData,
77+
};
7378

7479
// Steps:
7580
// Enable PWR and DBP
@@ -90,6 +95,8 @@ impl Rtc {
9095
if rcc.bdcr.read().lserdy().bit_is_clear() {
9196
result.enable_lse(rcc, mode);
9297
}
98+
// Set clock source to LSE.
99+
rcc.bdcr.modify(|_, w| w.rtcsel().lse());
93100
result.enable(rcc);
94101
}
95102

@@ -122,12 +129,75 @@ impl Rtc {
122129
LSEClockMode::Oscillator => bb::clear(&rcc.bdcr, 2),
123130
}
124131
while rcc.bdcr.read().lserdy().bit_is_clear() {}
125-
// Set clock source to LSE.
126-
// Set BDCR - Bit 8 (RTCSEL to value for LSE)
127-
bb::set(&rcc.bdcr, 8);
128132
}
129133
}
134+
}
135+
136+
impl Rtc<Lsi> {
137+
/// Create and enable a new RTC with internal crystal and default prescalers.
138+
pub fn new_lsi(regs: RTC, pwr: &mut PWR) -> Self {
139+
Self::lsi_with_config(regs, pwr, 249, 127)
140+
}
141+
142+
/// Create and enable a new RTC, and configure its clock source and prescalers.
143+
///
144+
/// From AN3371, Table 3, when using the LSI,
145+
/// set `prediv_s` to 249, and `prediv_a` to 127 to get a calendar clock of 1Hz.
146+
pub fn lsi_with_config(regs: RTC, pwr: &mut PWR, prediv_s: u16, prediv_a: u8) -> Self {
147+
let mut result = Self {
148+
regs,
149+
_clock_source: PhantomData,
150+
};
151+
152+
// Steps:
153+
// Enable PWR and DBP
154+
// Enable LSI (if needed)
155+
// Enable RTC Clock
156+
// Disable Write Protect
157+
// Enter Init
158+
// Configure 24 hour format
159+
// Set prescalers
160+
// Exit Init
161+
// Enable write protect
162+
163+
unsafe {
164+
let rcc = &(*RCC::ptr());
165+
// As per the sample code, unlock comes first. (Enable PWR and DBP)
166+
result.unlock(rcc, pwr);
167+
// If necessary, enable the LSE.
168+
if rcc.csr.read().lsirdy().bit_is_clear() {
169+
result.enable_lsi(rcc);
170+
}
171+
// Set clock source to LSI.
172+
rcc.bdcr.modify(|_, w| w.rtcsel().lsi());
173+
result.enable(rcc);
174+
}
175+
176+
result.modify(|regs| {
177+
// Set 24 Hour
178+
regs.cr.modify(|_, w| w.fmt().clear_bit());
179+
// Set prescalers
180+
regs.prer.modify(|_, w| {
181+
w.prediv_s().bits(prediv_s);
182+
w.prediv_a().bits(prediv_a)
183+
})
184+
});
185+
186+
result
187+
}
188+
189+
fn enable_lsi(&mut self, rcc: &RegisterBlock) {
190+
unsafe {
191+
// Force a reset of the backup domain.
192+
self.backup_reset(rcc);
193+
// Enable the LSI.
194+
rcc.csr.modify(|_, w| w.lsion().on());
195+
while rcc.csr.read().lsirdy().is_not_ready() {}
196+
}
197+
}
198+
}
130199

200+
impl<CS> Rtc<CS> {
131201
fn unlock(&mut self, rcc: &RegisterBlock, pwr: &mut PWR) {
132202
// Enable the backup interface
133203
// Set APB1 - Bit 28 (PWREN)

0 commit comments

Comments
 (0)