Skip to content

Stm32l412/Stm32l422 PAC specialisation #264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Dec 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ stm32l431 = [ "stm32l4/stm32l4x1" ]
stm32l451 = [ "stm32l4/stm32l4x1" ]
stm32l471 = [ "stm32l4/stm32l4x1" ]

# L412
stm32l412 = [ "stm32l4/stm32l412" ]
stm32l422 = [ "stm32l4/stm32l412" ]

# L4x2
stm32l412 = [ "stm32l4/stm32l4x2" ]
stm32l422 = [ "stm32l4/stm32l4x2" ]
stm32l432 = [ "stm32l4/stm32l4x2" ]
stm32l442 = [ "stm32l4/stm32l4x2" ]
stm32l452 = [ "stm32l4/stm32l4x2" ]
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ pub use stm32l4;
#[cfg(any(feature = "stm32l431", feature = "stm32l451", feature = "stm32l471"))]
pub use stm32l4::stm32l4x1 as pac;

#[cfg(any(feature = "stm32l412", feature = "stm32l422"))]
pub use stm32l4::stm32l412 as pac;
#[cfg(any(
feature = "stm32l412",
feature = "stm32l422",
feature = "stm32l432",
feature = "stm32l442",
feature = "stm32l452",
Expand Down
109 changes: 71 additions & 38 deletions src/rtc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
//! RTC peripheral abstraction

/// refer to AN4759 to compare features of RTC2 and RTC3
#[cfg(not(any(
feature = "stm32l412",
feature = "stm32l422",
feature = "stm32l4p5",
feature = "stm32l4q5"
)))]
pub mod rtc2;
#[cfg(not(any(
feature = "stm32l412",
feature = "stm32l422",
feature = "stm32l4p5",
feature = "stm32l4q5"
)))]
pub use rtc2 as rtc_registers;

/// refer to AN4759 to compare features of RTC2 and RTC3
#[cfg(any(
feature = "stm32l412",
feature = "stm32l422",
feature = "stm32l4p5",
feature = "stm32l4q5"
))]
pub mod rtc3;
#[cfg(any(
feature = "stm32l412",
feature = "stm32l422",
feature = "stm32l4p5",
feature = "stm32l4q5"
))]
pub use rtc3 as rtc_registers;

use void::Void;

use crate::{
Expand Down Expand Up @@ -214,10 +246,9 @@ impl Rtc {

self.write(false, |rtc| match alarm {
Alarm::AlarmA => {
rtc.cr.modify(|_, w| w.alrae().clear_bit());

// Wait until we're allowed to update the alarm b configuration
while rtc.isr.read().alrawf().bit_is_clear() {}
rtc.cr.modify(|_, w| w.alrae().clear_bit()); // Disable Alarm A
rtc_registers::clear_alarm_a_flag(rtc);
while !rtc_registers::is_alarm_a_accessible(rtc) {}

rtc.alrmar.modify(|_, w| unsafe {
w.dt()
Expand All @@ -241,13 +272,19 @@ impl Rtc {
.wdsel()
.clear_bit()
});
// binary mode alarm not implemented (RTC3 only)
// subsecond alarm not implemented
// would need a conversion method between `time.micros` and RTC ticks
// write the SS value and mask to `rtc.alrmassr`

// enable alarm and reenable interrupt if it was enabled
rtc.cr.modify(|_, w| w.alrae().set_bit());
}
Alarm::AlarmB => {
rtc.cr.modify(|_, w| w.alrbe().clear_bit());

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

rtc.alrmbr.modify(|_, w| unsafe {
w.dt()
Expand All @@ -271,10 +308,15 @@ impl Rtc {
.wdsel()
.clear_bit()
});
// binary mode alarm not implemented (RTC3 only)
// subsecond alarm not implemented
// would need a conversion method between `time.micros` and RTC ticks
// write the SS value and mask to `rtc.alrmbssr`

// enable alarm and reenable interrupt if it was enabled
rtc.cr.modify(|_, w| w.alrbe().set_bit());
}
});
self.check_interrupt(alarm.into(), true);
}

/// Starts listening for an interrupt event
Expand Down Expand Up @@ -334,27 +376,27 @@ impl Rtc {
/// Checks for an interrupt event
pub fn check_interrupt(&mut self, event: Event, clear: bool) -> bool {
let result = match event {
Event::WakeupTimer => self.rtc.isr.read().wutf().bit_is_set(),
Event::AlarmA => self.rtc.isr.read().alraf().bit_is_set(),
Event::AlarmB => self.rtc.isr.read().alrbf().bit_is_set(),
Event::Timestamp => self.rtc.isr.read().tsf().bit_is_set(),
Event::WakeupTimer => rtc_registers::is_wakeup_timer_flag_set(&self.rtc),
Event::AlarmA => rtc_registers::is_alarm_a_flag_set(&self.rtc),
Event::AlarmB => rtc_registers::is_alarm_b_flag_set(&self.rtc),
Event::Timestamp => rtc_registers::is_timestamp_flag_set(&self.rtc),
};
if clear {
self.write(false, |rtc| match event {
Event::WakeupTimer => {
rtc.isr.modify(|_, w| w.wutf().clear_bit());
rtc_registers::clear_wakeup_timer_flag(rtc);
unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 20)) };
}
Event::AlarmA => {
rtc.isr.modify(|_, w| w.alraf().clear_bit());
rtc_registers::clear_alarm_a_flag(rtc);
unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 18)) };
}
Event::AlarmB => {
rtc.isr.modify(|_, w| w.alrbf().clear_bit());
rtc_registers::clear_alarm_b_flag(rtc);
unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 18)) };
}
Event::Timestamp => {
rtc.isr.modify(|_, w| w.tsf().clear_bit());
rtc_registers::clear_timestamp_flag(rtc);
unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 19)) };
}
})
Expand Down Expand Up @@ -427,8 +469,7 @@ impl Rtc {
});

// TODO configuration for output pins
rtc.or
.modify(|_, w| w.rtc_alarm_type().clear_bit().rtc_out_rmp().clear_bit());
rtc_registers::reset_gpio(rtc);
});

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

if init_mode && self.rtc.isr.read().initf().bit_is_clear() {
// are we already in init mode?
self.rtc.isr.modify(|_, w| w.init().set_bit());
while self.rtc.isr.read().initf().bit_is_clear() {} // wait to return to init state
if init_mode && !rtc_registers::is_init_mode(&self.rtc) {
rtc_registers::enter_init_mode(&self.rtc);
// wait till init state entered
// ~2 RTCCLK cycles
while !rtc_registers::is_init_mode(&self.rtc) {}
}

let result = f(&self.rtc);

if init_mode {
self.rtc.isr.modify(|_, w| w.init().clear_bit()); // Exits init mode
rtc_registers::exit_init_mode(&self.rtc);
}

// Re-enable write protection.
Expand All @@ -467,26 +508,22 @@ impl Rtc {
result
}

pub const BACKUP_REGISTER_COUNT: usize = rtc_registers::BACKUP_REGISTER_COUNT;

/// Read content of the backup register.
///
/// The registers retain their values during wakes from standby mode or system resets. They also
/// retain their value when Vdd is switched off as long as V_BAT is powered.
pub fn read_backup_register(&self, register: usize) -> Option<u32> {
if register < 32 {
Some(self.rtc.bkpr[register].read().bits())
} else {
None
}
rtc_registers::read_backup_register(&self.rtc, register)
}

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

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

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

fn wait(&mut self) -> nb::Result<(), Void> {
Expand All @@ -591,12 +628,8 @@ impl timer::Cancel for WakeupTimer<'_> {
self.rtc.write(false, |rtc| {
// Disable the wakeup timer
rtc.cr.modify(|_, w| w.wute().clear_bit());

// Wait until we're allowed to update the wakeup timer configuration
while rtc.isr.read().wutwf().bit_is_clear() {}

// Clear wakeup timer flag
rtc.isr.modify(|_, w| w.wutf().clear_bit());
while rtc_registers::is_wakeup_timer_write_flag_set(&rtc) {}
rtc_registers::clear_wakeup_timer_flag(rtc);

// According to the reference manual, section 26.7.4, the WUTF flag
// must be cleared at least 1.5 RTCCLK periods "before WUTF is set
Expand Down
117 changes: 117 additions & 0 deletions src/rtc/rtc2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use crate::pac::RTC;

pub fn reset_gpio(rtc: &RTC) {
rtc.or
.modify(|_, w| w.rtc_alarm_type().clear_bit().rtc_out_rmp().clear_bit());
}

/// true if initf bit indicates RTC peripheral is in init mode
pub fn is_init_mode(rtc: &RTC) -> bool {
rtc.isr.read().initf().bit_is_set()
}

/// to update calendar date/time, time format, and prescaler configuration, RTC must be in init mode
pub fn enter_init_mode(rtc: &RTC) {
rtc.isr.modify(|_, w| w.init().set_bit());
}

/// counting will restart in 4 RTCCLK cycles
pub fn exit_init_mode(rtc: &RTC) {
rtc.isr.modify(|_, w| w.init().clear_bit()); // Exits init mode
}

/// has wakeup timer expired?
pub fn is_wakeup_timer_flag_set(rtc: &RTC) -> bool {
rtc.isr.read().wutf().bit_is_set()
}

pub fn is_wakeup_timer_write_flag_set(rtc: &RTC) -> bool {
rtc.isr.read().wutwf().bit_is_set()
}

/// clear the wakeup timer flag
pub fn clear_wakeup_timer_flag(rtc: &RTC) {
rtc.isr.modify(|_, w| w.wutf().clear_bit());
}

/// has alarm A been triggered
pub fn is_alarm_a_flag_set(rtc: &RTC) -> bool {
rtc.isr.read().alraf().bit_is_set()
}

/// clear the alarm A flag
pub fn clear_alarm_a_flag(rtc: &RTC) {
rtc.isr.modify(|_, w| w.alraf().clear_bit());
}

/// has alarm B been triggered?
pub fn is_alarm_b_flag_set(rtc: &RTC) -> bool {
rtc.isr.read().alrbf().bit_is_set()
}

/// clear the alarm B flag
pub fn clear_alarm_b_flag(rtc: &RTC) {
rtc.isr.modify(|_, w| w.alrbf().clear_bit());
}

/// has timestamp event triggered
pub fn is_timestamp_flag_set(rtc: &RTC) -> bool {
rtc.isr.read().tsf().bit_is_set()
}

/// clear the timestamp event flag
pub fn clear_timestamp_flag(rtc: &RTC) {
rtc.isr.modify(|_, w| w.tsf().clear_bit());
}

pub fn is_alarm_a_accessible(rtc: &RTC) -> bool {
rtc.isr.read().alrawf().bit_is_clear()
}

pub fn is_alarm_b_accessible(rtc: &RTC) -> bool {
rtc.isr.read().alrbwf().bit_is_clear()
}

// AN7459
// L4 series except L41/2 has 20 backup registers
// L41/2, L4P/Q and L4R/S have 32 backup registers
#[cfg(not(any(
feature = "stm32l4r5",
feature = "stm32l4s5",
feature = "stm32l4r7",
feature = "stm32l4s7",
feature = "stm32l4r9",
feature = "stm32l4s9"
)))]
pub const BACKUP_REGISTER_COUNT: usize = 20;
#[cfg(any(
feature = "stm32l4r5",
feature = "stm32l4s5",
feature = "stm32l4r7",
feature = "stm32l4s7",
feature = "stm32l4r9",
feature = "stm32l4s9"
))]
pub const BACKUP_REGISTER_COUNT: usize = 32;

/// Read content of the backup register.
///
/// The registers retain their values during wakes from standby mode or system resets. They also
/// retain their value when Vdd is switched off as long as V_BAT is powered.
pub fn read_backup_register(rtc: &RTC, register: usize) -> Option<u32> {
if register < BACKUP_REGISTER_COUNT {
Some(rtc.bkpr[register].read().bits())
} else {
None
}
}

/// Set content of the backup register.
///
/// The registers retain their values during wakes from standby mode or system resets. They also
/// retain their value when Vdd is switched off as long as V_BAT is powered.
pub fn write_backup_register(rtc: &RTC, register: usize, value: u32) {
if register < BACKUP_REGISTER_COUNT {
unsafe { rtc.bkpr[register].write(|w| w.bits(value)) }
}
}
Loading