//! Timers, PWM, quadrature decoder. use core::marker::PhantomData; use embassy_hal_internal::Peripheral; use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(stm32l0))] pub mod complementary_pwm; pub mod input_capture; pub mod low_level; pub mod pwm_input; pub mod qei; pub mod simple_pwm; use crate::interrupt; use crate::rcc::RccPeripheral; /// Timer channel. #[derive(Clone, Copy)] pub enum Channel { /// Channel 1. Ch1, /// Channel 2. Ch2, /// Channel 3. Ch3, /// Channel 4. Ch4, } impl Channel { /// Get the channel index (0..3) pub fn index(&self) -> usize { match self { Channel::Ch1 => 0, Channel::Ch2 => 1, Channel::Ch3 => 2, Channel::Ch4 => 3, } } } /// Amount of bits of a timer. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum TimerBits { /// 16 bits. Bits16, /// 32 bits. #[cfg(not(stm32l0))] Bits32, } struct State { up_waker: AtomicWaker, cc_waker: [AtomicWaker; 4], } impl State { const fn new() -> Self { Self { up_waker: AtomicWaker::new(), cc_waker: [const { AtomicWaker::new() }; 4], } } } trait SealedInstance: RccPeripheral + Peripheral

{ /// Async state for this timer fn state() -> &'static State; } /// Core timer instance. #[allow(private_bounds)] pub trait CoreInstance: SealedInstance + 'static { /// Update Interrupt for this timer. type UpdateInterrupt: interrupt::typelevel::Interrupt; /// Amount of bits this timer has. const BITS: TimerBits; /// Registers for this timer. /// /// This is a raw pointer to the register block. The actual register block layout varies depending on the timer type. fn regs() -> *mut (); } /// Cut-down basic timer instance. pub trait BasicNoCr2Instance: CoreInstance {} /// Basic timer instance. pub trait BasicInstance: BasicNoCr2Instance {} /// General-purpose 16-bit timer with 1 channel instance. pub trait GeneralInstance1Channel: CoreInstance { /// Capture compare interrupt for this timer. type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; } /// General-purpose 16-bit timer with 2 channels instance. pub trait GeneralInstance2Channel: GeneralInstance1Channel { /// Trigger event interrupt for this timer. type TriggerInterrupt: interrupt::typelevel::Interrupt; } // This trait add *extra* methods to GeneralInstance4Channel, // that GeneralInstance4Channel doesn't use, but the "AdvancedInstance"s need. // And it's a private trait, so it's content won't leak to outer namespace. // // If you want to add a new method to it, please leave a detail comment to explain it. trait General4ChBlankSealed { // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel // Advanced timers implement this trait, but the output needs to be // enabled explicitly. // To support general-purpose and advanced timers, this function is added // here defaulting to noop and overwritten for advanced timers. // // Enable timer outputs. fn enable_outputs(&self) {} } /// General-purpose 16-bit timer with 4 channels instance. #[allow(private_bounds)] pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel + General4ChBlankSealed {} /// General-purpose 32-bit timer with 4 channels instance. pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {} /// Advanced 16-bit timer with 1 channel instance. pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel { /// Communication interrupt for this timer. type CommunicationInterrupt: interrupt::typelevel::Interrupt; /// Break input interrupt for this timer. type BreakInputInterrupt: interrupt::typelevel::Interrupt; } /// Advanced 16-bit timer with 2 channels instance. pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {} /// Advanced 16-bit timer with 4 channels instance. pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} pin_trait!(Channel1Pin, GeneralInstance4Channel); pin_trait!(Channel2Pin, GeneralInstance4Channel); pin_trait!(Channel3Pin, GeneralInstance4Channel); pin_trait!(Channel4Pin, GeneralInstance4Channel); pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel); pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel); pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel); pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel); pin_trait!(BreakInputPin, AdvancedInstance4Channel); pin_trait!(BreakInput2Pin, AdvancedInstance4Channel); pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel); pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel); pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel); pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel); // Update Event trigger DMA for every timer dma_trait!(UpDma, BasicInstance); dma_trait!(Ch1Dma, GeneralInstance4Channel); dma_trait!(Ch2Dma, GeneralInstance4Channel); dma_trait!(Ch3Dma, GeneralInstance4Channel); dma_trait!(Ch4Dma, GeneralInstance4Channel); #[allow(unused)] macro_rules! impl_core_timer { ($inst:ident, $bits:expr) => { impl SealedInstance for crate::peripherals::$inst { fn state() -> &'static State { static STATE: State = State::new(); &STATE } } impl CoreInstance for crate::peripherals::$inst { type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP; const BITS: TimerBits = $bits; fn regs() -> *mut () { crate::pac::$inst.as_ptr() } } }; } #[allow(unused)] macro_rules! impl_general_1ch { ($inst:ident) => { impl GeneralInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } }; } #[allow(unused)] macro_rules! impl_general_2ch { ($inst:ident) => { impl GeneralInstance2Channel for crate::peripherals::$inst { type TriggerInterrupt = crate::_generated::peripheral_interrupts::$inst::TRG; } }; } #[allow(unused)] macro_rules! impl_advanced_1ch { ($inst:ident) => { impl AdvancedInstance1Channel for crate::peripherals::$inst { type CommunicationInterrupt = crate::_generated::peripheral_interrupts::$inst::COM; type BreakInputInterrupt = crate::_generated::peripheral_interrupts::$inst::BRK; } }; } // This macro only apply to "AdvancedInstance(s)", // not "GeneralInstance4Channel" itself. #[allow(unused)] macro_rules! impl_general_4ch_blank_sealed { ($inst:ident) => { impl General4ChBlankSealed for crate::peripherals::$inst { fn enable_outputs(&self) { unsafe { crate::pac::timer::Tim1chCmp::from_ptr(Self::regs()) } .bdtr() .modify(|w| w.set_moe(true)); } } }; } foreach_interrupt! { ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { impl_core_timer!($inst, TimerBits::Bits16); impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { impl_core_timer!($inst, TimerBits::Bits16); impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} impl_general_1ch!($inst); impl_general_2ch!($inst); impl GeneralInstance4Channel for crate::peripherals::$inst {} impl General4ChBlankSealed for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { impl_core_timer!($inst, TimerBits::Bits16); impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} impl_general_1ch!($inst); impl_general_2ch!($inst); impl GeneralInstance4Channel for crate::peripherals::$inst {} impl General4ChBlankSealed for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { impl_core_timer!($inst, TimerBits::Bits16); impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} impl_general_1ch!($inst); impl_general_2ch!($inst); impl GeneralInstance4Channel for crate::peripherals::$inst {} impl General4ChBlankSealed for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { impl_core_timer!($inst, TimerBits::Bits32); impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} impl_general_1ch!($inst); impl_general_2ch!($inst); impl GeneralInstance4Channel for crate::peripherals::$inst {} impl GeneralInstance32bit4Channel for crate::peripherals::$inst {} impl General4ChBlankSealed for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { impl_core_timer!($inst, TimerBits::Bits16); impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} impl_general_1ch!($inst); impl_general_2ch!($inst); impl GeneralInstance4Channel for crate::peripherals::$inst {} impl_general_4ch_blank_sealed!($inst); impl_advanced_1ch!($inst); impl AdvancedInstance2Channel for crate::peripherals::$inst {} impl AdvancedInstance4Channel for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { impl_core_timer!($inst, TimerBits::Bits16); impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} impl_general_1ch!($inst); impl_general_2ch!($inst); impl GeneralInstance4Channel for crate::peripherals::$inst {} impl_general_4ch_blank_sealed!($inst); impl_advanced_1ch!($inst); impl AdvancedInstance2Channel for crate::peripherals::$inst {} impl AdvancedInstance4Channel for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { impl_core_timer!($inst, TimerBits::Bits16); impl BasicNoCr2Instance for crate::peripherals::$inst {} impl BasicInstance for crate::peripherals::$inst {} impl_general_1ch!($inst); impl_general_2ch!($inst); impl GeneralInstance4Channel for crate::peripherals::$inst {} impl_general_4ch_blank_sealed!($inst); impl_advanced_1ch!($inst); impl AdvancedInstance2Channel for crate::peripherals::$inst {} impl AdvancedInstance4Channel for crate::peripherals::$inst {} }; } /// Update interrupt handler. pub struct UpdateInterruptHandler { _phantom: PhantomData, } impl interrupt::typelevel::Handler for UpdateInterruptHandler { unsafe fn on_interrupt() { #[cfg(feature = "low-power")] crate::low_power::on_wakeup_irq(); let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); // Read TIM interrupt flags. let sr = regs.sr().read(); // Mask relevant interrupts (UIE). let bits = sr.0 & 0x00000001; // Mask all the channels that fired. regs.dier().modify(|w| w.0 &= !bits); // Wake the tasks if sr.uif() { T::state().up_waker.wake(); } } } /// Capture/Compare interrupt handler. pub struct CaptureCompareInterruptHandler { _phantom: PhantomData, } impl interrupt::typelevel::Handler for CaptureCompareInterruptHandler { unsafe fn on_interrupt() { #[cfg(feature = "low-power")] crate::low_power::on_wakeup_irq(); let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); // Read TIM interrupt flags. let sr = regs.sr().read(); // Mask relevant interrupts (CCIE). let bits = sr.0 & 0x0000001E; // Mask all the channels that fired. regs.dier().modify(|w| w.0 &= !bits); // Wake the tasks for ch in 0..4 { if sr.ccif(ch) { T::state().cc_waker[ch].wake(); } } } }