From a1f7a94c6924a5344ed29b60e11be673ca04bfcb Mon Sep 17 00:00:00 2001 From: Matous Hybl <hyblmatous@gmail.com> Date: Wed, 8 Dec 2021 17:36:40 +0100 Subject: [PATCH] Add low level timer API. --- embassy-stm32/src/lib.rs | 1 + embassy-stm32/src/timer/mod.rs | 224 +++++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 embassy-stm32/src/timer/mod.rs diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 1ed48df3f..dfc027733 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -20,6 +20,7 @@ pub mod gpio; pub mod rcc; #[cfg(feature = "_time-driver")] mod time_driver; +pub mod timer; // Sometimes-present hardware diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs new file mode 100644 index 000000000..ed2cb2d97 --- /dev/null +++ b/embassy-stm32/src/timer/mod.rs @@ -0,0 +1,224 @@ +use embassy::interrupt::Interrupt; + +use crate::rcc::{sealed::RccPeripheral as __RccPeri, RccPeripheral}; +use crate::time::Hertz; +use stm32_metapac::timer::vals; + +#[cfg(feature = "unstable-pac")] +pub mod low_level { + pub use super::sealed::*; +} + +pub(crate) mod sealed { + use super::*; + pub trait Basic16bitInstance: RccPeripheral { + type Interrupt: Interrupt; + + fn regs(&self) -> crate::pac::timer::TimBasic; + + fn start(&mut self); + + fn stop(&mut self); + + fn reset(&mut self); + + fn set_frequency<F: Into<Hertz>>(&mut self, frequency: F); + + fn clear_update_interrupt(&mut self) -> bool; + + fn enable_update_interrupt(&mut self, enable: bool); + } + + pub trait GeneralPurpose16bitInstance: Basic16bitInstance { + fn regs_gp16(&self) -> crate::pac::timer::TimGp16; + } + + pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { + fn regs_gp32(&self) -> crate::pac::timer::TimGp32; + + fn set_frequency<F: Into<Hertz>>(&mut self, frequency: F); + } + + pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { + fn regs_advanced(&self) -> crate::pac::timer::TimAdv; + } +} + +pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} + +pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} + +pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} + +pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} + +#[allow(unused)] +macro_rules! impl_basic_16bit_timer { + ($inst:ident, $irq:ident) => { + impl sealed::Basic16bitInstance for crate::peripherals::$inst { + type Interrupt = crate::interrupt::$irq; + + fn regs(&self) -> crate::pac::timer::TimBasic { + crate::pac::timer::TimBasic(crate::pac::$inst.0) + } + + fn start(&mut self) { + unsafe { + self.regs().cr1().modify(|r| r.set_cen(true)); + } + } + + fn stop(&mut self) { + let regs = self.regs(); + unsafe { + regs.cr1().modify(|r| r.set_cen(false)); + } + } + + fn reset(&mut self) { + unsafe { + self.regs().cnt().write(|r| r.set_cnt(0)); + } + } + + fn set_frequency<F: Into<Hertz>>(&mut self, frequency: F) { + use core::convert::TryInto; + let f = frequency.into().0; + let timer_f = Self::frequency().0; + let pclk_ticks_per_timer_period = timer_f / f; + let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); + let arr: u16 = + unwrap!((pclk_ticks_per_timer_period / (u32::from(psc) + 1)).try_into()); + + let regs = self.regs(); + unsafe { + regs.psc().write(|r| r.set_psc(psc)); + regs.arr().write(|r| r.set_arr(arr)); + + regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); + regs.egr().write(|r| r.set_ug(true)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); + } + } + + fn clear_update_interrupt(&mut self) -> bool { + unsafe { + let sr = self.regs().sr().read(); + if sr.uif() { + self.regs().sr().modify(|r| { + r.set_uif(false); + }); + true + } else { + false + } + } + } + + fn enable_update_interrupt(&mut self, enable: bool) { + unsafe { + self.regs().dier().write(|r| r.set_uie(enable)); + } + } + } + }; +} + +#[allow(unused)] +macro_rules! impl_32bit_timer { + ($inst:ident) => { + impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst { + fn regs_gp32(&self) -> crate::pac::timer::TimGp32 { + crate::pac::$inst + } + + fn set_frequency<F: Into<Hertz>>(&mut self, frequency: F) { + use core::convert::TryInto; + let f = frequency.into().0; + let timer_f = Self::frequency().0; + let pclk_ticks_per_timer_period = (timer_f / f) as u64; + let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); + let arr: u32 = + unwrap!(((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into())); + + let regs = self.regs_gp32(); + unsafe { + regs.psc().write(|r| r.set_psc(psc)); + regs.arr().write(|r| r.set_arr(arr)); + + regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); + regs.egr().write(|r| r.set_ug(true)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); + } + } + } + }; +} + +crate::pac::interrupts! { + ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { + impl_basic_16bit_timer!($inst, $irq); + + impl Basic16bitInstance for crate::peripherals::$inst { + } + }; + ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { + impl_basic_16bit_timer!($inst, $irq); + + impl Basic16bitInstance for crate::peripherals::$inst { + } + + impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { + fn regs_gp16(&self) -> crate::pac::timer::TimGp16 { + crate::pac::$inst + } + } + + impl GeneralPurpose16bitInstance for crate::peripherals::$inst { + } + }; + + ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { + impl_basic_16bit_timer!($inst, $irq); + + impl Basic16bitInstance for crate::peripherals::$inst { + } + + impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { + fn regs_gp16(&self) -> crate::pac::timer::TimGp16 { + crate::pac::timer::TimGp16(crate::pac::$inst.0) + } + } + + impl GeneralPurpose16bitInstance for crate::peripherals::$inst { + } + + impl_32bit_timer!($inst); + + impl GeneralPurpose32bitInstance for crate::peripherals::$inst { + } + }; + + ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { + impl_basic_16bit_timer!($inst, $irq); + + impl Basic16bitInstance for crate::peripherals::$inst { + } + + impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { + fn regs_gp16(&self) -> crate::pac::timer::TimGp16 { + crate::pac::timer::TimGp16(crate::pac::$inst.0) + } + } + + impl GeneralPurpose16bitInstance for crate::peripherals::$inst { + } + impl sealed::AdvancedControlInstance for crate::peripherals::$inst { + fn regs_advanced(&self) -> crate::pac::timer::TimAdv { + crate::pac::$inst + } + } + impl AdvancedControlInstance for crate::peripherals::$inst { + } + }; +}