use super::*;
use crate::{
Mcu,
fugit::{HertzU32, KilohertzU32, TimerDurationU32, TimerInstantU32},
os_trait::{TickDuration, TickInstant},
prelude::*,
rcc,
};
use core::{
ops::{Deref, DerefMut},
sync::atomic::{AtomicU8, Ordering},
};
use cortex_m::peripheral::{SYST, syst::SystClkSource};
pub trait SysTimerInit: Sized {
fn counter_hz(self, mcu: &Mcu) -> SysCounterHz;
fn counter<const FREQ: u32>(self, mcu: &Mcu) -> SysCounter<FREQ>;
fn counter_us(self, mcu: &Mcu) -> SysCounterUs {
self.counter::<1_000_000>(mcu)
}
fn init_sys_tick_instant(self);
}
impl SysTimerInit for SYST {
fn counter_hz(self, mcu: &Mcu) -> SysCounterHz {
SystemTimer::syst(self, mcu).counter_hz()
}
fn counter<const FREQ: u32>(self, mcu: &Mcu) -> SysCounter<FREQ> {
SystemTimer::syst(self, mcu).counter()
}
fn init_sys_tick_instant(mut self) {
let factor = match self.get_clock_source() {
SystClkSource::Core => 0,
SystClkSource::External => 3, };
FACTOR.store(factor, Ordering::Relaxed);
}
}
pub struct SystemTimer {
pub(super) syst: SYST,
pub(super) clk: HertzU32,
}
impl SystemTimer {
pub fn syst(mut syst: SYST, mcu: &Mcu) -> Self {
syst.set_clock_source(SystClkSource::Core);
let clk = mcu.rcc.clocks().hclk();
FACTOR.store(0, Ordering::Relaxed);
Self { syst, clk }
}
pub fn syst_external(mut syst: SYST, mcu: &Mcu) -> Self {
syst.set_clock_source(SystClkSource::External);
let clk = mcu.rcc.clocks().hclk() / 8;
FACTOR.store(3, Ordering::Relaxed); Self { syst, clk }
}
pub fn release(self) -> SYST {
self.syst
}
pub fn listen(&mut self, event: SysEvent) {
match event {
SysEvent::Update => self.syst.enable_interrupt(),
}
}
pub fn unlisten(&mut self, event: SysEvent) {
match event {
SysEvent::Update => self.syst.disable_interrupt(),
}
}
pub fn reset(&mut self) {
self.syst.clear_current();
}
}
impl SystemTimer {
pub fn counter_hz(self) -> SysCounterHz {
SysCounterHz(self)
}
pub fn counter<const FREQ: u32>(self) -> SysCounter<FREQ> {
SysCounter(self)
}
pub fn counter_us(self) -> SysCounterUs {
SysCounter(self)
}
}
pub struct SysCounterHz(SystemTimer);
impl Deref for SysCounterHz {
type Target = SystemTimer;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for SysCounterHz {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl SysCounterHz {
pub fn start(&mut self, timeout: HertzU32) -> Result<(), Error> {
let rvr = self.clk.raw() / timeout.raw() - 1;
if rvr >= (1 << 24) {
return Err(Error::WrongAutoReload);
}
self.syst.set_reload(rvr);
self.syst.clear_current();
self.syst.enable_counter();
Ok(())
}
pub fn wait(&mut self) -> nb::Result<(), Error> {
if self.syst.has_wrapped() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
pub fn cancel(&mut self) -> Result<(), Error> {
if !self.syst.is_counter_enabled() {
return Err(Error::Disabled);
}
self.syst.disable_counter();
Ok(())
}
}
pub type SysCounterUs = SysCounter<1_000_000>;
pub struct SysCounter<const FREQ: u32>(SystemTimer);
impl<const FREQ: u32> Deref for SysCounter<FREQ> {
type Target = SystemTimer;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<const FREQ: u32> DerefMut for SysCounter<FREQ> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<const FREQ: u32> SysCounter<FREQ> {
pub fn listen(&mut self, event: SysEvent) {
match event {
SysEvent::Update => self.syst.enable_interrupt(),
}
}
pub fn unlisten(&mut self, event: SysEvent) {
match event {
SysEvent::Update => self.syst.disable_interrupt(),
}
}
pub fn now(&self) -> TimerInstantU32<FREQ> {
TimerInstantU32::from_ticks(SYST::get_current() / (self.clk.raw() / FREQ))
}
pub fn start(&mut self, timeout: TimerDurationU32<FREQ>) -> Result<(), Error> {
let rvr = timeout.ticks() * (self.clk.raw() / FREQ) - 1;
if rvr >= (1 << 24) {
return Err(Error::WrongAutoReload);
}
self.syst.set_reload(rvr);
self.syst.clear_current();
self.syst.enable_counter();
Ok(())
}
pub fn wait(&mut self) -> nb::Result<(), Error> {
if self.syst.has_wrapped() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
pub fn cancel(&mut self) -> Result<(), Error> {
if !self.syst.is_counter_enabled() {
return Err(Error::Disabled);
}
self.syst.disable_counter();
Ok(())
}
}
#[derive(Copy, Clone)]
pub struct SysTickInstant {
tick: u32,
elapsed: u64,
}
impl SysTickInstant {
fn update(&mut self) {
let now = SYST::get_current();
let tick_diff = if now <= self.tick {
self.tick - now
} else {
self.tick + (SYST::get_reload() - now + 1)
};
self.elapsed = self.elapsed.wrapping_add(tick_diff as u64);
self.tick = now;
}
}
static FACTOR: AtomicU8 = AtomicU8::new(0);
impl TickInstant for SysTickInstant {
fn frequency() -> KilohertzU32 {
KilohertzU32::from_raw(rcc::get_clocks().hclk().to_kHz() >> FACTOR.load(Ordering::Relaxed))
}
#[inline(always)]
fn now() -> Self {
Self {
tick: SYST::get_current(),
elapsed: 0,
}
}
#[inline]
fn elapsed(&mut self) -> TickDuration<Self> {
self.update();
TickDuration::from_ticks(self.elapsed)
}
#[inline]
fn move_forward(&mut self, dur: &TickDuration<Self>) {
self.elapsed = self.elapsed.wrapping_sub(dur.as_ticks());
}
}