| 1 | //! Timers, PWM, quadrature decoder. |
| 2 | |
| 3 | use core::marker::PhantomData; |
| 4 | |
| 5 | use embassy_hal_internal::Peripheral; |
| 6 | use embassy_sync::waitqueue::AtomicWaker; |
| 7 | |
| 8 | #[cfg (not(stm32l0))] |
| 9 | pub mod complementary_pwm; |
| 10 | pub mod input_capture; |
| 11 | pub mod low_level; |
| 12 | pub mod pwm_input; |
| 13 | pub mod qei; |
| 14 | pub mod simple_pwm; |
| 15 | |
| 16 | use crate::interrupt; |
| 17 | use crate::rcc::RccPeripheral; |
| 18 | |
| 19 | /// Timer channel. |
| 20 | #[derive (Clone, Copy)] |
| 21 | pub enum Channel { |
| 22 | /// Channel 1. |
| 23 | Ch1, |
| 24 | /// Channel 2. |
| 25 | Ch2, |
| 26 | /// Channel 3. |
| 27 | Ch3, |
| 28 | /// Channel 4. |
| 29 | Ch4, |
| 30 | } |
| 31 | |
| 32 | impl Channel { |
| 33 | /// Get the channel index (0..3) |
| 34 | pub fn index(&self) -> usize { |
| 35 | match self { |
| 36 | Channel::Ch1 => 0, |
| 37 | Channel::Ch2 => 1, |
| 38 | Channel::Ch3 => 2, |
| 39 | Channel::Ch4 => 3, |
| 40 | } |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | /// Amount of bits of a timer. |
| 45 | #[derive (Clone, Copy, PartialEq, Eq, Debug)] |
| 46 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
| 47 | pub enum TimerBits { |
| 48 | /// 16 bits. |
| 49 | Bits16, |
| 50 | /// 32 bits. |
| 51 | #[cfg (not(stm32l0))] |
| 52 | Bits32, |
| 53 | } |
| 54 | |
| 55 | struct State { |
| 56 | up_waker: AtomicWaker, |
| 57 | cc_waker: [AtomicWaker; 4], |
| 58 | } |
| 59 | |
| 60 | impl State { |
| 61 | const fn new() -> Self { |
| 62 | Self { |
| 63 | up_waker: AtomicWaker::new(), |
| 64 | cc_waker: [const { AtomicWaker::new() }; 4], |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | trait SealedInstance: RccPeripheral + Peripheral<P = Self> { |
| 70 | /// Async state for this timer |
| 71 | fn state() -> &'static State; |
| 72 | } |
| 73 | |
| 74 | /// Core timer instance. |
| 75 | #[allow (private_bounds)] |
| 76 | pub trait CoreInstance: SealedInstance + 'static { |
| 77 | /// Update Interrupt for this timer. |
| 78 | type UpdateInterrupt: interrupt::typelevel::Interrupt; |
| 79 | |
| 80 | /// Amount of bits this timer has. |
| 81 | const BITS: TimerBits; |
| 82 | |
| 83 | /// Registers for this timer. |
| 84 | /// |
| 85 | /// This is a raw pointer to the register block. The actual register block layout varies depending on the timer type. |
| 86 | fn regs() -> *mut (); |
| 87 | } |
| 88 | /// Cut-down basic timer instance. |
| 89 | pub trait BasicNoCr2Instance: CoreInstance {} |
| 90 | /// Basic timer instance. |
| 91 | pub trait BasicInstance: BasicNoCr2Instance {} |
| 92 | |
| 93 | /// General-purpose 16-bit timer with 1 channel instance. |
| 94 | pub trait GeneralInstance1Channel: CoreInstance { |
| 95 | /// Capture compare interrupt for this timer. |
| 96 | type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; |
| 97 | } |
| 98 | |
| 99 | /// General-purpose 16-bit timer with 2 channels instance. |
| 100 | pub trait GeneralInstance2Channel: GeneralInstance1Channel { |
| 101 | /// Trigger event interrupt for this timer. |
| 102 | type TriggerInterrupt: interrupt::typelevel::Interrupt; |
| 103 | } |
| 104 | |
| 105 | // This trait add *extra* methods to GeneralInstance4Channel, |
| 106 | // that GeneralInstance4Channel doesn't use, but the "AdvancedInstance"s need. |
| 107 | // And it's a private trait, so it's content won't leak to outer namespace. |
| 108 | // |
| 109 | // If you want to add a new method to it, please leave a detail comment to explain it. |
| 110 | trait General4ChBlankSealed { |
| 111 | // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel |
| 112 | // Advanced timers implement this trait, but the output needs to be |
| 113 | // enabled explicitly. |
| 114 | // To support general-purpose and advanced timers, this function is added |
| 115 | // here defaulting to noop and overwritten for advanced timers. |
| 116 | // |
| 117 | // Enable timer outputs. |
| 118 | fn enable_outputs(&self) {} |
| 119 | } |
| 120 | |
| 121 | /// General-purpose 16-bit timer with 4 channels instance. |
| 122 | #[allow (private_bounds)] |
| 123 | pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel + General4ChBlankSealed {} |
| 124 | |
| 125 | /// General-purpose 32-bit timer with 4 channels instance. |
| 126 | pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {} |
| 127 | |
| 128 | /// Advanced 16-bit timer with 1 channel instance. |
| 129 | pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel { |
| 130 | /// Communication interrupt for this timer. |
| 131 | type CommunicationInterrupt: interrupt::typelevel::Interrupt; |
| 132 | /// Break input interrupt for this timer. |
| 133 | type BreakInputInterrupt: interrupt::typelevel::Interrupt; |
| 134 | } |
| 135 | /// Advanced 16-bit timer with 2 channels instance. |
| 136 | |
| 137 | pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {} |
| 138 | |
| 139 | /// Advanced 16-bit timer with 4 channels instance. |
| 140 | pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} |
| 141 | |
| 142 | pin_trait!(Channel1Pin, GeneralInstance4Channel); |
| 143 | pin_trait!(Channel2Pin, GeneralInstance4Channel); |
| 144 | pin_trait!(Channel3Pin, GeneralInstance4Channel); |
| 145 | pin_trait!(Channel4Pin, GeneralInstance4Channel); |
| 146 | pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); |
| 147 | |
| 148 | pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel); |
| 149 | pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel); |
| 150 | pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel); |
| 151 | pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel); |
| 152 | |
| 153 | pin_trait!(BreakInputPin, AdvancedInstance4Channel); |
| 154 | pin_trait!(BreakInput2Pin, AdvancedInstance4Channel); |
| 155 | |
| 156 | pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel); |
| 157 | pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel); |
| 158 | |
| 159 | pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel); |
| 160 | pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel); |
| 161 | |
| 162 | // Update Event trigger DMA for every timer |
| 163 | dma_trait!(UpDma, BasicInstance); |
| 164 | |
| 165 | dma_trait!(Ch1Dma, GeneralInstance4Channel); |
| 166 | dma_trait!(Ch2Dma, GeneralInstance4Channel); |
| 167 | dma_trait!(Ch3Dma, GeneralInstance4Channel); |
| 168 | dma_trait!(Ch4Dma, GeneralInstance4Channel); |
| 169 | |
| 170 | #[allow (unused)] |
| 171 | macro_rules! impl_core_timer { |
| 172 | ($inst:ident, $bits:expr) => { |
| 173 | impl SealedInstance for crate::peripherals::$inst { |
| 174 | fn state() -> &'static State { |
| 175 | static STATE: State = State::new(); |
| 176 | &STATE |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | impl CoreInstance for crate::peripherals::$inst { |
| 181 | type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP; |
| 182 | |
| 183 | const BITS: TimerBits = $bits; |
| 184 | |
| 185 | fn regs() -> *mut () { |
| 186 | crate::pac::$inst.as_ptr() |
| 187 | } |
| 188 | } |
| 189 | }; |
| 190 | } |
| 191 | |
| 192 | #[allow (unused)] |
| 193 | macro_rules! impl_general_1ch { |
| 194 | ($inst:ident) => { |
| 195 | impl GeneralInstance1Channel for crate::peripherals::$inst { |
| 196 | type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; |
| 197 | } |
| 198 | }; |
| 199 | } |
| 200 | |
| 201 | #[allow (unused)] |
| 202 | macro_rules! impl_general_2ch { |
| 203 | ($inst:ident) => { |
| 204 | impl GeneralInstance2Channel for crate::peripherals::$inst { |
| 205 | type TriggerInterrupt = crate::_generated::peripheral_interrupts::$inst::TRG; |
| 206 | } |
| 207 | }; |
| 208 | } |
| 209 | |
| 210 | #[allow (unused)] |
| 211 | macro_rules! impl_advanced_1ch { |
| 212 | ($inst:ident) => { |
| 213 | impl AdvancedInstance1Channel for crate::peripherals::$inst { |
| 214 | type CommunicationInterrupt = crate::_generated::peripheral_interrupts::$inst::COM; |
| 215 | type BreakInputInterrupt = crate::_generated::peripheral_interrupts::$inst::BRK; |
| 216 | } |
| 217 | }; |
| 218 | } |
| 219 | |
| 220 | // This macro only apply to "AdvancedInstance(s)", |
| 221 | // not "GeneralInstance4Channel" itself. |
| 222 | #[allow (unused)] |
| 223 | macro_rules! impl_general_4ch_blank_sealed { |
| 224 | ($inst:ident) => { |
| 225 | impl General4ChBlankSealed for crate::peripherals::$inst { |
| 226 | fn enable_outputs(&self) { |
| 227 | unsafe { crate::pac::timer::Tim1chCmp::from_ptr(Self::regs()) } |
| 228 | .bdtr() |
| 229 | .modify(|w| w.set_moe(true)); |
| 230 | } |
| 231 | } |
| 232 | }; |
| 233 | } |
| 234 | |
| 235 | foreach_interrupt! { |
| 236 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { |
| 237 | impl_core_timer!($inst, TimerBits::Bits16); |
| 238 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 239 | impl BasicInstance for crate::peripherals::$inst {} |
| 240 | }; |
| 241 | |
| 242 | ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { |
| 243 | impl_core_timer!($inst, TimerBits::Bits16); |
| 244 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 245 | impl BasicInstance for crate::peripherals::$inst {} |
| 246 | impl_general_1ch!($inst); |
| 247 | impl_general_2ch!($inst); |
| 248 | impl GeneralInstance4Channel for crate::peripherals::$inst {} |
| 249 | impl General4ChBlankSealed for crate::peripherals::$inst {} |
| 250 | }; |
| 251 | |
| 252 | ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { |
| 253 | impl_core_timer!($inst, TimerBits::Bits16); |
| 254 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 255 | impl BasicInstance for crate::peripherals::$inst {} |
| 256 | impl_general_1ch!($inst); |
| 257 | impl_general_2ch!($inst); |
| 258 | impl GeneralInstance4Channel for crate::peripherals::$inst {} |
| 259 | impl General4ChBlankSealed for crate::peripherals::$inst {} |
| 260 | }; |
| 261 | |
| 262 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { |
| 263 | impl_core_timer!($inst, TimerBits::Bits16); |
| 264 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 265 | impl BasicInstance for crate::peripherals::$inst {} |
| 266 | impl_general_1ch!($inst); |
| 267 | impl_general_2ch!($inst); |
| 268 | impl GeneralInstance4Channel for crate::peripherals::$inst {} |
| 269 | impl General4ChBlankSealed for crate::peripherals::$inst {} |
| 270 | }; |
| 271 | |
| 272 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { |
| 273 | impl_core_timer!($inst, TimerBits::Bits32); |
| 274 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 275 | impl BasicInstance for crate::peripherals::$inst {} |
| 276 | impl_general_1ch!($inst); |
| 277 | impl_general_2ch!($inst); |
| 278 | impl GeneralInstance4Channel for crate::peripherals::$inst {} |
| 279 | impl GeneralInstance32bit4Channel for crate::peripherals::$inst {} |
| 280 | impl General4ChBlankSealed for crate::peripherals::$inst {} |
| 281 | }; |
| 282 | |
| 283 | ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { |
| 284 | impl_core_timer!($inst, TimerBits::Bits16); |
| 285 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 286 | impl BasicInstance for crate::peripherals::$inst {} |
| 287 | impl_general_1ch!($inst); |
| 288 | impl_general_2ch!($inst); |
| 289 | impl GeneralInstance4Channel for crate::peripherals::$inst {} |
| 290 | impl_general_4ch_blank_sealed!($inst); |
| 291 | impl_advanced_1ch!($inst); |
| 292 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 293 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} |
| 294 | }; |
| 295 | |
| 296 | ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { |
| 297 | impl_core_timer!($inst, TimerBits::Bits16); |
| 298 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 299 | impl BasicInstance for crate::peripherals::$inst {} |
| 300 | impl_general_1ch!($inst); |
| 301 | impl_general_2ch!($inst); |
| 302 | impl GeneralInstance4Channel for crate::peripherals::$inst {} |
| 303 | impl_general_4ch_blank_sealed!($inst); |
| 304 | impl_advanced_1ch!($inst); |
| 305 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 306 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} |
| 307 | }; |
| 308 | |
| 309 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { |
| 310 | impl_core_timer!($inst, TimerBits::Bits16); |
| 311 | impl BasicNoCr2Instance for crate::peripherals::$inst {} |
| 312 | impl BasicInstance for crate::peripherals::$inst {} |
| 313 | impl_general_1ch!($inst); |
| 314 | impl_general_2ch!($inst); |
| 315 | impl GeneralInstance4Channel for crate::peripherals::$inst {} |
| 316 | impl_general_4ch_blank_sealed!($inst); |
| 317 | impl_advanced_1ch!($inst); |
| 318 | impl AdvancedInstance2Channel for crate::peripherals::$inst {} |
| 319 | impl AdvancedInstance4Channel for crate::peripherals::$inst {} |
| 320 | }; |
| 321 | } |
| 322 | |
| 323 | /// Update interrupt handler. |
| 324 | pub struct UpdateInterruptHandler<T: CoreInstance> { |
| 325 | _phantom: PhantomData<T>, |
| 326 | } |
| 327 | |
| 328 | impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { |
| 329 | unsafe fn on_interrupt() { |
| 330 | #[cfg (feature = "low-power" )] |
| 331 | crate::low_power::on_wakeup_irq(); |
| 332 | |
| 333 | let regs: TimCore = crate::pac::timer::TimCore::from_ptr(T::regs()); |
| 334 | |
| 335 | // Read TIM interrupt flags. |
| 336 | let sr: SrCore = regs.sr().read(); |
| 337 | |
| 338 | // Mask relevant interrupts (UIE). |
| 339 | let bits: u32 = sr.0 & 0x00000001; |
| 340 | |
| 341 | // Mask all the channels that fired. |
| 342 | regs.dier().modify(|w: &mut DierCore| w.0 &= !bits); |
| 343 | |
| 344 | // Wake the tasks |
| 345 | if sr.uif() { |
| 346 | T::state().up_waker.wake(); |
| 347 | } |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | /// Capture/Compare interrupt handler. |
| 352 | pub struct CaptureCompareInterruptHandler<T: GeneralInstance1Channel> { |
| 353 | _phantom: PhantomData<T>, |
| 354 | } |
| 355 | |
| 356 | impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompareInterrupt> |
| 357 | for CaptureCompareInterruptHandler<T> |
| 358 | { |
| 359 | unsafe fn on_interrupt() { |
| 360 | #[cfg (feature = "low-power" )] |
| 361 | crate::low_power::on_wakeup_irq(); |
| 362 | |
| 363 | let regs: TimGp16 = crate::pac::timer::TimGp16::from_ptr(T::regs()); |
| 364 | |
| 365 | // Read TIM interrupt flags. |
| 366 | let sr: SrGp16 = regs.sr().read(); |
| 367 | |
| 368 | // Mask relevant interrupts (CCIE). |
| 369 | let bits: u32 = sr.0 & 0x0000001E; |
| 370 | |
| 371 | // Mask all the channels that fired. |
| 372 | regs.dier().modify(|w: &mut DierGp16| w.0 &= !bits); |
| 373 | |
| 374 | // Wake the tasks |
| 375 | for ch: usize in 0..4 { |
| 376 | if sr.ccif(ch) { |
| 377 | T::state().cc_waker[ch].wake(); |
| 378 | } |
| 379 | } |
| 380 | } |
| 381 | } |
| 382 | |