use crate::hal::timer::{CountDown, Periodic};
#[cfg(not(any(
feature = "stm32l412",
feature = "stm32l422",
feature = "stm32l451",
feature = "stm32l452",
feature = "stm32l462",
)))]
use crate::stm32::TIM7;
use crate::stm32::{TIM15, TIM16, TIM2, TIM6};
#[cfg(any(
// feature = "stm32l471", // missing PAC support
feature = "stm32l475",
feature = "stm32l476",
feature = "stm32l485",
feature = "stm32l486",
feature = "stm32l496",
feature = "stm32l4a6",
// feature = "stm32l4p5",
// feature = "stm32l4q5",
// feature = "stm32l4r5",
// feature = "stm32l4s5",
// feature = "stm32l4r7",
// feature = "stm32l4s7",
feature = "stm32l4r9",
feature = "stm32l4s9",
))]
use crate::stm32::{TIM17, TIM4, TIM5};
use cast::{u16, u32};
use void::Void;
use crate::rcc::{Clocks, Enable, Reset, APB1R1, APB2};
use crate::time::Hertz;
use fugit::RateExtU32;
pub struct Timer<TIM> {
clocks: Clocks,
tim: TIM,
timeout: Hertz,
}
pub enum Event {
TimeOut,
}
macro_rules! hal {
($($TIM:ident: ($tim:ident, $frname:ident, $apb:ident, $width:ident),)+) => {
$(
impl Periodic for Timer<$TIM> {}
impl CountDown for Timer<$TIM> {
type Time = Hertz;
// NOTE(allow) `w.psc().bits()` is safe for TIM{6,7} but not for TIM{2,3,4} due to
#[allow(unused_unsafe)]
fn start<T>(&mut self, timeout: T)
where
T: Into<Hertz>,
{
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
self.timeout = timeout.into();
let ticks = self.clocks.pclk1() / self.timeout; let psc = u16((ticks - 1) / (1 << 16)).unwrap();
self.tim.psc.write(|w| unsafe { w.psc().bits(psc) });
let arr = u16(ticks / u32(psc + 1)).unwrap();
self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
self.tim.egr.write(|w| w.ug().set_bit());
self.clear_update_interrupt_flag();
self.tim.cr1.modify(|_, w| w.cen().set_bit());
}
fn wait(&mut self) -> nb::Result<(), Void> {
if self.tim.sr.read().uif().bit_is_clear() {
Err(nb::Error::WouldBlock)
} else {
self.clear_update_interrupt_flag();
Ok(())
}
}
}
impl Timer<$TIM> {
pub fn $tim(tim: $TIM, timeout: Hertz, clocks: Clocks, apb: &mut $apb) -> Self {
<$TIM>::enable(apb);
<$TIM>::reset(apb);
let mut timer = Timer {
clocks,
tim,
timeout: 0.Hz(),
};
timer.start(timeout);
timer
}
pub fn $frname(
tim: $TIM,
clocks: Clocks,
frequency: Hertz,
event_on_overflow: bool,
apb: &mut $apb,
) -> Self {
<$TIM>::enable(apb);
<$TIM>::reset(apb);
let psc = clocks.pclk1() / frequency - 1;
debug_assert!(clocks.pclk1() >= frequency);
debug_assert!(frequency.raw() > 0);
debug_assert!(psc <= core::u16::MAX.into());
tim.psc.write(|w| w.psc().bits((psc as u16).into()) );
let max = core::$width::MAX;
tim.arr.write(|w| unsafe { w.bits(max.into()) });
tim.egr.write(|w| w.ug().set_bit());
tim.sr.modify(|_, w| w.uif().clear_bit());
tim.cr1.modify(|_, w| {
w.cen().set_bit();
if event_on_overflow {
w.udis().clear_bit();
} else {
w.udis().set_bit();
}
w
});
Timer {
clocks,
tim,
timeout: frequency,
}
}
pub fn listen(&mut self, event: Event) {
match event {
Event::TimeOut => {
self.tim.dier.write(|w| w.uie().set_bit());
}
}
}
pub fn clear_interrupt(&mut self, event: Event) {
match event {
Event::TimeOut => {
self.tim.sr.write(|w| w.uif().clear_bit());
}
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::TimeOut => {
self.tim.dier.write(|w| w.uie().clear_bit());
}
}
}
pub fn clear_update_interrupt_flag(&mut self) {
self.tim.sr.modify(|_, w| w.uif().clear_bit());
}
pub fn count() -> $width {
let cnt = unsafe { (*$TIM::ptr()).cnt.read() };
cnt.cnt().bits()
}
pub fn free(self) -> $TIM {
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
self.tim
}
}
)+
}
}
hal! {
TIM2: (tim2, free_running_tim2, APB1R1, u32),
TIM6: (tim6, free_running_tim6, APB1R1, u16),
TIM15: (tim15, free_running_tim15, APB2, u16),
TIM16: (tim16, free_running_tim16, APB2, u16),
}
#[cfg(not(any(
feature = "stm32l412",
feature = "stm32l422",
feature = "stm32l451",
feature = "stm32l452",
feature = "stm32l462",
)))]
hal! {
TIM7: (tim7, free_running_tim7, APB1R1, u16),
}
#[cfg(any(
feature = "stm32l475",
feature = "stm32l476",
feature = "stm32l485",
feature = "stm32l486",
feature = "stm32l496",
feature = "stm32l4a6",
// feature = "stm32l4p5",
// feature = "stm32l4q5",
// feature = "stm32l4r5",
// feature = "stm32l4s5",
// feature = "stm32l4r7",
// feature = "stm32l4s7",
// feature = "stm32l4r9",
// feature = "stm32l4s9",
))]
hal! {
TIM4: (tim4, free_running_tim4, APB1R1, u16),
TIM5: (tim5, free_running_tim5, APB1R1, u32),
TIM17: (tim17, free_running_tim17, APB2, u16),
}