use core::convert::TryFrom;
use core::marker::PhantomData;
use crate::hal::timer::{CountDown, Periodic};
use crate::stm32::{lptim1, lptim3};
use crate::stm32::{LPTIM1, LPTIM2, LPTIM3};
#[cfg(not(feature = "rm0455"))]
use crate::stm32::{LPTIM4, LPTIM5};
use crate::stm32::{
TIM1, TIM12, TIM13, TIM14, TIM15, TIM16, TIM17, TIM2, TIM3, TIM4, TIM5,
TIM6, TIM7, TIM8,
};
use cast::{u16, u32};
use nb;
use void::Void;
#[cfg(feature = "rm0455")]
use crate::stm32::rcc::{cdccip2r as ccip2r, srdccipr};
#[cfg(not(feature = "rm0455"))]
use crate::stm32::rcc::{d2ccip2r as ccip2r, d3ccipr as srdccipr};
use crate::rcc::{rec, CoreClocks, ResetEnable};
use crate::stm32;
use crate::time::Hertz;
use stm32h7::Variant::Val;
pub trait GetClk {
fn get_clk(clocks: &CoreClocks) -> Option<Hertz>;
}
macro_rules! impl_tim_ker_ck {
($($ckX:ident: $($TIMX:ident),+)+) => {
$(
$(
impl GetClk for $TIMX {
fn get_clk(clocks: &CoreClocks) -> Option<Hertz> {
Some(clocks.$ckX())
}
}
)+
)+
}
}
impl_tim_ker_ck! {
timx_ker_ck: TIM2, TIM3, TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14
timy_ker_ck: TIM1, TIM8, TIM15, TIM16, TIM17
}
impl GetClk for LPTIM1 {
fn get_clk(clocks: &CoreClocks) -> Option<Hertz> {
#[cfg(not(feature = "rm0455"))]
let ccip2r = &unsafe { &*stm32::RCC::ptr() }.d2ccip2r;
#[cfg(feature = "rm0455")]
let ccip2r = &unsafe { &*stm32::RCC::ptr() }.cdccip2r;
match ccip2r.read().lptim1sel().variant() {
Val(ccip2r::LPTIM1SEL_A::RCC_PCLK1) => Some(clocks.pclk1()),
Val(ccip2r::LPTIM1SEL_A::PLL2_P) => clocks.pll2_p_ck(),
Val(ccip2r::LPTIM1SEL_A::PLL3_R) => clocks.pll3_r_ck(),
Val(ccip2r::LPTIM1SEL_A::LSE) => unimplemented!(),
Val(ccip2r::LPTIM1SEL_A::LSI) => unimplemented!(),
Val(ccip2r::LPTIM1SEL_A::PER) => clocks.per_ck(),
_ => unreachable!(),
}
}
}
impl GetClk for LPTIM2 {
fn get_clk(clocks: &CoreClocks) -> Option<Hertz> {
#[cfg(not(feature = "rm0455"))]
let srdccipr = &unsafe { &*stm32::RCC::ptr() }.d3ccipr;
#[cfg(feature = "rm0455")]
let srdccipr = &unsafe { &*stm32::RCC::ptr() }.srdccipr;
match srdccipr.read().lptim2sel().variant() {
Val(srdccipr::LPTIM2SEL_A::RCC_PCLK4) => Some(clocks.pclk4()),
Val(srdccipr::LPTIM2SEL_A::PLL2_P) => clocks.pll2_p_ck(),
Val(srdccipr::LPTIM2SEL_A::PLL3_R) => clocks.pll3_r_ck(),
Val(srdccipr::LPTIM2SEL_A::LSE) => unimplemented!(),
Val(srdccipr::LPTIM2SEL_A::LSI) => unimplemented!(),
Val(srdccipr::LPTIM2SEL_A::PER) => clocks.per_ck(),
_ => unreachable!(),
}
}
}
#[cfg(feature = "rm0455")]
impl GetClk for LPTIM3 {
fn get_clk(clocks: &CoreClocks) -> Option<Hertz> {
let srdccipr = &unsafe { &*stm32::RCC::ptr() }.srdccipr;
match srdccipr.read().lptim3sel().bits() {
0 => Some(clocks.pclk4()),
1 => clocks.pll2_p_ck(),
2 => clocks.pll3_r_ck(),
3 => unimplemented!(),
4 => unimplemented!(),
5 => clocks.per_ck(),
_ => unreachable!(),
}
}
}
#[cfg(not(feature = "rm0455"))]
macro_rules! impl_clk_lptim345 {
($($TIMX:ident),+) => {
$(
impl GetClk for $TIMX {
fn get_clk(clocks: &CoreClocks) -> Option<Hertz> {
let d3ccipr = &unsafe { &*stm32::RCC::ptr() }.d3ccipr;
match d3ccipr.read().lptim345sel().variant() {
Val(srdccipr::LPTIM345SEL_A::RCC_PCLK4) => Some(clocks.pclk4()),
Val(srdccipr::LPTIM345SEL_A::PLL2_P) => clocks.pll2_p_ck(),
Val(srdccipr::LPTIM345SEL_A::PLL3_R) => clocks.pll3_r_ck(),
Val(srdccipr::LPTIM345SEL_A::LSE) => unimplemented!(),
Val(srdccipr::LPTIM345SEL_A::LSI) => unimplemented!(),
Val(srdccipr::LPTIM345SEL_A::PER) => clocks.per_ck(),
_ => unreachable!(),
}
}
}
)+
}
}
#[cfg(not(feature = "rm0455"))]
impl_clk_lptim345! { LPTIM3, LPTIM4, LPTIM5 }
pub struct Enabled;
pub struct Disabled;
pub trait TimerExt<TIM> {
type Rec: ResetEnable;
fn timer<T>(self, timeout: T, prec: Self::Rec, clocks: &CoreClocks) -> TIM
where
T: Into<Hertz>;
fn tick_timer<T>(
self,
frequency: T,
prec: Self::Rec,
clocks: &CoreClocks,
) -> TIM
where
T: Into<Hertz>;
}
#[derive(Debug)]
pub struct Timer<TIM> {
clk: u32,
tim: TIM,
}
#[derive(Debug)]
pub struct LpTimer<TIM, ED> {
clk: u32,
tim: TIM,
timeout: Hertz,
_enabled: PhantomData<ED>,
}
pub enum Event {
TimeOut,
}
macro_rules! hal {
($($TIMX:ident: ($timX:ident, $Rec:ident, $cntType:ty),)+) => {
$(
impl Periodic for Timer<$TIMX> {}
impl CountDown for Timer<$TIMX> {
type Time = Hertz;
fn start<T>(&mut self, timeout: T)
where
T: Into<Hertz>,
{
self.pause();
self.tim.cnt.reset();
self.tim.cr1.modify(|_, w| w.urs().counter_only());
self.clear_uif_bit();
self.set_freq(timeout);
self.tim.egr.write(|w| w.ug().set_bit());
self.resume()
}
fn wait(&mut self) -> nb::Result<(), Void> {
if self.tim.sr.read().uif().bit_is_clear() {
Err(nb::Error::WouldBlock)
} else {
self.clear_uif_bit();
Ok(())
}
}
}
impl TimerExt<Timer<$TIMX>> for $TIMX {
type Rec = rec::$Rec;
fn timer<T>(self, timeout: T,
prec: Self::Rec, clocks: &CoreClocks
) -> Timer<$TIMX>
where
T: Into<Hertz>,
{
let mut timer = Timer::$timX(self, prec, clocks);
timer.start(timeout);
timer
}
fn tick_timer<T>(self, frequency: T,
prec: Self::Rec, clocks: &CoreClocks
) -> Timer<$TIMX>
where
T: Into<Hertz>,
{
let mut timer = Timer::$timX(self, prec, clocks);
timer.pause();
timer.tim.cr1.modify(|_, w| w.urs().counter_only());
timer.clear_uif_bit();
timer.set_tick_freq(frequency);
timer.tim.egr.write(|w| w.ug().set_bit());
timer.resume();
timer
}
}
impl Timer<$TIMX> {
pub fn $timX(tim: $TIMX, prec: rec::$Rec, clocks: &CoreClocks) -> Self
{
prec.enable().reset();
let clk = $TIMX::get_clk(clocks)
.expect("Timer input clock not running!").0;
Timer {
clk,
tim,
}
}
pub fn set_freq<T>(&mut self, timeout: T)
where
T: Into<Hertz>,
{
let timeout = timeout.into();
let ticks = self.clk / timeout.0;
self.set_timeout_ticks(ticks);
}
pub fn set_timeout<T>(&mut self, timeout: T)
where
T: Into<core::time::Duration>
{
const NANOS_PER_SECOND: u64 = 1_000_000_000;
let timeout = timeout.into();
let clk = self.clk as u64;
let ticks = u32::try_from(
clk * timeout.as_secs() +
clk * u64::from(timeout.subsec_nanos()) / NANOS_PER_SECOND,
)
.unwrap_or(u32::max_value());
self.set_timeout_ticks(ticks.max(1));
}
fn set_timeout_ticks(&mut self, ticks: u32) {
let psc = u16((ticks - 1) / (1 << 16)).unwrap();
self.tim.psc.write(|w| w.psc().bits(psc));
let arr = u16(ticks / u32(psc + 1)).unwrap();
self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
}
pub fn set_tick_freq<T>(&mut self, frequency: T)
where
T: Into<Hertz>,
{
let frequency = frequency.into();
let div = self.clk / frequency.0;
let psc = u16(div - 1).unwrap();
self.tim.psc.write(|w| w.psc().bits(psc));
let counter_max = u32(<$cntType>::MAX);
self.tim.arr.write(|w| unsafe { w.bits(counter_max) });
}
pub fn apply_freq(&mut self) {
self.tim.egr.write(|w| w.ug().set_bit());
}
pub fn clear_uif_bit(&mut self) {
self.tim.sr.modify(|_, w| w.uif().clear_bit());
}
pub fn pause(&mut self) {
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
}
pub fn resume(&mut self) {
self.tim.cr1.modify(|_, w| w.cen().set_bit());
}
pub fn reset_counter(&mut self) {
self.tim.cnt.reset();
}
pub fn counter(&self) -> u32 {
self.tim.cnt.read().bits()
}
pub fn listen(&mut self, event: Event) {
match event {
Event::TimeOut => {
self.tim.dier.write(|w| w.uie().set_bit());
}
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::TimeOut => {
self.tim.dier.write(|w| w.uie().clear_bit());
}
}
}
pub fn clear_irq(&mut self) {
self.tim.sr.modify(|_, w| {
w.uif().clear_bit()
});
}
pub fn free(mut self) -> ($TIMX, rec::$Rec) {
self.pause();
(self.tim, rec::$Rec { _marker: PhantomData })
}
}
)+
}
}
hal! {
TIM1: (tim1, Tim1, u16),
TIM8: (tim8, Tim8, u16),
TIM2: (tim2, Tim2, u32),
TIM3: (tim3, Tim3, u16),
TIM4: (tim4, Tim4, u16),
TIM5: (tim5, Tim5, u32),
TIM6: (tim6, Tim6, u16),
TIM7: (tim7, Tim7, u16),
TIM12: (tim12, Tim12, u16),
TIM13: (tim13, Tim13, u16),
TIM14: (tim14, Tim14, u16),
TIM15: (tim15, Tim15, u16),
TIM16: (tim16, Tim16, u16),
TIM17: (tim17, Tim17, u16),
}
macro_rules! lptim_hal {
($($TIMX:ident: ($timx:ident, $Rec:ident, $timXpac:ident),)+) => {
$(
impl Periodic for LpTimer<$TIMX, Enabled> {}
impl CountDown for LpTimer<$TIMX, Enabled> {
type Time = Hertz;
fn start<T>(&mut self, timeout: T)
where
T: Into<Hertz>,
{
self.reset_counter();
self.tim.cr.write(|w| w.enable().disabled());
self.priv_set_freq(timeout);
self.clear_irq();
self.tim.cr.write(|w| w.cntstrt().set_bit().enable().enabled());
}
fn wait(&mut self) -> nb::Result<(), Void> {
if self.tim.isr.read().arrm().bit_is_clear() {
Err(nb::Error::WouldBlock)
} else {
self.clear_irq();
Ok(())
}
}
}
impl TimerExt<LpTimer<$TIMX, Enabled>> for $TIMX {
type Rec = rec::$Rec;
fn timer<T>(self, timeout: T,
prec: Self::Rec, clocks: &CoreClocks
) -> LpTimer<$TIMX, Enabled>
where
T: Into<Hertz>,
{
LpTimer::$timx(self, timeout, prec, clocks)
}
fn tick_timer<T>(self, _frequency: T,
_prec: Self::Rec, _clocks: &CoreClocks
) -> LpTimer<$TIMX, Enabled>
where
T: Into<Hertz>,
{
unimplemented!()
}
}
impl LpTimer<$TIMX, Enabled> {
pub fn $timx<T>(tim: $TIMX, timeout: T,
prec: rec::$Rec, clocks: &CoreClocks
) -> Self
where
T: Into<Hertz>,
{
prec.enable().reset();
let clk = $TIMX::get_clk(clocks)
.expect("Timer input clock not running!").0;
let mut timer = LpTimer {
clk,
tim,
timeout: Hertz(0),
_enabled: PhantomData,
};
timer.start(timeout);
timer
}
pub fn reset_counter(&mut self) {
self.tim.cr.write(|w| w.countrst().set_bit().enable().enabled());
while self.tim.cr.read().countrst().bit_is_set() {}
}
pub fn pause(self) -> LpTimer<$TIMX, Disabled> {
self.tim.cr.write(|w| w.enable().disabled());
LpTimer {
clk: self.clk,
tim: self.tim,
timeout: self.timeout,
_enabled: PhantomData,
}
}
}
impl LpTimer<$TIMX, Disabled> {
pub fn set_freq<T>(&mut self, timeout: T)
where
T: Into<Hertz>,
{
self.priv_set_freq(timeout);
self.tim.cr.write(|w| w.enable().disabled());
}
pub fn listen(&mut self, event: Event) {
match event {
Event::TimeOut => {
self.tim.ier.modify(|_, w| w.arrmie().set_bit());
}
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::TimeOut => {
self.tim.ier.modify(|_, w| w.arrmie().clear_bit());
}
}
}
pub fn resume(self) -> LpTimer<$TIMX, Enabled> {
self.tim.cr.write(|w| w.enable().enabled());
self.tim.cr.write(|w| w.cntstrt().set_bit().enable().enabled());
LpTimer {
clk: self.clk,
tim: self.tim,
timeout: self.timeout,
_enabled: PhantomData,
}
}
}
impl<ED> LpTimer<$TIMX, ED> {
fn priv_set_freq<T>(&mut self, timeout: T)
where
T: Into<Hertz>,
{
self.timeout = timeout.into();
let clk = self.clk;
let frequency = self.timeout.0;
let ticks = clk / frequency;
assert!(ticks < 128 * (1 << 16));
let (prescale, prescale_div) = match ticks / (1 << 16) {
0 => ($timXpac::cfgr::PRESC_A::DIV1, 1),
1 => ($timXpac::cfgr::PRESC_A::DIV2, 2),
2..=3 => ($timXpac::cfgr::PRESC_A::DIV4, 4),
4..=7 => ($timXpac::cfgr::PRESC_A::DIV8, 8),
8..=15 => ($timXpac::cfgr::PRESC_A::DIV16, 16),
16..=31 => ($timXpac::cfgr::PRESC_A::DIV32, 32),
32..=63 => ($timXpac::cfgr::PRESC_A::DIV64, 64),
_ => ($timXpac::cfgr::PRESC_A::DIV128, 128),
};
let arr = ticks / prescale_div;
assert!(arr <= 0xFFFF);
assert!(arr > 0);
self.tim.cfgr.modify(|_, w| w.presc().variant(prescale));
self.tim.cr.write(|w| w.enable().enabled());
self.tim.arr.write(|w| w.arr().bits(arr as u16));
while self.tim.isr.read().arrok().bit_is_clear() {}
self.tim.icr.write(|w| w.arrokcf().clear());
}
pub fn counter(&self) -> u32 {
loop {
let count1 = self.tim.cnt.read().bits();
let count2 = self.tim.cnt.read().bits();
if count1 == count2 { return count2; }
}
}
pub fn clear_irq(&mut self) {
self.tim.icr.write(|w| w.arrmcf().set_bit());
}
pub fn free(self) -> ($TIMX, rec::$Rec) {
self.tim.cr.write(|w| w.enable().disabled());
(self.tim, rec::$Rec { _marker: PhantomData })
}
}
)+
}
}
lptim_hal! {
LPTIM1: (lptim1, Lptim1, lptim1),
LPTIM2: (lptim2, Lptim2, lptim1),
LPTIM3: (lptim3, Lptim3, lptim3),
}
#[cfg(not(feature = "rm0455"))]
lptim_hal! {
LPTIM4: (lptim4, Lptim4, lptim3),
LPTIM5: (lptim5, Lptim5, lptim3),
}