use crate::pac::{DCB, DWT};
#[cfg(feature = "enumset")]
use enumset::{EnumSet, EnumSetType};
use void::Void;
use crate::hal::timer::{Cancel, CountDown, Periodic};
#[allow(unused)]
use crate::pac::{self, RCC};
use crate::rcc::{self, Clocks};
use crate::time::{duration, fixed_point::FixedPoint, rate::Hertz};
mod interrupts;
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone, Copy)]
pub struct MonoTimer {
frequency: Hertz,
}
#[cfg(feature = "defmt")]
impl defmt::Format for MonoTimer {
fn format(&self, f: defmt::Formatter) {
defmt::write!(
f,
"MonoTimer {{ frequency: {} Hz }}",
self.frequency.integer(),
);
}
}
impl MonoTimer {
pub fn new(mut dwt: DWT, clocks: Clocks, dcb: &mut DCB) -> Self {
dcb.enable_trace();
dwt.enable_cycle_counter();
MonoTimer {
frequency: clocks.hclk(),
}
}
#[must_use]
pub fn frequency(&self) -> Hertz {
self.frequency
}
#[must_use]
pub fn now(&self) -> Instant {
Instant {
now: DWT::cycle_count(),
}
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Instant {
now: u32,
}
impl Instant {
#[must_use]
pub fn elapsed(self) -> u32 {
DWT::cycle_count().wrapping_sub(self.now)
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Timer<TIM> {
tim: TIM,
clocks: Clocks,
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "enumset", derive(EnumSetType))]
#[cfg_attr(not(feature = "enumset"), derive(Copy, Clone, PartialEq, Eq))]
#[non_exhaustive]
pub enum Event {
Update,
}
impl<TIM> Timer<TIM>
where
TIM: Instance,
{
pub fn new(tim: TIM, clocks: Clocks, apb: &mut <TIM as rcc::RccBus>::Bus) -> Self {
TIM::enable(apb);
TIM::reset(apb);
Timer { tim, clocks }
}
#[inline]
pub fn stop(&mut self) {
self.tim.set_cr1_cen(false);
}
#[inline]
pub fn enable_interrupt(&mut self, event: Event) {
self.configure_interrupt(event, true);
}
#[inline]
pub fn disable_interrupt(&mut self, event: Event) {
self.configure_interrupt(event, false);
}
#[doc(alias = "unmask")]
pub fn interrupt(&self) -> <TIM as crate::interrupts::InterruptNumber>::Interrupt {
<TIM as crate::interrupts::InterruptNumber>::INTERRUPT
}
#[inline]
pub fn configure_interrupt(&mut self, event: Event, enable: bool) {
match event {
Event::Update => self.tim.set_dier_uie(enable),
}
}
#[cfg(feature = "enumset")]
#[cfg_attr(docsrs, doc(cfg(feature = "enumset")))]
pub fn configure_interrupts(&mut self, events: EnumSet<Event>) {
for event in events.complement().iter() {
self.configure_interrupt(event, false);
}
for event in events.iter() {
self.configure_interrupt(event, true);
}
}
#[inline]
pub fn is_interrupt_configured(&self, event: Event) -> bool {
match event {
Event::Update => self.tim.is_dier_uie_set(),
}
}
#[cfg(feature = "enumset")]
#[cfg_attr(docsrs, doc(cfg(feature = "enumset")))]
#[inline]
pub fn configured_interrupts(&mut self) -> EnumSet<Event> {
let mut events = EnumSet::new();
for event in EnumSet::<Event>::all().iter() {
if self.is_interrupt_configured(event) {
events |= event;
}
}
events
}
pub fn is_event_triggered(&self, event: Event) -> bool {
match event {
Event::Update => self.tim.is_sr_uief_set(),
}
}
#[cfg(feature = "enumset")]
#[cfg_attr(docsrs, doc(cfg(feature = "enumset")))]
pub fn triggered_events(&self) -> EnumSet<Event> {
let mut events = EnumSet::new();
for event in EnumSet::<Event>::all().iter() {
if self.is_event_triggered(event) {
events |= event;
}
}
events
}
#[inline]
pub fn clear_event(&mut self, event: Event) {
match event {
Event::Update => self.tim.clear_sr_uief(),
}
}
#[inline]
pub fn clear_events(&mut self) {
self.tim.clear_sr();
}
pub unsafe fn peripheral(&mut self) -> &mut TIM {
&mut self.tim
}
#[inline]
pub fn free(mut self) -> TIM {
self.stop();
self.tim
}
}
impl<TIM> Periodic for Timer<TIM> where TIM: Instance {}
impl<TIM> CountDown for Timer<TIM>
where
TIM: Instance,
{
type Time = duration::Generic<u32>;
fn start<T>(&mut self, timeout: T)
where
T: Into<Self::Time>,
{
self.stop();
let timeout: Self::Time = timeout.into();
let clock = TIM::clock(&self.clocks);
let ticks = u64::from(clock.integer()).saturating_mul(u64::from(timeout.integer()))
* *timeout.scaling_factor();
let psc = ticks.saturating_sub(1) / (1 << 16);
self.tim.set_psc(crate::unwrap!(u16::try_from(psc).ok()));
let mut arr = ticks / psc.saturating_add(1);
if psc == 0 && arr == 0 {
arr = 1;
}
self.tim.set_arr(crate::unwrap!(u16::try_from(arr).ok()));
let is_update_interrupt_active = self.is_interrupt_configured(Event::Update);
if is_update_interrupt_active {
self.configure_interrupt(Event::Update, false);
}
self.tim.set_egr_ug();
self.clear_event(Event::Update);
if is_update_interrupt_active {
self.configure_interrupt(Event::Update, true);
}
self.tim.set_cr1_cen(true);
}
fn wait(&mut self) -> nb::Result<(), Void> {
if self.tim.is_sr_uief_set() {
self.clear_event(Event::Update);
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AlreadyCancled;
impl<TIM> Cancel for Timer<TIM>
where
TIM: Instance,
{
type Error = AlreadyCancled;
fn cancel(&mut self) -> Result<(), Self::Error> {
if !self.tim.is_cr1_cen_set() {
return Err(AlreadyCancled);
}
self.stop();
Ok(())
}
}
pub trait CommonRegisterBlock: crate::private::Sealed {
#[doc(hidden)]
fn set_cr1_cen(&mut self, enable: bool);
#[doc(hidden)]
fn is_cr1_cen_set(&mut self) -> bool;
#[doc(hidden)]
fn set_dier_uie(&mut self, enable: bool);
#[doc(hidden)]
fn is_dier_uie_set(&self) -> bool;
#[doc(hidden)]
fn clear_sr_uief(&mut self);
#[doc(hidden)]
fn clear_sr(&mut self);
#[doc(hidden)]
fn is_sr_uief_set(&self) -> bool;
#[doc(hidden)]
fn set_egr_ug(&mut self);
#[doc(hidden)]
fn set_psc(&mut self, psc: u16);
#[doc(hidden)]
fn set_arr(&mut self, arr: u16);
}
pub trait Instance:
CommonRegisterBlock
+ crate::interrupts::InterruptNumber
+ crate::private::Sealed
+ rcc::Enable
+ rcc::Reset
{
#[doc(hidden)]
fn clock(clocks: &Clocks) -> Hertz;
}
macro_rules! timer {
($TIMX:ident) => {
impl CommonRegisterBlock for crate::pac::$TIMX {
#[inline]
fn set_cr1_cen(&mut self, enable: bool) {
self.cr1.modify(|_, w| w.cen().bit(enable));
}
#[inline]
fn is_cr1_cen_set(&mut self) -> bool {
self.cr1.read().cen().bit()
}
#[inline]
fn set_dier_uie(&mut self, enable: bool) {
self.dier.modify(|_, w| w.uie().bit(enable));
}
#[inline]
fn is_dier_uie_set(&self) -> bool {
self.dier.read().uie().bit()
}
#[inline]
fn clear_sr_uief(&mut self) {
self.sr.modify(|_, w| w.uif().clear())
}
#[inline]
fn clear_sr(&mut self) {
self.sr.write(|w| unsafe { w.bits(0) });
}
#[inline]
fn is_sr_uief_set(&self) -> bool {
self.sr.read().uif().is_update_pending()
}
#[inline]
fn set_egr_ug(&mut self) {
self.egr.write(|w| w.ug().update());
}
#[inline]
fn set_psc(&mut self, psc: u16) {
self.psc.write(|w| w.psc().bits(psc));
}
#[inline]
fn set_arr(&mut self, arr: u16) {
#[allow(unused_unsafe)]
self.arr.write(|w| unsafe { w.arr().bits(arr.into()) });
}
}
};
}
#[allow(unused)]
macro_rules! timer_var_clock {
($($TIMX:ident, $timXsw:ident),+) => {
$(
impl Instance for crate::pac::$TIMX {
#[inline]
fn clock(clocks: &Clocks) -> Hertz {
match unsafe {(*RCC::ptr()).cfgr3.read().$timXsw().variant()} {
crate::pac::rcc::cfgr3::TIM1SW_A::Pclk2 => {
<pac::$TIMX as rcc::BusTimerClock>::timer_clock(clocks)
}
crate::pac::rcc::cfgr3::TIM1SW_A::Pll => {
if let Some(pllclk) = clocks.pllclk() {
pllclk * 2
} else {
crate::panic!("Invalid timer clock source.");
}
}
}
}
}
timer!($TIMX);
)+
};
($(($X:literal: $Y:literal)),+) => {
paste::paste! {
timer_var_clock!(
$([<TIM $X>], [<tim $Y sw>]),+
);
}
};
($($X:literal),+) => {
timer_var_clock!($(($X: $X)),+);
};
}
macro_rules! timer_static_clock {
($($TIMX:ident),+) => {
$(
impl Instance for crate::pac::$TIMX {
#[inline]
fn clock(clocks: &Clocks) -> Hertz {
<pac::$TIMX as rcc::BusTimerClock>::timer_clock(clocks)
}
}
timer!($TIMX);
)+
};
($($X:literal),+) => {
paste::paste! {
timer_static_clock!(
$([<TIM $X>]),+
);
}
};
}
cfg_if::cfg_if! {
if #[cfg(feature = "svd-f301")] {
timer_static_clock!(2, 6);
timer_var_clock!(1, 15, 16, 17);
}
}
cfg_if::cfg_if! {
if #[cfg(all(feature = "svd-f302", feature = "gpio-f303"))] {
timer_static_clock!(2, 3, 4, 6, 15, 16, 17);
timer_var_clock!(1);
}
else if #[cfg(all(feature = "svd-f302", feature = "gpio-f303e"))] {
timer_static_clock!(6);
timer_var_clock!(1, 2, 15, 16, 17);
timer_var_clock!((3: 34), (4: 34));
}
else if #[cfg(all(feature = "svd-f302", feature = "gpio-f302"))] {
timer_static_clock!(2, 6);
timer_var_clock!(1, 15, 16, 17);
}
else if #[cfg(all(feature = "svd-f303", feature = "gpio-f303"))] {
timer_static_clock!(2, 3, 4, 6, 7, 15, 16, 17);
timer_var_clock!(1, 8);
}
else if #[cfg(all(feature = "svd-f303", feature = "gpio-f303e"))] {
timer_static_clock!(6, 7);
timer_var_clock!(1, 2, 8, 15, 16, 17, 20);
timer_var_clock!((3: 34), (4: 34));
}
else if #[cfg(all(feature = "svd-f303", feature = "gpio-f333"))] {
timer_static_clock!(2, 3, 6, 7, 15, 16, 17);
timer_var_clock!(1);
}
else if #[cfg(feature = "gpio-f373")] {
timer_static_clock!(2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, 18, 19);
}
else if #[cfg(all(feature = "svd-f3x4", feature = "gpio-f333"))] {
timer_static_clock!(2, 3, 6, 7, 15, 16, 17);
timer_var_clock!(1);
}
}