Skip to content

Commit 0e66113

Browse files
authored
Stm32l412/Stm32l422 PAC specialisation (#264)
* L412/L422 has a specialised PAC use correct PAC for stm32l412 * RTC set alarm conditionals for L41/L42 update feature gates * get and clear RTC interrupt state for L41/L42 * RTC::set_config - clear output state for L41/L42 * INIT/INITF are in rtc.icsr not rtc.isr for L41/L42 * handle polling the RTC WUTWF bit for L41/L42 * fix all the places where self used inside RTC::write # Conflicts: # src/rtc.rs * remove interrupt state caching that is not required by RM, don't include L4P/L4Q anywhere yet * move all of the conditional code behind a set of traits # Conflicts: # src/rtc.rs * move rtc traits declaration location * update feature names * drop traits, add rtc2/rtc3 modules where the register access differs * backup registers atleast compiling. RTC3 PAC support??
1 parent 9a2d2bd commit 0e66113

File tree

5 files changed

+305
-42
lines changed

5 files changed

+305
-42
lines changed

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@ stm32l431 = [ "stm32l4/stm32l4x1" ]
6969
stm32l451 = [ "stm32l4/stm32l4x1" ]
7070
stm32l471 = [ "stm32l4/stm32l4x1" ]
7171

72+
# L412
73+
stm32l412 = [ "stm32l4/stm32l412" ]
74+
stm32l422 = [ "stm32l4/stm32l412" ]
75+
7276
# L4x2
73-
stm32l412 = [ "stm32l4/stm32l4x2" ]
74-
stm32l422 = [ "stm32l4/stm32l4x2" ]
7577
stm32l432 = [ "stm32l4/stm32l4x2" ]
7678
stm32l442 = [ "stm32l4/stm32l4x2" ]
7779
stm32l452 = [ "stm32l4/stm32l4x2" ]

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ pub use stm32l4;
8686
#[cfg(any(feature = "stm32l431", feature = "stm32l451", feature = "stm32l471"))]
8787
pub use stm32l4::stm32l4x1 as pac;
8888

89+
#[cfg(any(feature = "stm32l412", feature = "stm32l422"))]
90+
pub use stm32l4::stm32l412 as pac;
8991
#[cfg(any(
90-
feature = "stm32l412",
91-
feature = "stm32l422",
9292
feature = "stm32l432",
9393
feature = "stm32l442",
9494
feature = "stm32l452",

src/rtc.rs

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,37 @@
11
//! RTC peripheral abstraction
22
3+
/// refer to AN4759 to compare features of RTC2 and RTC3
4+
#[cfg(not(any(
5+
feature = "stm32l412",
6+
feature = "stm32l422",
7+
feature = "stm32l4p5",
8+
feature = "stm32l4q5"
9+
)))]
10+
pub mod rtc2;
11+
#[cfg(not(any(
12+
feature = "stm32l412",
13+
feature = "stm32l422",
14+
feature = "stm32l4p5",
15+
feature = "stm32l4q5"
16+
)))]
17+
pub use rtc2 as rtc_registers;
18+
19+
/// refer to AN4759 to compare features of RTC2 and RTC3
20+
#[cfg(any(
21+
feature = "stm32l412",
22+
feature = "stm32l422",
23+
feature = "stm32l4p5",
24+
feature = "stm32l4q5"
25+
))]
26+
pub mod rtc3;
27+
#[cfg(any(
28+
feature = "stm32l412",
29+
feature = "stm32l422",
30+
feature = "stm32l4p5",
31+
feature = "stm32l4q5"
32+
))]
33+
pub use rtc3 as rtc_registers;
34+
335
use void::Void;
436

537
use crate::{
@@ -214,10 +246,9 @@ impl Rtc {
214246

215247
self.write(false, |rtc| match alarm {
216248
Alarm::AlarmA => {
217-
rtc.cr.modify(|_, w| w.alrae().clear_bit());
218-
219-
// Wait until we're allowed to update the alarm b configuration
220-
while rtc.isr.read().alrawf().bit_is_clear() {}
249+
rtc.cr.modify(|_, w| w.alrae().clear_bit()); // Disable Alarm A
250+
rtc_registers::clear_alarm_a_flag(rtc);
251+
while !rtc_registers::is_alarm_a_accessible(rtc) {}
221252

222253
rtc.alrmar.modify(|_, w| unsafe {
223254
w.dt()
@@ -241,13 +272,19 @@ impl Rtc {
241272
.wdsel()
242273
.clear_bit()
243274
});
275+
// binary mode alarm not implemented (RTC3 only)
276+
// subsecond alarm not implemented
277+
// would need a conversion method between `time.micros` and RTC ticks
278+
// write the SS value and mask to `rtc.alrmassr`
279+
280+
// enable alarm and reenable interrupt if it was enabled
244281
rtc.cr.modify(|_, w| w.alrae().set_bit());
245282
}
246283
Alarm::AlarmB => {
247284
rtc.cr.modify(|_, w| w.alrbe().clear_bit());
248285

249-
// Wait until we're allowed to update the alarm b configuration
250-
while rtc.isr.read().alrbwf().bit_is_clear() {}
286+
rtc_registers::clear_alarm_b_flag(rtc);
287+
while !rtc_registers::is_alarm_b_accessible(rtc) {}
251288

252289
rtc.alrmbr.modify(|_, w| unsafe {
253290
w.dt()
@@ -271,10 +308,15 @@ impl Rtc {
271308
.wdsel()
272309
.clear_bit()
273310
});
311+
// binary mode alarm not implemented (RTC3 only)
312+
// subsecond alarm not implemented
313+
// would need a conversion method between `time.micros` and RTC ticks
314+
// write the SS value and mask to `rtc.alrmbssr`
315+
316+
// enable alarm and reenable interrupt if it was enabled
274317
rtc.cr.modify(|_, w| w.alrbe().set_bit());
275318
}
276319
});
277-
self.check_interrupt(alarm.into(), true);
278320
}
279321

280322
/// Starts listening for an interrupt event
@@ -334,27 +376,27 @@ impl Rtc {
334376
/// Checks for an interrupt event
335377
pub fn check_interrupt(&mut self, event: Event, clear: bool) -> bool {
336378
let result = match event {
337-
Event::WakeupTimer => self.rtc.isr.read().wutf().bit_is_set(),
338-
Event::AlarmA => self.rtc.isr.read().alraf().bit_is_set(),
339-
Event::AlarmB => self.rtc.isr.read().alrbf().bit_is_set(),
340-
Event::Timestamp => self.rtc.isr.read().tsf().bit_is_set(),
379+
Event::WakeupTimer => rtc_registers::is_wakeup_timer_flag_set(&self.rtc),
380+
Event::AlarmA => rtc_registers::is_alarm_a_flag_set(&self.rtc),
381+
Event::AlarmB => rtc_registers::is_alarm_b_flag_set(&self.rtc),
382+
Event::Timestamp => rtc_registers::is_timestamp_flag_set(&self.rtc),
341383
};
342384
if clear {
343385
self.write(false, |rtc| match event {
344386
Event::WakeupTimer => {
345-
rtc.isr.modify(|_, w| w.wutf().clear_bit());
387+
rtc_registers::clear_wakeup_timer_flag(rtc);
346388
unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 20)) };
347389
}
348390
Event::AlarmA => {
349-
rtc.isr.modify(|_, w| w.alraf().clear_bit());
391+
rtc_registers::clear_alarm_a_flag(rtc);
350392
unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 18)) };
351393
}
352394
Event::AlarmB => {
353-
rtc.isr.modify(|_, w| w.alrbf().clear_bit());
395+
rtc_registers::clear_alarm_b_flag(rtc);
354396
unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 18)) };
355397
}
356398
Event::Timestamp => {
357-
rtc.isr.modify(|_, w| w.tsf().clear_bit());
399+
rtc_registers::clear_timestamp_flag(rtc);
358400
unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 19)) };
359401
}
360402
})
@@ -427,8 +469,7 @@ impl Rtc {
427469
});
428470

429471
// TODO configuration for output pins
430-
rtc.or
431-
.modify(|_, w| w.rtc_alarm_type().clear_bit().rtc_out_rmp().clear_bit());
472+
rtc_registers::reset_gpio(rtc);
432473
});
433474

434475
self.rtc_config = rtc_config;
@@ -448,16 +489,16 @@ impl Rtc {
448489
self.rtc.wpr.write(|w| unsafe { w.key().bits(0xca) });
449490
self.rtc.wpr.write(|w| unsafe { w.key().bits(0x53) });
450491

451-
if init_mode && self.rtc.isr.read().initf().bit_is_clear() {
452-
// are we already in init mode?
453-
self.rtc.isr.modify(|_, w| w.init().set_bit());
454-
while self.rtc.isr.read().initf().bit_is_clear() {} // wait to return to init state
492+
if init_mode && !rtc_registers::is_init_mode(&self.rtc) {
493+
rtc_registers::enter_init_mode(&self.rtc);
494+
// wait till init state entered
495+
// ~2 RTCCLK cycles
496+
while !rtc_registers::is_init_mode(&self.rtc) {}
455497
}
456498

457499
let result = f(&self.rtc);
458-
459500
if init_mode {
460-
self.rtc.isr.modify(|_, w| w.init().clear_bit()); // Exits init mode
501+
rtc_registers::exit_init_mode(&self.rtc);
461502
}
462503

463504
// Re-enable write protection.
@@ -467,26 +508,22 @@ impl Rtc {
467508
result
468509
}
469510

511+
pub const BACKUP_REGISTER_COUNT: usize = rtc_registers::BACKUP_REGISTER_COUNT;
512+
470513
/// Read content of the backup register.
471514
///
472515
/// The registers retain their values during wakes from standby mode or system resets. They also
473516
/// retain their value when Vdd is switched off as long as V_BAT is powered.
474517
pub fn read_backup_register(&self, register: usize) -> Option<u32> {
475-
if register < 32 {
476-
Some(self.rtc.bkpr[register].read().bits())
477-
} else {
478-
None
479-
}
518+
rtc_registers::read_backup_register(&self.rtc, register)
480519
}
481520

482521
/// Set content of the backup register.
483522
///
484523
/// The registers retain their values during wakes from standby mode or system resets. They also
485524
/// retain their value when Vdd is switched off as long as V_BAT is powered.
486525
pub fn write_backup_register(&self, register: usize, value: u32) {
487-
if register < 32 {
488-
unsafe { self.rtc.bkpr[register].write(|w| w.bits(value)) }
489-
}
526+
rtc_registers::write_backup_register(&self.rtc, register, value)
490527
}
491528
}
492529

@@ -572,7 +609,7 @@ impl timer::CountDown for WakeupTimer<'_> {
572609

573610
// Let's wait for WUTWF to clear. Otherwise we might run into a race
574611
// condition, if the user calls this method again really quickly.
575-
while self.rtc.rtc.isr.read().wutwf().bit_is_set() {}
612+
while rtc_registers::is_wakeup_timer_write_flag_set(&self.rtc.rtc) {}
576613
}
577614

578615
fn wait(&mut self) -> nb::Result<(), Void> {
@@ -591,12 +628,8 @@ impl timer::Cancel for WakeupTimer<'_> {
591628
self.rtc.write(false, |rtc| {
592629
// Disable the wakeup timer
593630
rtc.cr.modify(|_, w| w.wute().clear_bit());
594-
595-
// Wait until we're allowed to update the wakeup timer configuration
596-
while rtc.isr.read().wutwf().bit_is_clear() {}
597-
598-
// Clear wakeup timer flag
599-
rtc.isr.modify(|_, w| w.wutf().clear_bit());
631+
while rtc_registers::is_wakeup_timer_write_flag_set(&rtc) {}
632+
rtc_registers::clear_wakeup_timer_flag(rtc);
600633

601634
// According to the reference manual, section 26.7.4, the WUTF flag
602635
// must be cleared at least 1.5 RTCCLK periods "before WUTF is set

src/rtc/rtc2.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use crate::pac::RTC;
2+
3+
pub fn reset_gpio(rtc: &RTC) {
4+
rtc.or
5+
.modify(|_, w| w.rtc_alarm_type().clear_bit().rtc_out_rmp().clear_bit());
6+
}
7+
8+
/// true if initf bit indicates RTC peripheral is in init mode
9+
pub fn is_init_mode(rtc: &RTC) -> bool {
10+
rtc.isr.read().initf().bit_is_set()
11+
}
12+
13+
/// to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode
14+
pub fn enter_init_mode(rtc: &RTC) {
15+
rtc.isr.modify(|_, w| w.init().set_bit());
16+
}
17+
18+
/// counting will restart in 4 RTCCLK cycles
19+
pub fn exit_init_mode(rtc: &RTC) {
20+
rtc.isr.modify(|_, w| w.init().clear_bit()); // Exits init mode
21+
}
22+
23+
/// has wakeup timer expired?
24+
pub fn is_wakeup_timer_flag_set(rtc: &RTC) -> bool {
25+
rtc.isr.read().wutf().bit_is_set()
26+
}
27+
28+
pub fn is_wakeup_timer_write_flag_set(rtc: &RTC) -> bool {
29+
rtc.isr.read().wutwf().bit_is_set()
30+
}
31+
32+
/// clear the wakeup timer flag
33+
pub fn clear_wakeup_timer_flag(rtc: &RTC) {
34+
rtc.isr.modify(|_, w| w.wutf().clear_bit());
35+
}
36+
37+
/// has alarm A been triggered
38+
pub fn is_alarm_a_flag_set(rtc: &RTC) -> bool {
39+
rtc.isr.read().alraf().bit_is_set()
40+
}
41+
42+
/// clear the alarm A flag
43+
pub fn clear_alarm_a_flag(rtc: &RTC) {
44+
rtc.isr.modify(|_, w| w.alraf().clear_bit());
45+
}
46+
47+
/// has alarm B been triggered?
48+
pub fn is_alarm_b_flag_set(rtc: &RTC) -> bool {
49+
rtc.isr.read().alrbf().bit_is_set()
50+
}
51+
52+
/// clear the alarm B flag
53+
pub fn clear_alarm_b_flag(rtc: &RTC) {
54+
rtc.isr.modify(|_, w| w.alrbf().clear_bit());
55+
}
56+
57+
/// has timestamp event triggered
58+
pub fn is_timestamp_flag_set(rtc: &RTC) -> bool {
59+
rtc.isr.read().tsf().bit_is_set()
60+
}
61+
62+
/// clear the timestamp event flag
63+
pub fn clear_timestamp_flag(rtc: &RTC) {
64+
rtc.isr.modify(|_, w| w.tsf().clear_bit());
65+
}
66+
67+
pub fn is_alarm_a_accessible(rtc: &RTC) -> bool {
68+
rtc.isr.read().alrawf().bit_is_clear()
69+
}
70+
71+
pub fn is_alarm_b_accessible(rtc: &RTC) -> bool {
72+
rtc.isr.read().alrbwf().bit_is_clear()
73+
}
74+
75+
// AN7459
76+
// L4 series except L41/2 has 20 backup registers
77+
// L41/2, L4P/Q and L4R/S have 32 backup registers
78+
#[cfg(not(any(
79+
feature = "stm32l4r5",
80+
feature = "stm32l4s5",
81+
feature = "stm32l4r7",
82+
feature = "stm32l4s7",
83+
feature = "stm32l4r9",
84+
feature = "stm32l4s9"
85+
)))]
86+
pub const BACKUP_REGISTER_COUNT: usize = 20;
87+
#[cfg(any(
88+
feature = "stm32l4r5",
89+
feature = "stm32l4s5",
90+
feature = "stm32l4r7",
91+
feature = "stm32l4s7",
92+
feature = "stm32l4r9",
93+
feature = "stm32l4s9"
94+
))]
95+
pub const BACKUP_REGISTER_COUNT: usize = 32;
96+
97+
/// Read content of the backup register.
98+
///
99+
/// The registers retain their values during wakes from standby mode or system resets. They also
100+
/// retain their value when Vdd is switched off as long as V_BAT is powered.
101+
pub fn read_backup_register(rtc: &RTC, register: usize) -> Option<u32> {
102+
if register < BACKUP_REGISTER_COUNT {
103+
Some(rtc.bkpr[register].read().bits())
104+
} else {
105+
None
106+
}
107+
}
108+
109+
/// Set content of the backup register.
110+
///
111+
/// The registers retain their values during wakes from standby mode or system resets. They also
112+
/// retain their value when Vdd is switched off as long as V_BAT is powered.
113+
pub fn write_backup_register(rtc: &RTC, register: usize, value: u32) {
114+
if register < BACKUP_REGISTER_COUNT {
115+
unsafe { rtc.bkpr[register].write(|w| w.bits(value)) }
116+
}
117+
}

0 commit comments

Comments
 (0)