mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 14:22:33 +00:00
STM32: add support for LPTIM time driver
This commit is contained in:
parent
05d36233fc
commit
7fc279c026
@ -167,6 +167,10 @@ time-driver-tim22 = ["_time-driver"]
|
||||
time-driver-tim23 = ["_time-driver"]
|
||||
## Use TIM24 as time driver
|
||||
time-driver-tim24 = ["_time-driver"]
|
||||
## Use LPTIM1 as time driver
|
||||
time-driver-lptim1 = ["_time-driver"]
|
||||
## Use LPTIM2 as time driver
|
||||
time-driver-lptim2 = ["_time-driver"]
|
||||
|
||||
|
||||
#! ## Analog Switch Pins (Pxy_C) on STM32H7 series
|
||||
|
@ -214,6 +214,8 @@ fn main() {
|
||||
Some("tim22") => "TIM22",
|
||||
Some("tim23") => "TIM23",
|
||||
Some("tim24") => "TIM24",
|
||||
Some("lptim1") => "LPTIM1",
|
||||
Some("lptim2") => "LPTIM2",
|
||||
Some("any") => {
|
||||
// Order of TIM candidators:
|
||||
// 1. 2CH -> 2CH_CMP -> GP16 -> GP32 -> ADV
|
||||
@ -236,7 +238,7 @@ fn main() {
|
||||
}
|
||||
for tim in [
|
||||
"tim1", "tim2", "tim3", "tim4", "tim5", "tim8", "tim9", "tim12", "tim15", "tim20", "tim21", "tim22", "tim23",
|
||||
"tim24",
|
||||
"tim24", "lptim1", "lptim2",
|
||||
] {
|
||||
cfgs.declare(format!("time_driver_{}", tim));
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ pin_trait!(Channel2Pin, BasicInstance);
|
||||
|
||||
pub(crate) trait SealedInstance: RccPeripheral {
|
||||
fn regs() -> crate::pac::lptim::Lptim;
|
||||
type Interrupt: crate::interrupt::typelevel::Interrupt;
|
||||
}
|
||||
pub(crate) trait SealedBasicInstance: RccPeripheral {}
|
||||
|
||||
@ -34,6 +35,7 @@ foreach_interrupt! {
|
||||
fn regs() -> crate::pac::lptim::Lptim {
|
||||
crate::pac::$inst
|
||||
}
|
||||
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||
}
|
||||
impl SealedBasicInstance for crate::peripherals::$inst {
|
||||
}
|
||||
|
461
embassy-stm32/src/time_driver/lptim.rs
Normal file
461
embassy-stm32/src/time_driver/lptim.rs
Normal file
@ -0,0 +1,461 @@
|
||||
use core::mem;
|
||||
use core::sync::atomic::{AtomicU16, AtomicU32, AtomicU8, Ordering};
|
||||
|
||||
use critical_section::CriticalSection;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
use embassy_time::TICK_HZ;
|
||||
use embassy_time_driver::{AlarmHandle, Driver};
|
||||
use stm32_metapac::lptim::regs::IcrAdv;
|
||||
|
||||
use super::{AlarmState, ALARM_STATE_NEW};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::lptim::SealedInstance;
|
||||
use crate::rcc::{self, SealedRccPeripheral};
|
||||
use crate::{interrupt, peripherals};
|
||||
|
||||
#[cfg(time_driver_lptim1)]
|
||||
type T = peripherals::LPTIM1;
|
||||
#[cfg(time_driver_lptim2)]
|
||||
type T = peripherals::LPTIM1;
|
||||
|
||||
foreach_interrupt! {
|
||||
(LPTIM1, lptim, $block:ident, GLOBAL, $irq:ident) => {
|
||||
#[cfg(time_driver_lptim1)]
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn $irq() {
|
||||
DRIVER.on_interrupt()
|
||||
}
|
||||
};
|
||||
(LPTIM2, lptim, $block:ident, GLOBAL, $irq:ident) => {
|
||||
#[cfg(time_driver_lptim2)]
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn $irq() {
|
||||
DRIVER.on_interrupt()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn init(cs: CriticalSection) {
|
||||
DRIVER.init(cs)
|
||||
}
|
||||
|
||||
/*impl RtcDriver {
|
||||
#[cfg(time_driver_lptim1)]
|
||||
fn init(&'static self, cs: critical_section::CriticalSection) {
|
||||
let r = T::regs();
|
||||
|
||||
rcc::enable_and_reset_with_cs::<T>(cs);
|
||||
|
||||
<T as SealedInstance>::Interrupt::unpend();
|
||||
unsafe {
|
||||
<T as SealedInstance>::Interrupt::enable();
|
||||
};
|
||||
|
||||
let timer_freq = T::frequency();
|
||||
|
||||
// disable timer to write to CFGR register
|
||||
r.cr().modify(|w| w.set_enable(false));
|
||||
// set counter to 0
|
||||
r.cnt().write(|w| w.set_cnt(0));
|
||||
|
||||
// calculate the prescaler value
|
||||
let prescaler = if timer_freq.0 < TICK_HZ as u32 {
|
||||
panic!("lptim1 (= {}) is clocked too slow for desired TICK_HZ (= {})", timer_freq, TICK_HZ);
|
||||
} else if timer_freq.0 % TICK_HZ as u32 != 0 {
|
||||
panic!("frequency of lptim1 (= {}) must be a multiple of TICK_HZ (= {})", timer_freq, TICK_HZ);
|
||||
} else {
|
||||
use crate::pac::lptim::vals::Presc;
|
||||
match timer_freq.0 / TICK_HZ as u32 {
|
||||
1 => Presc::DIV1,
|
||||
2 => Presc::DIV2,
|
||||
4 => Presc::DIV4,
|
||||
8 => Presc::DIV8,
|
||||
16 => Presc::DIV16,
|
||||
32 => Presc::DIV32,
|
||||
64 => Presc::DIV64,
|
||||
128 => Presc::DIV128,
|
||||
_ => panic!("no valid prescaler value found for lptim1 (= {}) and TICK_HZ (= {})", timer_freq.0, TICK_HZ),
|
||||
}
|
||||
};
|
||||
// set the prescaler
|
||||
r.cfgr().write(|w| w.set_presc(prescaler));
|
||||
|
||||
debug!("timer_freq: {}", timer_freq);
|
||||
|
||||
|
||||
// TODO: check what the URS stuff is for
|
||||
|
||||
|
||||
|
||||
// enable timer to write do DIER
|
||||
r.cr().modify(|w| w.set_enable(true));
|
||||
for _ in 0..10 {
|
||||
|
||||
}
|
||||
info!("dier: {}", r.dier().read().0);
|
||||
info!("isr: {}", r.isr().read().0);
|
||||
r.arr().write(|w| w.set_arr(u16::MAX));
|
||||
while r.isr().read().arrok() == false {}
|
||||
// Mid-way point
|
||||
r.ccr(0).write(|w| w.set_ccr(0x8000));
|
||||
// unpend interrupts
|
||||
r.icr().write(|w| {
|
||||
w.set_uecf(true);
|
||||
w.set_cccf(0, true);
|
||||
w.set_dierokcf(true);
|
||||
});
|
||||
// Enable overflow and half-overflow interrupts
|
||||
r.dier().write(|w| {
|
||||
w.set_ueie(true);
|
||||
w.set_ccie(0, true);
|
||||
});
|
||||
while r.isr().read().dierok() == false {}
|
||||
|
||||
// start continuous mode
|
||||
r.cr().modify(|w| w.set_cntstrt(true));
|
||||
}
|
||||
|
||||
fn on_interrupt(&self) {
|
||||
let r = regs_gp16();
|
||||
|
||||
// XXX: reduce the size of this critical section ?
|
||||
critical_section::with(|cs| {
|
||||
#[cfg(not(time_driver_lptim1))]
|
||||
let sr = r.sr().read();
|
||||
#[cfg(time_driver_lptim1)]
|
||||
let isr = r.isr().read();
|
||||
|
||||
let dier = r.dier().read();
|
||||
|
||||
// Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT.
|
||||
// Other approaches such as writing all zeros, or RMWing won't work, they can
|
||||
// miss interrupts.
|
||||
#[cfg(not(time_driver_lptim1))]
|
||||
r.sr().write_value(regs::SrGp16(!sr.0));
|
||||
|
||||
#[cfg(time_driver_lptim1)]
|
||||
r.icr().write_value(IcrAdv(isr.0));
|
||||
|
||||
// Overflow
|
||||
#[cfg(not(time_driver_lptim1))]
|
||||
if sr.uif() {
|
||||
self.next_period();
|
||||
}
|
||||
#[cfg(time_driver_lptim1)]
|
||||
if isr.arrm() {
|
||||
self.next_period();
|
||||
}
|
||||
|
||||
// Half overflow
|
||||
if isr.ccif(0) {
|
||||
self.next_period();
|
||||
}
|
||||
|
||||
for n in 0..ALARM_COUNT {
|
||||
if isr.ccif(n + 1) && dier.ccie(n + 1) {
|
||||
self.trigger_alarm(n, cs);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}*/
|
||||
// TODO: let the user choose somehow
|
||||
const ALARM_COUNT: usize = 1;
|
||||
|
||||
/// The LptimTimeDriver depends on a 16bit hardware counter. The software counters are increased on overflow.
|
||||
/// The capture and compare channel is used for the alarms. It is not associated with any specific alarm, but
|
||||
/// all alarms are checked (only on capture and compare match).
|
||||
pub(crate) struct LptimTimeDriver {
|
||||
ticks_upper: AtomicU32,
|
||||
ticks_lower: AtomicU16,
|
||||
alarm_count: AtomicU8,
|
||||
alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>,
|
||||
}
|
||||
|
||||
embassy_time_driver::time_driver_impl!(static DRIVER: LptimTimeDriver = LptimTimeDriver {
|
||||
ticks_upper: AtomicU32::new(0),
|
||||
ticks_lower: AtomicU16::new(0),
|
||||
alarm_count: AtomicU8::new(0),
|
||||
alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]),
|
||||
});
|
||||
|
||||
fn calc_now(ticks_upper: u32, ticks_lower: u16, counter: u16) -> u64 {
|
||||
((ticks_upper as u64) << 32) + ((ticks_lower as u64) << 16) + (counter as u64)
|
||||
}
|
||||
|
||||
fn calc_ticks_from_timestamp(timestamp: u64) -> (u32, u16) {
|
||||
let ticks_upper = (timestamp >> 32) as u32;
|
||||
let ticks_lower = ((timestamp & 0x00000000_FFFF0000) >> 16) as u16;
|
||||
(ticks_upper, ticks_lower)
|
||||
}
|
||||
|
||||
fn calc_counter_from_timestamp(timestamp: u64) -> u16 {
|
||||
(timestamp & 0x00000000_0000FFFF) as u16
|
||||
}
|
||||
|
||||
impl LptimTimeDriver {
|
||||
pub(crate) fn init(&'static self, cs: critical_section::CriticalSection) {
|
||||
let r = T::regs();
|
||||
|
||||
rcc::enable_and_reset_with_cs::<T>(cs);
|
||||
|
||||
<T as SealedInstance>::Interrupt::unpend();
|
||||
unsafe {
|
||||
<T as SealedInstance>::Interrupt::enable();
|
||||
}
|
||||
|
||||
let timer_freq = T::frequency();
|
||||
|
||||
// disable timer to write to CFGR register
|
||||
r.cr().modify(|w| w.set_enable(false));
|
||||
// set counter to 0
|
||||
r.cnt().write(|w| w.set_cnt(0));
|
||||
|
||||
// calculate and set the prescaler value
|
||||
r.cfgr().write(|w| {
|
||||
w.set_presc(if timer_freq.0 < TICK_HZ as u32 {
|
||||
panic!(
|
||||
"lptim (= {}) is clocked too slow for desired TICK_HZ (= {})",
|
||||
timer_freq, TICK_HZ
|
||||
);
|
||||
} else if timer_freq.0 % TICK_HZ as u32 != 0 {
|
||||
panic!(
|
||||
"frequency of lptim1 (= {}) must be a multiple of TICK_HZ (= {})",
|
||||
timer_freq, TICK_HZ
|
||||
);
|
||||
} else {
|
||||
use crate::pac::lptim::vals::Presc;
|
||||
match timer_freq.0 / TICK_HZ as u32 {
|
||||
1 => Presc::DIV1,
|
||||
2 => Presc::DIV2,
|
||||
4 => Presc::DIV4,
|
||||
8 => Presc::DIV8,
|
||||
16 => Presc::DIV16,
|
||||
32 => Presc::DIV32,
|
||||
64 => Presc::DIV64,
|
||||
128 => Presc::DIV128,
|
||||
_ => panic!(
|
||||
"no valid prescaler value found for lptim1 (= {}) and TICK_HZ (= {})",
|
||||
timer_freq.0, TICK_HZ
|
||||
),
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// enable timer to write to DIER, CCR, ARR
|
||||
r.cr().modify(|w| w.set_enable(true));
|
||||
|
||||
// set ARR
|
||||
r.arr().write(|w| w.set_arr(u16::MAX));
|
||||
// check that write is finished
|
||||
while r.isr().read().arrok() == false {}
|
||||
|
||||
// unpend interrupts
|
||||
r.icr().write(|w| {
|
||||
w.set_arrmcf(true);
|
||||
});
|
||||
|
||||
// Enable overflow interrupt
|
||||
r.dier().write(|w| {
|
||||
w.set_arrmie(true);
|
||||
});
|
||||
// check that write is finished
|
||||
while r.isr().read().dierok() == false {}
|
||||
|
||||
// start continuous mode
|
||||
r.cr().modify(|w| w.set_cntstrt(true));
|
||||
}
|
||||
|
||||
fn on_interrupt(&self) {
|
||||
// TODO: check all the memory ordering
|
||||
let r = T::regs();
|
||||
|
||||
critical_section::with(|cs| {
|
||||
let isr = r.isr().read();
|
||||
|
||||
// Clear all interrupts. Bits in ISR are "write 1 to clear", so write ISR to ICR.
|
||||
// Other approaches such as writing all zeros, or RMWing won't work, they can
|
||||
// miss interrupts.
|
||||
r.icr().write_value(IcrAdv(isr.0));
|
||||
|
||||
let ticks_upper = self.ticks_upper.load(Ordering::Relaxed);
|
||||
let ticks_lower = self.ticks_lower.load(Ordering::Relaxed);
|
||||
|
||||
// Overflow
|
||||
let now = if isr.arrm() {
|
||||
let new_ticks_lower = ticks_lower.overflowing_add(1);
|
||||
|
||||
self.ticks_lower
|
||||
.compare_exchange(ticks_lower, new_ticks_lower.0, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.expect("No one else is writing them so it shouldn't fail to write them.");
|
||||
|
||||
// add 1 to ticks_upper if ticks_lower had an overflow
|
||||
let new_ticks_upper = if new_ticks_lower.1 {
|
||||
// add 1 to ticks_upper, ignoring an overflow since it is very far in the future
|
||||
let new_ticks_upper = ticks_upper.overflowing_add(1).0;
|
||||
|
||||
self.ticks_upper
|
||||
.compare_exchange(ticks_upper, new_ticks_upper, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.expect("No one else is writing these so it shouldn't fail to write them.");
|
||||
new_ticks_upper
|
||||
} else {
|
||||
// no overflow -> ticks_upper stays the same
|
||||
ticks_upper
|
||||
};
|
||||
|
||||
// check if next alarms is before the next counter overflow
|
||||
self.set_ccp_interrupt_for_next_alarm_if_before_overflow(cs, new_ticks_upper, new_ticks_lower.0);
|
||||
|
||||
calc_now(new_ticks_upper, new_ticks_lower.0, r.cnt().read().cnt())
|
||||
} else {
|
||||
calc_now(ticks_upper, ticks_lower, r.cnt().read().cnt())
|
||||
};
|
||||
|
||||
// check if an alarm is ready
|
||||
for n in 0..ALARM_COUNT {
|
||||
self.trigger_alarm_if_ready(now, n, cs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn set_ccp_interrupt_if_before_overflow(&self, alarm_timestamp: u64, ticks_upper: u32, ticks_lower: u16) {
|
||||
// skip u64::MAX immediately
|
||||
if alarm_timestamp == u64::MAX {
|
||||
return;
|
||||
}
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
let (alarm_ticks_upper, alarm_ticks_lower) = calc_ticks_from_timestamp(alarm_timestamp);
|
||||
if alarm_ticks_upper == ticks_upper && alarm_ticks_lower == ticks_lower {
|
||||
// alarm is before next counter overflow
|
||||
|
||||
// set capture compare value
|
||||
r.ccr(0)
|
||||
.modify(|m| m.set_ccr(calc_counter_from_timestamp(alarm_timestamp)));
|
||||
|
||||
// enable capture compare alarm
|
||||
r.dier().modify(|m| m.set_ccie(0, true));
|
||||
while r.isr().read().dierok() == false {}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ccp_interrupt_for_next_alarm_if_before_overflow(
|
||||
&self,
|
||||
cs: CriticalSection,
|
||||
ticks_upper: u32,
|
||||
ticks_lower: u16,
|
||||
) {
|
||||
let next_timestamp = self.next_alarm_timestamp(cs);
|
||||
self.set_ccp_interrupt_if_before_overflow(next_timestamp, ticks_upper, ticks_lower);
|
||||
}
|
||||
|
||||
fn trigger_alarm_if_ready(&self, now: u64, n: usize, cs: CriticalSection) {
|
||||
let alarm = &self.alarms.borrow(cs)[n];
|
||||
|
||||
if alarm.timestamp.get() <= now {
|
||||
alarm.timestamp.set(u64::MAX);
|
||||
}
|
||||
|
||||
// Call the callback after clearing the alarm, so the callback can set another alarm.
|
||||
|
||||
// safety:
|
||||
// - we can ignore the possibility of `f` being unset (null) because of the safety contract of `allocate_alarm`.
|
||||
// - other than that we only store valid function pointers into alarm.callback
|
||||
let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
|
||||
f(alarm.ctx.get());
|
||||
}
|
||||
|
||||
fn next_alarm_timestamp(&self, cs: CriticalSection) -> u64 {
|
||||
self.alarms.borrow(cs).iter().map(|a| a.timestamp.get()).min().unwrap()
|
||||
}
|
||||
|
||||
fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState {
|
||||
// safety: we're allowed to assume the AlarmState is created by us, and
|
||||
// we never create one that's out of bounds.
|
||||
unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Driver for LptimTimeDriver {
|
||||
fn now(&self) -> u64 {
|
||||
// TODO: check memory ordering
|
||||
|
||||
let r = T::regs();
|
||||
loop {
|
||||
let ticks_lower = self.ticks_lower.load(Ordering::Acquire);
|
||||
|
||||
let ticks_upper = self.ticks_upper.load(Ordering::Relaxed);
|
||||
|
||||
let ticks_lower_2 = self.ticks_lower.load(Ordering::Acquire);
|
||||
|
||||
if ticks_lower == ticks_lower_2 {
|
||||
return calc_now(ticks_upper, ticks_lower, r.cnt().read().cnt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
||||
critical_section::with(|_| {
|
||||
let id = self.alarm_count.load(Ordering::Relaxed);
|
||||
if id < ALARM_COUNT as u8 {
|
||||
self.alarm_count.store(id + 1, Ordering::Relaxed);
|
||||
Some(AlarmHandle::new(id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
||||
critical_section::with(|cs| {
|
||||
let alarm = self.get_alarm(cs, alarm);
|
||||
|
||||
alarm.callback.set(callback as *const ());
|
||||
alarm.ctx.set(ctx);
|
||||
})
|
||||
}
|
||||
|
||||
fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
|
||||
critical_section::with(|cs| {
|
||||
let r = T::regs();
|
||||
|
||||
let n = alarm.id() as usize;
|
||||
let alarm = self.get_alarm(cs, alarm);
|
||||
alarm.timestamp.set(timestamp);
|
||||
|
||||
let t = self.now();
|
||||
if timestamp <= t {
|
||||
// If alarm timestamp has passed the alarm will not fire.
|
||||
// Disarm the alarm and return `false` to indicate that.
|
||||
alarm.timestamp.set(u64::MAX);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// recompute the ccp interrupt
|
||||
let (ticks_upper, ticks_lower) = calc_ticks_from_timestamp(t);
|
||||
self.set_ccp_interrupt_for_next_alarm_if_before_overflow(cs, ticks_upper, ticks_lower);
|
||||
|
||||
// Reevaluate if the alarm timestamp is still in the future
|
||||
let t = self.now();
|
||||
if timestamp <= t {
|
||||
// If alarm timestamp has passed since we set it, we have a race condition and
|
||||
// the alarm may or may not have fired.
|
||||
// Disarm the alarm and return 'false' to indicate that.
|
||||
// It is the caller's responsibility to handle this ambiguity.
|
||||
r.dier().modify(|m| m.set_ccie(0, false));
|
||||
|
||||
alarm.timestamp.set(u64::MAX);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're confident the alarm will ring in the future
|
||||
true
|
||||
})
|
||||
}
|
||||
}
|
52
embassy-stm32/src/time_driver/mod.rs
Normal file
52
embassy-stm32/src/time_driver/mod.rs
Normal file
@ -0,0 +1,52 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use core::cell::Cell;
|
||||
use core::ptr;
|
||||
|
||||
#[cfg_attr(
|
||||
any(
|
||||
time_driver_tim1,
|
||||
time_driver_tim2,
|
||||
time_driver_tim3,
|
||||
time_driver_tim4,
|
||||
time_driver_tim5,
|
||||
time_driver_tim8,
|
||||
time_driver_tim9,
|
||||
time_driver_tim12,
|
||||
time_driver_tim15,
|
||||
time_driver_tim20,
|
||||
time_driver_tim21,
|
||||
time_driver_tim22,
|
||||
time_driver_tim23,
|
||||
time_driver_tim24
|
||||
),
|
||||
path = "tim.rs"
|
||||
)]
|
||||
#[cfg_attr(any(time_driver_lptim1, time_driver_lptim2), path = "lptim.rs")]
|
||||
mod _timer;
|
||||
#[allow(unused_imports)]
|
||||
pub use _timer::*;
|
||||
|
||||
struct AlarmState {
|
||||
timestamp: Cell<u64>,
|
||||
|
||||
// This is really a Option<(fn(*mut ()), *mut ())>
|
||||
// but fn pointers aren't allowed in const yet
|
||||
callback: Cell<*const ()>,
|
||||
ctx: Cell<*mut ()>,
|
||||
}
|
||||
|
||||
unsafe impl Send for AlarmState {}
|
||||
|
||||
impl AlarmState {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
timestamp: Cell::new(u64::MAX),
|
||||
callback: Cell::new(ptr::null()),
|
||||
ctx: Cell::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::declare_interior_mutable_const)]
|
||||
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
|
@ -1,22 +1,23 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
use core::cell::Cell;
|
||||
use core::mem;
|
||||
use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering};
|
||||
use core::{mem, ptr};
|
||||
|
||||
use critical_section::CriticalSection;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ};
|
||||
use embassy_time::TICK_HZ;
|
||||
use embassy_time_driver::{AlarmHandle, Driver};
|
||||
use stm32_metapac::timer::{regs, TimGp16};
|
||||
|
||||
use super::{AlarmState, ALARM_STATE_NEW};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::timer::vals;
|
||||
use crate::rcc::{self, SealedRccPeripheral};
|
||||
use crate::rcc::SealedRccPeripheral;
|
||||
#[cfg(feature = "low-power")]
|
||||
use crate::rtc::Rtc;
|
||||
use crate::timer::{CoreInstance, GeneralInstance1Channel};
|
||||
use crate::{interrupt, peripherals};
|
||||
use crate::{interrupt, peripherals, rcc};
|
||||
|
||||
// NOTE regarding ALARM_COUNT:
|
||||
//
|
||||
@ -31,9 +32,9 @@ use crate::{interrupt, peripherals};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(time_driver_tim9, time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] {
|
||||
const ALARM_COUNT: usize = 1;
|
||||
pub(crate) const ALARM_COUNT: usize = 1;
|
||||
} else {
|
||||
const ALARM_COUNT: usize = 3;
|
||||
pub(crate) const ALARM_COUNT: usize = 3;
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,27 +231,6 @@ fn calc_now(period: u32, counter: u16) -> u64 {
|
||||
((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
|
||||
}
|
||||
|
||||
struct AlarmState {
|
||||
timestamp: Cell<u64>,
|
||||
|
||||
// This is really a Option<(fn(*mut ()), *mut ())>
|
||||
// but fn pointers aren't allowed in const yet
|
||||
callback: Cell<*const ()>,
|
||||
ctx: Cell<*mut ()>,
|
||||
}
|
||||
|
||||
unsafe impl Send for AlarmState {}
|
||||
|
||||
impl AlarmState {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
timestamp: Cell::new(u64::MAX),
|
||||
callback: Cell::new(ptr::null()),
|
||||
ctx: Cell::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RtcDriver {
|
||||
/// Number of 2^15 periods elapsed since boot.
|
||||
period: AtomicU32,
|
||||
@ -261,9 +241,6 @@ pub(crate) struct RtcDriver {
|
||||
rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>,
|
||||
}
|
||||
|
||||
#[allow(clippy::declare_interior_mutable_const)]
|
||||
const ALARM_STATE_NEW: AlarmState = AlarmState::new();
|
||||
|
||||
embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
|
||||
period: AtomicU32::new(0),
|
||||
alarm_count: AtomicU8::new(0),
|
||||
@ -273,7 +250,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
|
||||
});
|
||||
|
||||
impl RtcDriver {
|
||||
fn init(&'static self, cs: critical_section::CriticalSection) {
|
||||
pub(crate) fn init(&'static self, cs: critical_section::CriticalSection) {
|
||||
let r = regs_gp16();
|
||||
|
||||
rcc::enable_and_reset_with_cs::<T>(cs);
|
||||
@ -318,6 +295,7 @@ impl RtcDriver {
|
||||
// XXX: reduce the size of this critical section ?
|
||||
critical_section::with(|cs| {
|
||||
let sr = r.sr().read();
|
||||
|
||||
let dier = r.dier().read();
|
||||
|
||||
// Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT.
|
Loading…
Reference in New Issue
Block a user