stm32_hal2/timer.rs
1//! Provides support for basic timer functionality. Includes initialization, interrupts,
2//! and PWM features. Also supports capture compare, output compare, burst DMA, and getting the current uptime using
3//! an overflowing wrapper. (In seconds, milliseconds, or microseconds)
4//!
5//! Low-power timers (LPTIM) and high-presolution timers (HRTIM) are not yet supported.
6
7// todo: WB and WL should support pwm features
8
9#[cfg(feature = "monotonic")]
10use core;
11#[cfg(not(any(
12 feature = "f401",
13 feature = "f410",
14 feature = "f411",
15 feature = "f413",
16 feature = "g031",
17 feature = "g041",
18 feature = "g070",
19 feature = "g030",
20 feature = "wb",
21 feature = "wl"
22)))]
23use core::ops::Deref;
24use core::{
25 sync::atomic::{AtomicU32, Ordering},
26 time::Duration,
27};
28
29use cfg_if::cfg_if;
30use num_traits::float::FloatCore; // To round floats.
31use paste::paste;
32#[cfg(feature = "monotonic")]
33use rtic_monotonic::Monotonic;
34
35#[cfg(any(feature = "f3", feature = "l4"))]
36use crate::dma::DmaInput;
37#[cfg(not(any(feature = "f4", feature = "l552")))]
38use crate::dma::{self, ChannelCfg, DmaChannel};
39#[cfg(feature = "c0")]
40use crate::pac::DMA as DMA1;
41#[cfg(not(feature = "c0"))]
42use crate::pac::DMA1;
43#[cfg(not(any(
44 feature = "f401",
45 feature = "f410",
46 feature = "f411",
47 feature = "f413",
48 feature = "g031",
49 feature = "g041",
50 feature = "g070",
51 feature = "g030",
52 feature = "g051",
53 feature = "c0",
54 feature = "wb",
55 feature = "wl"
56)))]
57use crate::util::RccPeriph;
58// todo: LPTIM (low-power timers) and HRTIM (high-resolution timers). And Advanced control functionality
59use crate::{
60 clocks::Clocks,
61 error::{Error, Result},
62 instant::Instant,
63 pac::{self, RCC},
64 util::rcc_en_reset,
65};
66
67// This `TICK_OVERFLOW_COUNT` must be incremented in firmware in the timer's update interrupt.
68pub static TICK_OVERFLOW_COUNT: AtomicU32 = AtomicU32::new(0);
69
70// todo: Low power timer enabling etc. eg on L4, RCC_APB1Enr1().LPTIM1EN
71
72#[derive(Debug, Clone, Copy, Eq, PartialEq, defmt::Format)]
73pub enum TimerError {
74 /// Used for when attempting to set a timer period that is out of range.
75 ValueError,
76}
77
78#[derive(Clone, Copy)]
79#[repr(u8)]
80/// This bit-field selects the trigger input to be used to synchronize the counter.
81/// Sets SMCR register, TS field.
82pub enum InputTrigger {
83 ///Internal Trigger 0 (ITR0)
84 Internal0 = 0b00000,
85 Internal1 = 0b00001,
86 Internal2 = 0b00010,
87 Internal3 = 0b00011,
88 /// TI1 Edge Detector (TI1F_ED)
89 Ti1Edge = 0b00100,
90 FilteredTimerInput1 = 0b00101,
91 FilteredTimerInput2 = 0b00110,
92 ExternalTriggerInput = 0b00111,
93 Internal4 = 0b01000,
94 Internal5 = 0b01001,
95 Internal6 = 0b01010,
96 Internal7 = 0b01011,
97 Internal8 = 0b01100,
98 Internal9 = 0b01101,
99 Internal10 = 0b01110,
100 Internal11 = 0b01111,
101 Internal12 = 0b10000,
102 Internal13 = 0b10001,
103}
104
105#[derive(Clone, Copy)]
106#[repr(u8)]
107/// When external signals are selected the active edge of the trigger signal (TRGI) is linked to
108/// the polarity selected on the external input (see Input Control register and Control Register
109/// description. Sets SMCR register, SMS field.
110pub enum InputSlaveMode {
111 /// Slave mode disabled - if CEN = ‘1 then the prescaler is clocked directly by the internal
112 /// clock
113 Disabled = 0b0000,
114 /// Encoder mode 1 - Counter counts up/down on TI1FP1 edge depending on TI2FP2
115 /// level
116 Encoder1 = 0b0001,
117 /// Encoder mode 2 - Counter counts up/down on TI2FP2 edge depending on TI1FP1
118 /// level.
119 Encoder2 = 0b0010,
120 /// Encoder mode 3 - Counter counts up/down on both TI1FP1 and TI2FP2 edges
121 /// depending on the level of the other input.
122 Encoder3 = 0b0011,
123 /// Reset mode - Rising edge of the selected trigger input (TRGI) reinitializes the counter
124 /// and generates an update of the registers.
125 Reset = 0b0100,
126 /// Gated Mode - The counter clock is enabled when the trigger input (TRGI) is high. The
127 /// counter stops (but is not reset) as soon as the trigger becomes low. Both start and stop of
128 /// the counter are controlled.
129 Gated = 0b0101,
130 /// Trigger Mode - The counter starts at a rising edge of the trigger TRGI (but it is not
131 /// reset). Only the start of the counter is controlled.
132 Trigger = 0b0110,
133 /// External Clock Mode 1 - Rising edges of the selected trigger (TRGI) clock the counter.
134 ExternalClock1 = 0b0111,
135 /// Combined reset + trigger mode - Rising edge of the selected trigger input (TRGI)
136 /// reinitializes the counter, generates an update of the registers and starts the counter.
137 CombinedResetTrigger = 0b1000,
138}
139
140#[derive(Clone, Copy)]
141#[repr(u8)]
142/// These bits allow selected information to be sent in master mode to slave timers for
143/// synchronization (TRGO). Sets CR2 register, MMS field.
144pub enum MasterModeSelection {
145 /// Tthe UG bit from the TIMx_EGR register is used as trigger output (TRGO). If the
146 /// reset is generated by the trigger input (slave mode controller configured in reset mode) then
147 /// the signal on TRGO is delayed compared to the actual reset.
148 Reset = 0b000,
149 /// the Counter Enable signal CNT_EN is used as trigger output (TRGO). It is
150 /// useful to start several timers at the same time or to control a window in which a slave timer is
151 /// enable. The Counter Enable signal is generated by a logic AND between CEN control bit
152 /// and the trigger input when configured in gated mode. When the Counter Enable signal is
153 /// controlled by the trigger input, there is a delay on TRGO, except if the master/slave mode is
154 /// selected (see the MSM bit description in TIMx_SMCR register).
155 Enable = 0b001,
156 /// The update event is selected as trigger output (TRGO). For instance a master
157 /// timer can then be used as a prescaler for a slave timer.
158 Update = 0b010,
159 /// Compare Pulse - The trigger output send a positive pulse when the CC1IF flag is to be
160 /// set (even if it was already high), as soon as a capture or a compare match occurred.
161 /// (TRGO).
162 ComparePulse = 0b011,
163 /// OC1REF signal is used as trigger output (TRGO)
164 Compare1 = 0b100,
165 /// OC2REF signal is used as trigger output (TRGO)
166 Compare2 = 0b101,
167 /// OC3REF signal is used as trigger output (TRGO)
168 Compare3 = 0b110,
169 /// OC4REF signal is used as trigger output (TRGO)
170 Compare4 = 0b111,
171}
172
173/// Timer interrupt
174pub enum TimerInterrupt {
175 /// Update interrupt can be used for a timeout. DIER UIE to set, ... to clear
176 Update,
177 /// Trigger. DIER TIE to set, ... to clear
178 Trigger,
179 /// Capture/Compare. CC1IE to set, ... to clear
180 CaptureCompare1,
181 /// Capture/Compare. CC2IE to set, ... to clear
182 CaptureCompare2,
183 /// Capture/Compare. CC3IE to set, ... to clear
184 CaptureCompare3,
185 /// Capture/Compare. CC4IE to set, ... to clear
186 CaptureCompare4,
187 /// Update DMA. DIER UDE to set, ... to clear
188 UpdateDma,
189 /// Drigger. TDE to set, ... to clear
190 TriggerDma,
191 /// Capture/Compare. CC1DE to set, ... to clear
192 CaptureCompare1Dma,
193 /// Capture/Compare. CC2DE to set, ... to clear
194 CaptureCompare2Dma,
195 /// Capture/Compare. CC3DE to set, ... to clear
196 CaptureCompare3Dma,
197 /// Capture/Compare. CC4DE to set, ... to clear
198 CaptureCompare4Dma,
199}
200
201/// Output alignment. Sets `TIMx_CR1` register, `CMS` field.
202#[derive(Clone, Copy)]
203pub enum Alignment {
204 /// Edge-aligned mode. The counter counts up or down depending on the direction bit
205 /// (DIR).
206 Edge = 0b00,
207 /// Center-aligned mode 1. The counter counts up and down alternatively. Output compare
208 /// interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are set
209 /// only when the counter is counting down.
210 Center1 = 0b01,
211 /// Center-aligned mode 2. The counter counts up and down alternatively. Output compare
212 /// interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are set
213 /// only when the counter is counting up.
214 Center2 = 0b10,
215 /// Center-aligned mode 3. The counter counts up and down alternatively. Output compare
216 /// interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are set
217 /// both when the counter is counting up or down.
218 Center3 = 0b11,
219}
220
221/// Timer channel
222#[derive(Clone, Copy)]
223pub enum TimChannel {
224 C1,
225 C2,
226 C3,
227 #[cfg(not(feature = "wl"))]
228 C4,
229}
230
231/// Timer count direction. Defaults to `Up`.
232#[repr(u8)]
233#[derive(Clone, Copy)]
234pub enum CountDir {
235 Up = 0,
236 Down = 1,
237}
238
239/// Capture/Compare selection.
240/// This field defines the direction of the channel (input/output) as well as the used input.
241/// It affects the TIMx_CCMR1 register, CCxS fields.
242///
243/// Note that the the specific timer input source varies depending on the channel.
244/// `InputTiPrimary` always matches the associated channel (e.g. TI1 for CH1, TI2 for CH2, etc),
245/// while `InputTiSecondary` is TI2 for CH1, TI1 for CH2, TI4 for CH3, and TI3 for CH4.
246#[repr(u8)]
247#[derive(Clone, Copy)]
248pub enum CaptureCompare {
249 Output = 0b00,
250 InputTiPrimary = 0b01,
251 InputTiSecondary = 0b10,
252 InputTrc = 0b11,
253}
254
255/// Capture/Compare output polarity. Defaults to `ActiveHigh` in hardware. Sets TIMx_CCER register,
256/// CCxP and CCXNP fields.
257#[derive(Clone, Copy)]
258pub enum Polarity {
259 ActiveHigh,
260 ActiveLow,
261}
262
263impl Polarity {
264 /// For use with `set_bit()`.
265 fn bit(&self) -> bool {
266 match self {
267 Self::ActiveHigh => false,
268 Self::ActiveLow => true,
269 }
270 }
271}
272
273#[derive(Clone, Copy)]
274#[repr(u8)]
275/// See F303 ref man, section 21.4.7. H745 RM, section 41.4.8. Sets TIMx_CCMR1 register, OC1M field.
276/// These bits define the behavior of the output reference signal OC1REF from which OC1 and
277/// OC1N are derived. OC1REF is active high whereas OC1 and OC1N active level depends
278/// on CC1P and CC1NP bits.
279pub enum OutputCompare {
280 /// Frozen - The comparison between the output compare register TIMx_CCR1 and the
281 /// counter TIMx_CNT has no effect on the outputs.(this mode is used to generate a timing
282 /// base).
283 Frozen = 0b0000,
284 /// Set channel 1 to active level on match. OC1REF signal is forced high when the
285 /// counter TIMx_CNT matches the capture/compare register 1 (TIMx_CCR1).
286 Active = 0b0001,
287 /// Set channel 1 to inactive level on match. OC1REF signal is forced low when the
288 /// counter TIMx_CNT matches the capture/compare register 1 (TIMx_CCR1).
289 /// 0011: Toggle - OC1REF toggles when TIMx_CNT=TIMx_CCR1.
290 Inactive = 0b0010,
291 /// tim_oc1ref toggles when TIMx_CNT=TIMx_CCR1.
292 Toggle = 0b0011,
293 /// Force inactive level - OC1REF is forced low.
294 ForceInactive = 0b0100,
295 /// Force active level - OC1REF is forced high.
296 ForceActive = 0b0101,
297 /// PWM mode 1 - In upcounting, channel 1 is active as long as TIMx_CNT<TIMx_CCR1
298 /// else inactive. In downcounting, channel 1 is inactive (OC1REF=‘0) as long as
299 /// TIMx_CNT>TIMx_CCR1 else active (OC1REF=1).
300 Pwm1 = 0b0110,
301 /// PWM mode 2 - In upcounting, channel 1 is inactive as long as
302 /// TIMx_CNT<TIMx_CCR1 else active. In downcounting, channel 1 is active as long as
303 /// TIMx_CNT>TIMx_CCR1 else inactive.
304 Pwm2 = 0b0111,
305 /// Retriggerable OPM mode 1 - In up-counting mode, the channel is active until a trigger
306 /// event is detected (on TRGI signal). Then, a comparison is performed as in PWM mode 1
307 /// and the channels becomes inactive again at the next update. In down-counting mode, the
308 /// channel is inactive until a trigger event is detected (on TRGI signal). Then, a comparison is
309 /// performed as in PWM mode 1 and the channels becomes inactive again at the next update.
310 RetriggerableOpmMode1 = 0b1000,
311 /// Retriggerable OPM mode 2 - In up-counting mode, the channel is inactive until a
312 /// trigger event is detected (on TRGI signal). Then, a comparison is performed as in PWM
313 /// mode 2 and the channels becomes inactive again at the next update. In down-counting
314 /// mode, the channel is active until a trigger event is detected (on TRGI signal). Then, a
315 /// comparison is performed as in PWM mode 1 and the channels becomes active again at the
316 /// next update.
317 RetriggerableOpmMode2 = 0b1001,
318 /// Combined PWM mode 1 - OC1REF has the same behavior as in PWM mode 1.
319 /// OC1REFC is the logical OR between OC1REF and OC2REF.
320 CombinedPwm1 = 0b1100,
321 /// Combined PWM mode 2 - OC1REF has the same behavior as in PWM mode 2.
322 /// OC1REFC is the logical AND between OC1REF and OC2REF.
323 CombinedPwm2 = 0b1101,
324 /// Asymmetric PWM mode 1 - OC1REF has the same behavior as in PWM mode 1.
325 /// OC1REFC outputs OC1REF when the counter is counting up, OC2REF when it is counting
326 /// down.
327 AsymmetricPwm1 = 0b1110,
328 /// Asymmetric PWM mode 2 - OC1REF has the same behavior as in PWM mode 2.
329 /// /// OC1REFC outputs OC1REF when the counter is counting up, OC2REF when it is counting
330 /// down
331 AsymmetricPwm2 = 0b1111,
332}
333
334/// Update Request source. This bit is set and cleared by software to select the UEV event sources.
335/// Sets `TIMx_CR1` register, `URS` field.
336#[derive(Clone, Copy)]
337#[repr(u8)]
338pub enum UpdateReqSrc {
339 /// Any of the following events generate an update interrupt or DMA request.
340 /// These events can be:
341 /// – Counter overflow/underflow
342 /// – Setting the UG bit
343 /// – Update generation through the slave mode controller
344 Any = 0,
345 /// Only counter overflow/underflow generates an update interrupt or DMA request.
346 OverUnderFlow = 1,
347}
348
349/// Capture/Compaer DMA selection.
350/// Sets `TIMx_CR2` register, `CCDS` field.
351#[derive(Clone, Copy)]
352#[repr(u8)]
353pub enum CaptureCompareDma {
354 /// CCx DMA request sent when CCx event occur
355 Ccx = 0,
356 /// CCx DMA request sent when update event occurs
357 Update = 1,
358}
359
360/// Initial configuration data for Timer peripherals.
361#[derive(Clone)]
362pub struct TimerConfig {
363 /// If `one_pulse_mode` is true, the counter stops counting at the next update event
364 /// (clearing the bit CEN). If false, Counter is not stopped at update event. Defaults to false.
365 /// Sets `TIMx_CR` register, `OPM` field.
366 pub one_pulse_mode: bool,
367 /// Update request source. Ie, counter overflow/underflow only, or any. defaults to any.
368 pub update_request_source: UpdateReqSrc,
369 /// Set `true` to buffer the preload. Useful when changing period and duty while the timer is running.
370 /// Default to false.
371 pub auto_reload_preload: bool,
372 /// Select center or edge alignment. Defaults to edge.
373 pub alignment: Alignment,
374 /// Sets when CCx DMA requests occur. Defaults to on CCx event.
375 pub capture_compare_dma: CaptureCompareDma,
376 /// Timer counting direction. Defaults to up.
377 pub direction: CountDir,
378}
379
380impl Default for TimerConfig {
381 fn default() -> Self {
382 Self {
383 one_pulse_mode: false,
384 update_request_source: UpdateReqSrc::Any,
385 auto_reload_preload: false,
386 alignment: Alignment::Edge,
387 capture_compare_dma: CaptureCompareDma::Ccx,
388 direction: CountDir::Up,
389 }
390 }
391}
392
393/// Represents a General Purpose or Advanced Control timer.
394pub struct Timer<TIM> {
395 /// Register block for the specific timer.
396 pub regs: TIM,
397 /// Our config stucture, for configuration that is written to the timer hardware on initialization
398 /// via the constructor.
399 pub cfg: TimerConfig,
400 /// Associated timer clock speed in Hz.
401 clock_speed: u32,
402 // #[cfg(feature = "monotonic")]
403 // /// Used to indicate the timer has expired, and running time counts (eg the `time_elapsed()` method) properly
404 // /// increment.
405 // pub wrap_count: u32,
406 // #[cfg(feature = "monotonic")]
407 /// Updated in the constructor and `set_freq` fns. Used for mapping timer ticks to time (eg in
408 /// seconds, us etc)
409 ns_per_tick: u64,
410 period: f32, // In seconds. Used for overflow tracking. Updated when `ns_per_tick` is.
411}
412
413macro_rules! make_timer {
414 ($TIMX:ident, $tim:ident, $apb:expr, $res:ident) => {
415 impl Timer<pac::$TIMX> {
416 paste! {
417 /// Initialize a Timer peripheral, including enabling and resetting
418 /// its RCC peripheral clock.
419 ///
420 /// Sets prescaler and auto-reload based on the requested frequency.
421 /// Use `new_timx_manual` to set the prescaler and auto-reload directly.
422 pub fn [<new_ $tim>](regs: pac::$TIMX, freq: f32, cfg: TimerConfig, clocks: &Clocks) -> Self {
423 let mut result = Self::new_internal(regs, cfg, clocks);
424
425 result.set_freq(freq).ok();
426 result.set_dir();
427
428 // Trigger an update event to load the prescaler value to the clock
429 // NOTE(write): uses all bits in this register. This also clears the interrupt flag,
430 // which the EGER update will generate.
431 result.reinitialize();
432
433 result
434 }
435
436 /// Initialize a Timer peripheral, including enabling and resetting
437 /// its RCC peripheral clock.
438 pub fn [<new_ $tim _manual>](regs: pac::$TIMX, psc: u16, arr: u32, cfg: TimerConfig, clocks: &Clocks) -> Self {
439 let mut result = Self::new_internal(regs, cfg, clocks);
440
441 result.set_prescaler(psc);
442 result.set_auto_reload(arr);
443 result.set_dir();
444
445 // Trigger an update event to load the prescaler value to the clock
446 // NOTE(write): uses all bits in this register. This also clears the interrupt flag,
447 // which the EGER update will generate.
448 result.reinitialize();
449
450 result
451 }
452
453 #[inline]
454 fn new_internal(regs: pac::$TIMX, cfg: TimerConfig, clocks: &Clocks) -> Self {
455 let rcc = unsafe { &(*RCC::ptr()) };
456
457 // `freq` is in Hz.
458 rcc_en_reset!([<apb $apb>], $tim, rcc);
459
460 #[cfg(not(feature = "c0"))]
461 let clock_speed = clocks.[<apb $apb _timer>]();
462 #[cfg(feature = "c0")]
463 let clock_speed = clocks.apb1_timer(); // C0 only has one APB
464
465 regs.cr1().modify(|_, w| {
466 #[cfg(not(feature = "f373"))]
467 w.opm().bit(cfg.one_pulse_mode);
468 w.urs().bit(cfg.update_request_source as u8 != 0);
469 w.arpe().bit(cfg.auto_reload_preload)
470 });
471
472 #[cfg(not(any(feature = "f373", feature = "c0")))]
473 regs.cr2().modify(|_, w| {
474 w.ccds().bit(cfg.capture_compare_dma as u8 != 0)
475 });
476
477 Timer {
478 clock_speed,
479 cfg,
480 regs,
481 // #[cfg(feature = "monotonic")]
482 // wrap_count: 0,
483 // #[cfg(feature = "monotonic")]
484 ns_per_tick: 0, // set in `new_timx`
485 period: 0., // set in `new_timx`
486 }
487 }
488 }
489
490 /// Enable a specific type of Timer interrupt.
491 pub fn enable_interrupt(&mut self, interrupt: TimerInterrupt) {
492 match interrupt {
493 TimerInterrupt::Update => self.regs.dier().modify(|_, w| w.uie().bit(true)),
494 // todo: Only DIER is in PAC, or some CCs. PAC BUG? Only avail on some timers/MCUs?
495 // TimerInterrupt::Trigger => self.regs.dier().modify(|_, w| w.tie().bit(true)),
496 // TimerInterrupt::CaptureCompare1 => self.regs.dier().modify(|_, w| w.cc1ie().bit(true)),
497 // TimerInterrupt::CaptureCompare2 => self.regs.dier().modify(|_, w| w.cc2ie().bit(true)),
498 // TimerInterrupt::CaptureCompare3 => self.regs.dier().modify(|_, w| w.cc3ie().bit(true)),
499 // TimerInterrupt::CaptureCompare4 => self.regs.dier().modify(|_, w| w.cc4ie().bit(true)),
500 #[cfg(not(feature = "f3"))] // todo: Not working on some variants
501 TimerInterrupt::UpdateDma => self.regs.dier().modify(|_, w| w.ude().bit(true)),
502 // TimerInterrupt::TriggerDma => self.regs.dier().modify(|_, w| w.tde().bit(true)),
503 // TimerInterrupt::CaptureCompare1Dma => self.regs.dier().modify(|_, w| w.cc1de().bit(true)),
504 // TimerInterrupt::CaptureCompare2Dma => self.regs.dier().modify(|_, w| w.ccd2de().bit(true)),
505 // TimerInterrupt::CaptureCompare3Dma => self.regs.dier().modify(|_, w| w.cc3de().bit(true)),
506 // TimerInterrupt::CaptureCompare4Dma => self.regs.dier().modify(|_, w| w.cc4de().bit(true)),
507 _ => unimplemented!("TODO TEMP PROBLEMS"),
508 };
509 }
510
511 /// Disable a specific type of Timer interrupt.
512 pub fn disable_interrupt(&mut self, interrupt: TimerInterrupt) {
513 match interrupt {
514 TimerInterrupt::Update => self.regs.dier().modify(|_, w| w.uie().clear_bit()),
515 // todo: Only DIER is in PAC, or some CCs. PAC BUG? Only avail on some timers/MCUs?
516 // TimerInterrupt::Trigger => self.regs.dier().modify(|_, w| w.tie().clear_bit()),
517 // TimerInterrupt::CaptureCompare1 => self.regs.dier().modify(|_, w| w.cc1ie().clear_bit()),
518 // TimerInterrupt::CaptureCompare2 => self.regs.dier().modify(|_, w| w.cc2ie().clear_bit()),
519 // TimerInterrupt::CaptureCompare3 => self.regs.dier().modify(|_, w| w.cc3ie().clear_bit()),
520 // TimerInterrupt::CaptureCompare4 => self.regs.dier().modify(|_, w| w.cc4ie().clear_bit()),
521 #[cfg(not(feature = "f3"))] // todo: Not working on some variants
522 TimerInterrupt::UpdateDma => self.regs.dier().modify(|_, w| w.ude().clear_bit()),
523 // TimerInterrupt::TriggerDma => self.regs.dier().modify(|_, w| w.tde().clear_bit()),
524 // TimerInterrupt::CaptureCompare1Dma => self.regs.dier().modify(|_, w| w.cc1de().clear_bit()),
525 // TimerInterrupt::CaptureCompare2Dma => self.regs.dier().modify(|_, w| w.ccd2de().clear_bit()),
526 // TimerInterrupt::CaptureCompare3Dma => self.regs.dier().modify(|_, w| w.cc3de().clear_bit()),
527 // TimerInterrupt::CaptureCompare4Dma => self.regs.dier().modify(|_, w| w.cc4de().clear_bit()),
528 _ => unimplemented!("TODO TEMP PROBLEMS"),
529 };
530 }
531
532 /// Clears interrupt associated with this timer.
533 ///
534 /// If the interrupt is not cleared, it will immediately retrigger after
535 /// the ISR has finished. For examlpe, place this at the top of your timer's
536 /// interrupt handler.
537 pub fn clear_interrupt(&mut self, interrupt: TimerInterrupt) {
538 // Note that unlike other clear interrupt functions, for this, we clear the bit instead
539 // of setting it. Due to the way our SVDs are set up not working well with this atomic clear,
540 // we need to make sure we write 1s to the rest of the bits.
541 // todo: Overcapture flags for each CC? DMA interrupts?
542 #[cfg(feature = "c0")]
543 let bits = 0xffff;
544 #[cfg(not(feature = "c0"))]
545 let bits = 0xffff_ffff;
546
547 unsafe {
548 match interrupt {
549 TimerInterrupt::Update => self
550 .regs
551 .sr()
552 .write(|w| w.bits(bits).uif().clear_bit()),
553 // todo: Only DIER is in PAC, or some CCs. PAC BUG? Only avail on some timers?
554 // TimerInterrupt::Trigger => self.regs.sr().write(|w| w.bits(bits).tif().clear_bit()),
555 // TimerInterrupt::CaptureCompare1 => self.regs.sr().write(|w| w.bits(bits).cc1if().clear_bit()),
556 // TimerInterrupt::CaptureCompare2 => self.regs.sr().write(|w| w.bits(bits).cc2if().clear_bit()),
557 // TimerInterrupt::CaptureCompare3 => self.regs.sr().write(|w| w.bits(bits).cc3if().clear_bit()),
558 // TimerInterrupt::CaptureCompare4 => self.regs.sr().write(|w| w.bits(bits).cc4if().clear_bit()),
559 _ => unimplemented!(
560 "Clearing DMA flags is unimplemented using this function."
561 ),
562 };
563 }
564 }
565
566 /// Enable (start) the timer.
567 pub fn enable(&mut self) {
568 self.regs.cr1().modify(|_,w| w.cen().bit(true));
569 }
570
571 /// Disable (stop) the timer.
572 pub fn disable(&mut self) {
573 self.regs.cr1().modify(|_, w| w.cen().clear_bit());
574 }
575
576 /// Check if the timer is enabled.
577 pub fn is_enabled(&self) -> bool {
578 self.regs.cr1().read().cen().bit_is_set()
579 }
580
581 #[cfg(not(feature = "c0"))]
582 /// Print the (raw) contents of the status register.
583 pub fn read_status(&self) -> u32 {
584 unsafe { self.regs.sr().read().bits() }
585 }
586
587 #[cfg(feature = "c0")]
588 /// Print the (raw) contents of the status register.
589 pub fn read_status(&self) -> u16 {
590 unsafe { self.regs.sr().read().bits().try_into().unwrap() }
591 }
592
593 /// Set the timer frequency, in Hz. Overrides the period or frequency set
594 /// in the constructor.
595 pub fn set_freq(&mut self, mut freq: f32) -> Result<()> {
596 assert!(freq > 0.);
597 // todo: Take into account the `timxsw` bit in RCC CFGR3, which may also
598 // todo require an adjustment to freq.
599 match self.cfg.alignment {
600 Alignment::Edge => (),
601 _ => freq *= 2.,
602 }
603
604 let (psc, arr) = calc_freq_vals(freq, self.clock_speed)?;
605
606 self.regs.arr().write(|w| unsafe { w.bits(arr.into()) });
607 self.regs.psc().write(|w| unsafe { w.bits(psc.into()) });
608
609 // (PSC+1)*(ARR+1) = TIMclk/Updatefrequency = TIMclk * period
610 // period = (PSC+1)*(ARR+1) / TIMclk
611 // Calculate this based on our actual ARR and PSC values; don't use
612 // the requested frequency or period.
613 let arr_f32 = arr as f32;
614 let period_secs = (psc as f32 + 1.) * ( arr_f32 + 1.) / self.clock_speed as f32;
615 self.ns_per_tick = (period_secs / arr_f32 * 1_000_000_000.) as u64;
616 self.period = period_secs;
617
618 Ok(())
619 }
620
621 /// Set the timer period, in seconds. Overrides the period or frequency set
622 /// in the constructor.
623 pub fn set_period(&mut self, period: f32) -> Result<()> {
624 assert!(period > 0.);
625 self.set_freq(1. / period)
626 }
627
628 /// Set the auto-reload register value. Used for adjusting frequency.
629 pub fn set_auto_reload(&mut self, arr: u32) {
630 // todo: Could be u16 or u32 depending on timer resolution,
631 // todo but this works for now.
632 #[cfg(not(feature = "c0"))]
633 self.regs.arr().write(|w| unsafe { w.bits(arr.into()) });
634 #[cfg(feature = "c0")]
635 self.regs.arr().write(|w| unsafe { w.bits((arr as u32).try_into().unwrap()) });
636 }
637
638 /// Set the prescaler value. Used for adjusting frequency.
639 pub fn set_prescaler(&mut self, psc: u16) {
640 self.regs.psc().write(|w| unsafe { w.bits(psc.into()) });
641 }
642
643 /// Reset the countdown; set the counter to 0.
644 pub fn reset_count(&mut self) {
645 self.regs.cnt().write(|w| unsafe { w.bits(0) });
646 }
647
648 /// UIF Flag in SR register is set when CNT reg is overflow / underflow
649 ///
650 pub fn get_uif(&self ) -> bool {
651 self.regs.sr().read().uif().bit_is_set()
652 }
653
654 pub fn clear_uif(&mut self) {
655 #[cfg(feature = "c0")]
656 let bits = 0xffff;
657 #[cfg(not(feature = "c0"))]
658 let bits = 0xffff_ffff;
659
660 unsafe {
661 self.regs
662 .sr()
663 .write(|w| w.bits(bits).uif().clear_bit());
664 }
665 }
666
667 /// Re-initialize the counter and generates an update of the registers. Note that the prescaler
668 /// counter is cleared too (anyway the prescaler ratio is not affected). The counter is cleared.
669 /// When changing timer frequency (or period) via PSC, you may need to run this. Alternatively, change
670 /// the freq in an update ISR.
671 /// Note from RM, PSC reg: PSC contains the value to be loaded in the active prescaler
672 /// register at each update event
673 /// (including when the counter is cleared through UG bit of TIMx_EGR register or through
674 /// trigger controller when configured in “reset mode”).'
675 /// If you're doing something where the updates can wait a cycle, this isn't required. (eg PWM
676 /// with changing duty period).
677 pub fn reinitialize(&mut self) {
678 self.regs.egr().write(|w| w.ug().bit(true));
679 self.clear_interrupt(TimerInterrupt::Update);
680 }
681
682 /// Read the current counter value.
683 pub fn read_count(&self) -> u32 {
684 // todo: This depends on resolution. We read the whole
685 // todo res and pass a u32 just in case.
686 // self.regs.cnt().read().cnt().bits()
687 self.regs.cnt().read().bits()
688 }
689
690
691 /// Enables PWM output for a given channel and output compare, with an initial duty cycle, in Hz.
692 /// Note: On TIM1 and TIM8, (And others if on C0), you must manually set the `bdtr` register,
693 /// `moe` bit.
694 pub fn enable_pwm_output(
695 &mut self,
696 channel: TimChannel,
697 compare: OutputCompare,
698 duty: f32,
699 ) {
700 self.set_capture_compare_output(channel, CaptureCompare::Output);
701 self.set_preload(channel, true);
702 self.set_output_compare(channel, compare);
703 self.set_duty(channel, (self.get_max_duty() as f32 * duty) as $res);
704 self.enable_capture_compare(channel);
705 }
706
707 /// Return the integer associated with the maximum duty period.
708 pub fn get_max_duty(&self) -> $res {
709 #[cfg(feature = "g0")]
710 return self.regs.arr().read().bits().try_into().unwrap();
711 #[cfg(not(feature = "g0"))]
712 self.regs.arr().read().arr().bits().try_into().unwrap()
713 }
714
715 /// See G4 RM, section 29.4.24: Dma burst mode. "The TIMx timers have the capability to
716 /// generate multiple DMA requests upon a single event.
717 /// The main purpose is to be able to re-program part of the timer multiple times without
718 /// software overhead, but it can also be used to read several registers in a row, at regular
719 /// intervals." This may be used to create arbitrary waveforms by modifying the CCR register
720 /// (base address = 13-16, for CCR1-4), or for implementing duty-cycle based digital protocols.
721 #[cfg(not(any(feature = "g0", feature = "f", feature = "l552", feature = "l4")))]
722 pub unsafe fn write_dma_burst(
723 &mut self,
724 buf: &[u16],
725 base_address: u8,
726 burst_len: u8,
727 dma_channel: DmaChannel,
728 channel_cfg: ChannelCfg,
729 ds_32_bits: bool,
730 dma_periph: dma::DmaPeriph,
731 ) -> Result<()> {
732 // Note: F3 and L4 are unsupported here, since I'm not sure how to select teh
733 // correct Timer channel.
734
735 // todo: Should we disable the timer here?
736
737 let (ptr, len) = (buf.as_ptr(), buf.len());
738
739 // todo: For F3 and L4, manually set channel using PAC for now. Currently
740 // todo we don't have a way here to pick the timer. Could do it with a new macro arg.
741
742 // L44 RM, Table 41. "DMA1 requests for each channel"
743 // #[cfg(any(feature = "f3", feature = "l4"))]
744 // let dma_channel = match tim_channel {
745 // // SaiChannel::A => DmaInput::Sai1A.dma1_channel(),
746 // };
747 //
748 // #[cfg(feature = "l4")]
749 // match tim_channel {
750 // SaiChannel::B => dma.channel_select(DmaInput::Sai1B),
751 // };
752
753 // RM:
754 // This example is for the case where every CCRx register has to be updated once. If every
755 // CCRx register is to be updated twice for example, the number of data to transfer should be
756 // 6. Let's take the example of a buffer in the RAM containing data1, data2, data3, data4, data5
757 // and data6. The data is transferred to the CCRx registers as follows: on the first update DMA
758 // request, data1 is transferred to CCR2, data2 is transferred to CCR3, data3 is transferred to
759 // CCR4 and on the second update DMA request, data4 is transferred to CCR2, data5 is
760 // transferred to CCR3 and data6 is transferred to CCR4.
761
762 // 1. Configure the corresponding DMA channel as follows:
763 // –DMA channel peripheral address is the DMAR register address
764 let periph_addr = unsafe { &self.regs.dmar() as *const _ as u32 };
765 // –DMA channel memory address is the address of the buffer in the RAM containing
766 // the data to be transferred by DMA into CCRx registers.
767
768 // Number of data to transfer is our buffer len number of registers we're editing, x
769 // number of half-words written to each reg.
770 let num_data = len as u32;
771
772 // 2.
773 // Configure the DCR register by configuring the DBA and DBL bit fields as follows:
774 // DBL = 3 transfers, DBA = 0xE.
775
776 // The DBL[4:0] bits in the TIMx_DCR register set the DMA burst length. The timer recognizes
777 // a burst transfer when a read or a write access is done to the TIMx_DMAR address), i.e. the
778 // number of transfers (either in half-words or in bytes).
779 // The DBA[4:0] bits in the TIMx_DCR registers define the DMA base address for DMA
780 // transfers (when read/write access are done through the TIMx_DMAR address). DBA is
781 // defined as an offset starting from the address of the TIMx_CR1 register:
782 // Example:
783 // 00000: TIMx_CR1
784 // 00001: TIMx_CR2
785 // 00010: TIMx_SMCR
786 self.regs.dcr().modify(|_, w| unsafe {
787 w.dba().bits(base_address);
788 w.dbl().bits(burst_len as u8 - 1)
789 });
790
791 // 3. Enable the TIMx update DMA request (set the UDE bit in the DIER register).
792 // note: Leaving this to application code for now.
793 // self.enable_interrupt(TimerInterrupt::UpdateDma);
794
795 // 4. Enable TIMx
796 self.enable();
797
798 // 5. Enable the DMA channel
799 match dma_periph {
800 dma::DmaPeriph::Dma1 => {
801 let mut regs = unsafe { &(*DMA1::ptr()) };
802 dma::cfg_channel(
803 &mut regs,
804 dma_channel,
805 periph_addr,
806 ptr as u32,
807 num_data,
808 dma::Direction::ReadFromMem,
809 // Note: This may only be relevant if modifying a reg that changes for 32-bit
810 // timers, like AAR and CCRx
811 if ds_32_bits { dma::DataSize::S32} else { dma::DataSize::S16 },
812 dma::DataSize::S16,
813 channel_cfg,
814 )?;
815 }
816 #[cfg(dma2)]
817 dma::DmaPeriph::Dma2 => {
818 let mut regs = unsafe { &(*pac::DMA2::ptr()) };
819 dma::cfg_channel(
820 &mut regs,
821 dma_channel,
822 periph_addr,
823 ptr as u32,
824 num_data,
825 dma::Direction::ReadFromMem,
826 // Note: This may only be relevant if modifying a reg that changes for 32-bit
827 // timers, like AAR and CCRx
828 if ds_32_bits { dma::DataSize::S32} else { dma::DataSize::S16 },
829 dma::DataSize::S16,
830 channel_cfg,
831 )?;
832 }
833 }
834 Ok(())
835 }
836
837 #[cfg(not(any(feature = "g0", feature = "f", feature = "l552", feature = "l4")))]
838 pub unsafe fn read_dma_burst(
839 // todo: Experimenting with input capture.
840 &mut self,
841 buf: &mut [u16],
842 base_address: u8,
843 burst_len: u8,
844 dma_channel: DmaChannel,
845 channel_cfg: ChannelCfg,
846 ds_32_bits: bool,
847 dma_periph: dma::DmaPeriph,
848 ) -> Result<()> {
849 let (ptr, len) = (buf.as_mut_ptr(), buf.len());
850
851 let periph_addr = unsafe { &self.regs.dmar() as *const _ as u32 };
852
853 let num_data = len as u32;
854
855 self.regs.dcr().modify(|_, w| unsafe {
856 w.dba().bits(base_address);
857 w.dbl().bits(burst_len as u8 - 1)
858 });
859
860 self.enable();
861
862 match dma_periph {
863 dma::DmaPeriph::Dma1 => {
864 #[cfg(not(feature = "c0"))]
865 let mut regs = unsafe { &(*pac::DMA1::ptr()) };
866 #[cfg(feature = "c0")]
867 let mut regs = unsafe { &(*pac::DMA::ptr()) };
868
869 dma::cfg_channel(
870 &mut regs,
871 dma_channel,
872 periph_addr,
873 ptr as u32,
874 num_data,
875 dma::Direction::ReadFromPeriph,
876 // Note: This may only be relevant if modifying a reg that changes for 32-bit
877 // timers, like AAR and CCRx
878 if ds_32_bits { dma::DataSize::S32} else { dma::DataSize::S16 },
879 dma::DataSize::S16,
880 channel_cfg,
881 )?;
882 }
883 #[cfg(dma2)]
884 dma::DmaPeriph::Dma2 => {
885 let mut regs = unsafe { &(*pac::DMA2::ptr()) };
886 dma::cfg_channel(
887 &mut regs,
888 dma_channel,
889 periph_addr,
890 ptr as u32,
891 num_data,
892 dma::Direction::ReadFromPeriph,
893 // Note: This may only be relevant if modifying a reg that changes for 32-bit
894 // timers, like AAR and CCRx
895 if ds_32_bits { dma::DataSize::S32} else { dma::DataSize::S16 },
896 dma::DataSize::S16,
897 channel_cfg,
898 )?;
899 }
900 }
901 Ok(())
902 }
903
904 /// Get the time elapsed since the start of the timer, taking overflow wraps into account.
905 ///
906 /// Important: the value returned here will only be correct if the ARR and PSC are set
907 /// only using the constructor, `set_freq`, or `set_period` methods.
908 pub fn now(&mut self) -> Instant {
909 // let wrap_count = self.wrap_count;
910 let wrap_count = TICK_OVERFLOW_COUNT.load(Ordering::Acquire);
911
912 let ticks = (self.read_count() as u64 + wrap_count as u64 *
913 self.get_max_duty() as u64);
914 let count_ns = ticks as i128 * self.ns_per_tick as i128;
915
916 Instant::new(count_ns)
917 }
918
919 pub fn elapsed(&mut self, since: Instant) -> Duration {
920 self.now() - since
921 }
922 }
923
924 #[cfg(feature = "monotonic")]
925 impl Monotonic for Timer<pac::$TIMX> {
926 type Instant = Instant;
927 type Duration = core::time::Duration;
928
929 const DISABLE_INTERRUPT_ON_EMPTY_QUEUE: bool = false;
930
931 fn now(&mut self) -> Self::Instant {
932 self.time_elapsed()
933 }
934
935 /// We use the compare 1 channel for this.
936 /// todo: Support wrapping?
937 fn set_compare(&mut self, instant: Self::Instant) {
938 self.regs
939 .ccr1()
940 .write(|w| unsafe { w.ccr().bits(((instant.count_ns as f32 / self.ns_per_tick) as u16).into()) });
941 }
942
943 /// We use the compare 1 channel for this.
944 /// todo: Support wrapping?
945 fn clear_compare_flag(&mut self) {
946 self.regs.sr().modify(|_, w| w.cc1if().clear_bit());
947 }
948
949 fn zero() -> Self::Instant {
950 Instant::default()
951 }
952
953 unsafe fn reset(&mut self) {
954 self.reset_count();
955 TICK_OVERFLOW_COUNT.store(0, Ordering::Release);
956 }
957
958 fn on_interrupt(&mut self) {
959 // self.wrap_count += 1;
960 TICK_OVERFLOW_COUNT.fetch_add(1, Ordering::Relaxed);
961 }
962 fn enable_timer(&mut self) {
963 self.enable();
964 }
965 fn disable_timer(&mut self) {
966 self.disable();
967 }
968
969 /// Print the (raw) contents of the status register.
970 pub fn read_status(&self) -> u32 {
971 unsafe { self.regs.isr().read().bits() }
972 }
973 }
974
975 // cfg_if! {
976 // if #[cfg(feature = "embedded_hal")] {
977 // // use embedded_hal::{
978 // // blocking::delay::{DelayMs, DelayUs},
979 // // timer::CountDown,
980 // // };
981 // // use embedded_time::{rate::Hertz, duration};
982 // // use void::Void;
983 // }
984 // }
985
986 // #[cfg(feature = "embedded_hal")]
987 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
988 // impl DelayMs<u32> for Timer<pac::$TIMX> {
989 // fn delay_ms(&mut self, ms: u32) {
990 // let ms_to_s = ms as f32 / 1_000.;
991 // self.set_freq(1. / (ms_to_s)).ok();
992 // self.reset_count();
993 // self.enable();
994 // while self.get_uif() == false {}
995 // self.clear_uif();
996 // self.disable();
997 // }
998 // }
999 //
1000 // #[cfg(feature = "embedded_hal")]
1001 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
1002 // impl DelayMs<u16> for Timer<pac::$TIMX> {
1003 // fn delay_ms(&mut self, ms: u16) {
1004 // self.delay_ms(ms as u32)
1005 // }
1006 // }
1007 //
1008 // #[cfg(feature = "embedded_hal")]
1009 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
1010 // impl DelayMs<u8> for Timer<pac::$TIMX> {
1011 // fn delay_ms(&mut self, ms: u8) {
1012 // self.delay_ms(ms as u32)
1013 // }
1014 // }
1015 //
1016 // #[cfg(feature = "embedded_hal")]
1017 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
1018 // impl DelayUs<u32> for Timer<pac::$TIMX> {
1019 // fn delay_us(&mut self, us: u32) {
1020 // let us_to_s = us as f32 / 1_000_000.;
1021 // self.set_freq(1. / (us_to_s)).ok();
1022 // self.reset_count();
1023 // self.enable();
1024 // while self.get_uif() == false {}
1025 // self.clear_uif();
1026 // self.disable();
1027 // }
1028 // }
1029 //
1030 // #[cfg(feature = "embedded_hal")]
1031 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
1032 // impl DelayUs<u16> for Timer<pac::$TIMX> {
1033 // fn delay_us(&mut self, us: u16) {
1034 // self.delay_us(us as u32);
1035 // }
1036 // }
1037 //
1038 // #[cfg(feature = "embedded_hal")]
1039 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
1040 // impl DelayUs<u8> for Timer<pac::$TIMX> {
1041 // fn delay_us(&mut self, us: u8) {
1042 // self.delay_us(us as u32);
1043 // }
1044 // }
1045
1046 // /// Implementation of the embedded-hal CountDown trait
1047 // /// To use Countdown it is prefered to configure new timer in Oneshot mode :
1048 // ///
1049 // /// Example :
1050 // /// llet tim16_conf = TimerConfig {
1051 // /// one_pulse_mode: true,
1052 // /// ..Default::default()
1053 // /// };
1054 // ///
1055 // /// Creation of timer. Here the freq arg value is not important, the freq
1056 // /// will be changed for each CountDown start timer depends on delay wanted.
1057 // ///
1058 // /// let mut tim16: Timer<TIM16> = Timer::new_tim16(dp.TIM16, 1000., tim16_conf, &clocks);
1059 // ///
1060 // ///
1061 // #[cfg(feature = "embedded_hal")]
1062 // impl CountDown for Timer<pac::$TIMX>
1063 // {
1064 // type Time = duration::Generic<u32>;
1065 //
1066 // fn start<T>(&mut self, timeout: T)
1067 // where
1068 // T: Into<Self::Time>,
1069 // {
1070 //
1071 // //Disable timer and clear flag uif
1072 // self.disable();
1073 // self.clear_uif();
1074 //
1075 // //Get timeout
1076 // let timeout: Self::Time = timeout.into();
1077 //
1078 // let denom = timeout.scaling_factor().denominator();
1079 //
1080 // //Prevent a division by zero
1081 // if *denom != 0 {
1082 // //Convert time to seconds
1083 // let time_to_s = timeout.integer() as f32 / *denom as f32;
1084 //
1085 // //Configure timer
1086 // self.set_freq(1. / (time_to_s)).ok();
1087 // self.reset_count();
1088 // //Update event to setup prescale and reload registers
1089 // self.reinitialize();
1090 // self.clear_uif();
1091 //
1092 // //start the timer
1093 // self.enable();
1094 // }
1095 //
1096 // }
1097 //
1098 // /// Wait until the timer has elapsed
1099 // /// and than clear the event.
1100 // fn wait(&mut self) -> nb::Result<(), Void> {
1101 // if !self.get_uif() {
1102 // Err(nb::Error::WouldBlock)
1103 // } else {
1104 // self.clear_uif();
1105 // self.disable();
1106 // Ok(())
1107 // }
1108 // }
1109 // }
1110 }
1111}
1112
1113macro_rules! cc_slave_mode {
1114 ($TIMX:ident) => {
1115 impl Timer<pac::$TIMX> {
1116 /// Set input slave mode and input trigger. See `InputSlaveMode` and `InputTrigger` documentation for more details.
1117 /// Use `set_input_capture` to configure input channels if required.
1118 ///
1119 /// Note: Some modes (e.g. encoder modes) are unavailable on some timers. Consult the reference manual for specifics.
1120 pub fn set_input_slave_mode(
1121 &mut self,
1122 slave_mode: InputSlaveMode,
1123 trigger: InputTrigger,
1124 ) {
1125 self.regs.smcr().modify(|_, w| unsafe {
1126 w.sms().bits(slave_mode as u8).ts().bits(trigger as u8)
1127 });
1128 }
1129 }
1130 };
1131}
1132
1133// We use macros to support the varying number of capture compare channels available on
1134// different timers.
1135// Note that there's lots of DRY between these implementations.
1136macro_rules! cc_4_channels {
1137 ($TIMX:ident, $res:ident) => {
1138 impl Timer<pac::$TIMX> {
1139 /// Function that allows us to set direction only on timers that have this option.
1140 pub fn set_dir(&mut self) {
1141 self.regs
1142 .cr1()
1143 .modify(|_, w| w.dir().bit(self.cfg.direction as u8 != 0));
1144 self.regs
1145 .cr1()
1146 .modify(|_, w| unsafe { w.cms().bits(self.cfg.alignment as u8) });
1147 }
1148
1149 /// Set up input capture, eg for PWM input.
1150 /// L4 RM, section 26.3.8. H723 RM, section 43.3.7.
1151 ///
1152 /// Note: Does not handle TISEL (timer input selection register), ICxPS (input capture prescaler),
1153 /// and ICxF (input capture filter) - you must set these manually using the PAC if hardware defaults are not appropriate.
1154 #[cfg(not(any(
1155 feature = "f",
1156 feature = "l4x5",
1157 feature = "l5",
1158 feature = "g0",
1159 feature = "wb"
1160 )))]
1161 pub fn set_input_capture(
1162 &mut self,
1163 channel: TimChannel,
1164 mode: CaptureCompare,
1165 ccp: Polarity,
1166 ccnp: Polarity,
1167 ) {
1168 // 2. Select the active input for TIMx_CCR1: write the CC1S bits to 01 in the TIMx_CCMR1
1169 // register.
1170 self.set_capture_compare_input(channel, mode);
1171
1172 // 1. Select the proper TI1x source (internal or external) with the TI1SEL[3:0] bits in the
1173 // TIMx_TISEL register.
1174 // Leaving it at its default value of 0 selects the timer input, which we'll hard-code
1175 // for now.
1176 // let tisel = 0b0000;
1177
1178 // 3.
1179 // Program the needed input filter duration in relation with the signal connected to the
1180 // timer (when the input is one of the tim_tix (ICxF bits in the TIMx_CCMRx register). Let’s
1181 // imagine that, when toggling, the input signal is not stable during at must 5 internal clock
1182 // cycles. We must program a filter duration longer than these 5 clock cycles. We can
1183 // validate a transition on tim_ti1 when 8 consecutive samples with the new level have
1184 // been detected (sampled at fDTS frequency). Then write IC1F bits to 0011 in the
1185 // TIMx_CCMR1 register.
1186 // let filter = 0b0000;
1187
1188 match channel {
1189 TimChannel::C1 => {
1190 // self.regs.tisel.modify(|_, w| unsafe { w.ti1sel().bits(tisel) });
1191
1192 // 4. Select the active polarity for TI1FP1 (used both for capture in TIMx_CCR1 and counter
1193 // clear): write the CC1P and CC1NP bits to ‘0’ (active on rising edge).
1194 // (Note: We could use the `set_polarity` and `set_complementary_polarity` methods, but
1195 // this allows us to combine them in a single reg write.)
1196 self.regs.ccer().modify(|_, w| {
1197 w.cc1p().bit(ccp.bit());
1198 w.cc1np().bit(ccnp.bit())
1199 });
1200
1201 // 5.
1202 // Program the input prescaler. In our example, we wish the capture to be performed at
1203 // each valid transition, so the prescaler is disabled (write IC1PS bits to 00 in the
1204 // TIMx_CCMR1 register).
1205 // self.regs.ccmr1_input().modify(|_, w| unsafe {
1206 // // todo: PAC ommission?
1207 // // w.ic1psc().bits(0b00);
1208 // w.ic1f().bits(filter)
1209 // });
1210 }
1211 TimChannel::C2 => {
1212 // self.regs.tisel.modify(|_, w| unsafe { w.ti2sel().bits(tisel) });
1213
1214 self.regs.ccer().modify(|_, w| {
1215 w.cc2p().bit(ccp.bit());
1216 w.cc2np().bit(ccnp.bit())
1217 });
1218
1219 // self.regs.ccmr1_input().modify(|_, w| unsafe {
1220 // w.ic2psc().bits(0b00);
1221 // w.ic2f().bits(filter)
1222 // });
1223 }
1224 TimChannel::C3 => {
1225 // self.regs.tisel.modify(|_, w| unsafe { w.ti3sel().bits(tisel) });
1226
1227 self.regs.ccer().modify(|_, w| {
1228 w.cc3p().bit(ccp.bit());
1229 w.cc3np().bit(ccnp.bit())
1230 });
1231
1232 // self.regs.ccmr2_input().modify(|_, w| unsafe {
1233 // w.ic3psc().bits(0b00);
1234 // w.ic3f().bits(filter)
1235 // });
1236 }
1237 #[cfg(not(feature = "wl"))]
1238 TimChannel::C4 => {
1239 // self.regs.tisel.modify(|_, w| unsafe { w.ti4sel().bits(tisel) });
1240
1241 self.regs.ccer().modify(|_, w| {
1242 #[cfg(not(any(feature = "f4", feature = "l4")))]
1243 w.cc4np().bit(ccnp.bit());
1244 w.cc4p().bit(ccp.bit())
1245 });
1246
1247 // self.regs.ccmr2_input().modify(|_, w| unsafe {
1248 // w.ic4psc().bits(0b00);
1249 // w.ic4f().bits(filter)
1250 // });
1251 }
1252 }
1253
1254 // 6. Enable capture from the counter into the capture register by setting the CC1E bit in the
1255 // TIMx_CCER register.
1256 self.enable_capture_compare(channel);
1257
1258 // 7.If needed, enable the related interrupt request by setting the CC1IE bit in the
1259 // TIMx_DIER register, and/or the DMA request by setting the CC1DE bit in the
1260 // TIMx_DIER register.
1261 }
1262
1263 // todo: more advanced PWM modes. Asymmetric, combined, center-aligned etc.
1264
1265 /// Set Output Compare Mode. See docs on the `OutputCompare` enum.
1266 /// Note: On TIM1 and TIM8, (And others if on C0), you must manually set the `bdtr` register,
1267 /// `moe` bit.
1268 pub fn set_output_compare(&mut self, channel: TimChannel, mode: OutputCompare) {
1269 match channel {
1270 TimChannel::C1 => {
1271 self.regs.ccmr1_output().modify(|_, w| unsafe {
1272 #[cfg(not(any(feature = "f", feature = "l5", feature = "wb")))]
1273 w.oc1m_3().bit((mode as u8) >> 3 != 0);
1274 w.oc1m().bits((mode as u8) & 0b111)
1275 });
1276 }
1277 TimChannel::C2 => {
1278 self.regs.ccmr1_output().modify(|_, w| unsafe {
1279 #[cfg(not(any(feature = "f", feature = "l5", feature = "wb")))]
1280 w.oc2m_3().bit((mode as u8) >> 3 != 0);
1281 w.oc2m().bits((mode as u8) & 0b111)
1282 });
1283 }
1284 TimChannel::C3 => {
1285 self.regs.ccmr2_output().modify(|_, w| unsafe {
1286 #[cfg(not(any(feature = "f", feature = "l5", feature = "wb")))]
1287 w.oc3m_3().bit((mode as u8) >> 3 != 0);
1288 w.oc3m().bits((mode as u8) & 0b111)
1289 });
1290 }
1291 #[cfg(not(feature = "wl"))]
1292 TimChannel::C4 => {
1293 self.regs.ccmr2_output().modify(|_, w| unsafe {
1294 #[cfg(not(any(
1295 feature = "f3",
1296 feature = "f4",
1297 feature = "l5",
1298 feature = "wb",
1299 feature = "h7"
1300 )))]
1301 w.oc4m_3().bit((mode as u8) >> 3 != 0);
1302 w.oc4m().bits((mode as u8) & 0b111)
1303 });
1304 }
1305 }
1306 }
1307
1308 /// Return the set duty period for a given channel. Divide by `get_max_duty()`
1309 /// to find the portion of the duty cycle used.
1310 pub fn get_duty(&self, channel: TimChannel) -> $res {
1311 cfg_if! {
1312 if #[cfg(any(feature = "wb", feature = "wl"))] {
1313 (match channel {
1314 TimChannel::C1 => self.regs.ccr1().read().bits(),
1315 TimChannel::C2 => self.regs.ccr2().read().bits(),
1316 TimChannel::C3 => self.regs.ccr3().read().bits(),
1317 #[cfg(not(feature = "wl"))]
1318 TimChannel::C4 => self.regs.ccr4().read().bits(),
1319 }) as $res
1320 } else {
1321 match channel {
1322 TimChannel::C1 => self.regs.ccr1().read().ccr().bits().into(),
1323 TimChannel::C2 => self.regs.ccr2().read().ccr().bits().into(),
1324 TimChannel::C3 => self.regs.ccr3().read().ccr().bits().into(),
1325 #[cfg(not(feature = "wl"))]
1326 TimChannel::C4 => self.regs.ccr4().read().ccr().bits().into(),
1327 }
1328 }
1329 }
1330 }
1331
1332 /// Set the duty cycle, as a portion of ARR (`get_max_duty()`). Note that this
1333 /// needs to be re-run if you change ARR at any point.
1334 pub fn set_duty(&mut self, channel: TimChannel, duty: $res) {
1335 unsafe {
1336 match channel {
1337 TimChannel::C1 => self
1338 .regs
1339 .ccr1()
1340 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1341 TimChannel::C2 => self
1342 .regs
1343 .ccr2()
1344 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1345 TimChannel::C3 => self
1346 .regs
1347 .ccr3()
1348 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1349 #[cfg(not(feature = "wl"))]
1350 TimChannel::C4 => self
1351 .regs
1352 .ccr4()
1353 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1354 };
1355 }
1356 }
1357
1358 /// Set timer alignment to Edge, or one of 3 center modes.
1359 /// STM32F303 ref man, section 21.4.1:
1360 /// Bits 6:5 CMS: Center-aligned mode selection
1361 /// 00: Edge-aligned mode. The counter counts up or down depending on the direction bit
1362 /// (DIR).
1363 /// 01: Center-aligned mode 1. The counter counts up and down alternatively. Output compare
1364 /// interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are set
1365 /// only when the counter is counting down.
1366 /// 10: Center-aligned mode 2. The counter counts up and down alternatively. Output compare
1367 /// interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are set
1368 /// only when the counter is counting up.
1369 /// 11: Center-aligned mode 3. The counter counts up and down alternatively. Output compare
1370 /// interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are set
1371 /// both when the counter is counting up or down.
1372 pub fn set_alignment(&mut self, alignment: Alignment) {
1373 self.regs
1374 .cr1()
1375 .modify(|_, w| unsafe { w.cms().bits(alignment as u8) });
1376 self.cfg.alignment = alignment;
1377 }
1378
1379 /// Set output polarity. See docs on the `Polarity` enum.
1380 pub fn set_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1381 match channel {
1382 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1p().bit(polarity.bit())),
1383 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2p().bit(polarity.bit())),
1384 TimChannel::C3 => self.regs.ccer().modify(|_, w| w.cc3p().bit(polarity.bit())),
1385 #[cfg(not(feature = "wl"))]
1386 TimChannel::C4 => self.regs.ccer().modify(|_, w| w.cc4p().bit(polarity.bit())),
1387 };
1388 }
1389
1390 /// Set complementary output polarity. See docs on the `Polarity` enum.
1391 pub fn set_complementary_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1392 match channel {
1393 TimChannel::C1 => self
1394 .regs
1395 .ccer()
1396 .modify(|_, w| w.cc1np().bit(polarity.bit())),
1397 TimChannel::C2 => self
1398 .regs
1399 .ccer()
1400 .modify(|_, w| w.cc2np().bit(polarity.bit())),
1401 TimChannel::C3 => self
1402 .regs
1403 .ccer()
1404 .modify(|_, w| w.cc3np().bit(polarity.bit())),
1405 #[cfg(not(any(feature = "f4", feature = "wl", feature = "l4")))]
1406 TimChannel::C4 => self
1407 .regs
1408 .ccer()
1409 .modify(|_, w| w.cc4np().bit(polarity.bit())),
1410 #[cfg(any(feature = "f4", feature = "wl", feature = "l4"))] // PAC ommission
1411 _ => panic!(),
1412 };
1413 }
1414 /// Disables capture compare on a specific channel.
1415 pub fn disable_capture_compare(&mut self, channel: TimChannel) {
1416 match channel {
1417 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().clear_bit()),
1418 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2e().clear_bit()),
1419 TimChannel::C3 => self.regs.ccer().modify(|_, w| w.cc3e().clear_bit()),
1420 #[cfg(not(feature = "wl"))]
1421 TimChannel::C4 => self.regs.ccer().modify(|_, w| w.cc4e().clear_bit()),
1422 };
1423 }
1424
1425 /// Enables capture compare on a specific channel.
1426 pub fn enable_capture_compare(&mut self, channel: TimChannel) {
1427 match channel {
1428 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().bit(true)),
1429 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2e().bit(true)),
1430 TimChannel::C3 => self.regs.ccer().modify(|_, w| w.cc3e().bit(true)),
1431 #[cfg(not(feature = "wl"))]
1432 TimChannel::C4 => self.regs.ccer().modify(|_, w| w.cc4e().bit(true)),
1433 };
1434 }
1435
1436 /// Set Capture Compare mode in output mode. See docs on the `CaptureCompare` enum.
1437 pub fn set_capture_compare_output(
1438 &mut self,
1439 channel: TimChannel,
1440 mode: CaptureCompare,
1441 ) {
1442 // Note: CC1S bits are writable only when the channel is OFF (CC1E = 0 in TIMx_CCER)
1443 self.disable_capture_compare(channel);
1444
1445 match channel {
1446 TimChannel::C1 => self
1447 .regs
1448 .ccmr1_output()
1449 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1450 TimChannel::C2 => self
1451 .regs
1452 .ccmr1_output()
1453 .modify(unsafe { |_, w| w.cc2s().bits(mode as u8) }),
1454 TimChannel::C3 => self
1455 .regs
1456 .ccmr2_output()
1457 .modify(unsafe { |_, w| w.cc3s().bits(mode as u8) }),
1458 #[cfg(not(feature = "wl"))]
1459 TimChannel::C4 => self
1460 .regs
1461 .ccmr2_output()
1462 .modify(unsafe { |_, w| w.cc4s().bits(mode as u8) }),
1463 };
1464 }
1465
1466 /// Set Capture Compare mode in input mode. See docs on the `CaptureCompare` enum.
1467 pub fn set_capture_compare_input(&mut self, channel: TimChannel, mode: CaptureCompare) {
1468 // Note: CC1S bits are writable only when the channel is OFF (CC1E = 0 in TIMx_CCER)
1469 self.disable_capture_compare(channel);
1470
1471 match channel {
1472 TimChannel::C1 => self
1473 .regs
1474 .ccmr1_input()
1475 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1476 TimChannel::C2 => self
1477 .regs
1478 .ccmr1_input()
1479 .modify(unsafe { |_, w| w.cc2s().bits(mode as u8) }),
1480 TimChannel::C3 => self
1481 .regs
1482 .ccmr2_input()
1483 .modify(unsafe { |_, w| w.cc3s().bits(mode as u8) }),
1484 #[cfg(not(feature = "wl"))]
1485 TimChannel::C4 => self
1486 .regs
1487 .ccmr2_input()
1488 .modify(unsafe { |_, w| w.cc4s().bits(mode as u8) }),
1489 };
1490 }
1491
1492 /// Set preload mode.
1493 /// OC1PE: Output Compare 1 preload enable
1494 /// 0: Preload register on TIMx_CCR1 disabled. TIMx_CCR1 can be written at anytime, the
1495 /// new value is taken in account immediately.
1496 /// 1: Preload register on TIMx_CCR1 enabled. Read/Write operations access the preload
1497 /// register. TIMx_CCR1 preload value is loaded in the active register at each update event.
1498 /// Note: 1: These bits can not be modified as long as LOCK level 3 has been programmed
1499 /// (LOCK bits in TIMx_BDTR register) and CC1S=’00’ (the channel is configured in
1500 /// output).
1501 /// 2: The PWM mode can be used without validating the preload register only in one
1502 /// pulse mode (OPM bit set in TIMx_CR1 register). Else the behavior is not guaranteed.
1503 ///
1504 /// Setting preload is required to enable PWM.
1505 pub fn set_preload(&mut self, channel: TimChannel, value: bool) {
1506 match channel {
1507 TimChannel::C1 => self.regs.ccmr1_output().modify(|_, w| w.oc1pe().bit(value)),
1508 TimChannel::C2 => self.regs.ccmr1_output().modify(|_, w| w.oc2pe().bit(value)),
1509 TimChannel::C3 => self.regs.ccmr2_output().modify(|_, w| w.oc3pe().bit(value)),
1510 #[cfg(not(feature = "wl"))]
1511 TimChannel::C4 => self.regs.ccmr2_output().modify(|_, w| w.oc4pe().bit(value)),
1512 };
1513
1514 // "As the preload registers are transferred to the shadow registers only when an update event
1515 // occurs, before starting the counter, you have to initialize all the registers by setting the UG
1516 // bit in the TIMx_EGR register."
1517 self.reinitialize();
1518 }
1519 }
1520 };
1521}
1522
1523#[cfg(any(feature = "g0", feature = "g4", feature = "c0"))]
1524macro_rules! cc_2_channels {
1525 ($TIMX:ident, $res:ident) => {
1526 impl Timer<pac::$TIMX> {
1527 /// Function that allows us to set direction only on timers that have this option.
1528 fn set_dir(&mut self) {
1529 // self.regs.cr1().modify(|_, w| w.dir().bit(self.cfg.direction as u8 != 0));
1530 }
1531
1532 // todo: more advanced PWM modes. Asymmetric, combined, center-aligned etc.
1533
1534 /// Set up input capture, eg for PWM input.
1535 /// L4 RM, section 26.3.8. H723 RM, section 43.3.7.
1536 ///
1537 /// Note: Does not handle TISEL (timer input selection register), ICxPS (input capture prescaler),
1538 /// and ICxF (input capture filter) - you must set these manually using the PAC if hardware defaults are not appropriate.
1539 #[cfg(not(any(feature = "f", feature = "l4x5", feature = "l5", feature = "g0")))]
1540 pub fn set_input_capture(
1541 &mut self,
1542 channel: TimChannel,
1543 mode: CaptureCompare,
1544 ccp: Polarity,
1545 ccnp: Polarity,
1546 ) {
1547 self.set_capture_compare_input(channel, mode);
1548
1549 match channel {
1550 TimChannel::C1 => {
1551 self.regs.ccer().modify(|_, w| {
1552 w.cc1p().bit(ccp.bit());
1553 w.cc1np().bit(ccnp.bit())
1554 });
1555 }
1556 TimChannel::C2 => {
1557 #[cfg(not(feature = "c0"))]
1558 self.regs.ccer().modify(|_, w| {
1559 w.cc2p().bit(ccp.bit());
1560 w.cc2np().bit(ccnp.bit())
1561 });
1562 }
1563 _ => panic!()
1564 }
1565
1566 // self.regs.smcr().modify(|_, w| unsafe {
1567 // w.ts().bits(trigger as u8);
1568 // w.sms().bits(slave_mode as u8)
1569 // });
1570
1571 self.enable_capture_compare(channel);
1572 }
1573
1574 /// Set Output Compare Mode. See docs on the `OutputCompare` enum.
1575 /// Note: On TIM1 and TIM8, (And others if on C0), you must manually set the `bdtr` register,
1576 /// `moe` bit.
1577 pub fn set_output_compare(&mut self, channel: TimChannel, mode: OutputCompare) {
1578 match channel {
1579 TimChannel::C1 => {
1580 self.regs.ccmr1_output().modify(|_, w| unsafe {
1581 #[cfg(not(any(feature = "f4", feature = "l5", feature = "wb")))]
1582 w.oc1m_3().bit((mode as u8) >> 3 != 0);
1583 w.oc1m().bits((mode as u8) & 0b111)
1584
1585 });
1586 }
1587 TimChannel::C2 => {
1588 self.regs.ccmr1_output().modify(|_, w| unsafe {
1589 #[cfg(not(any(feature = "f4", feature = "l5", feature = "wb")))]
1590 w.oc2m_3().bit((mode as u8) >> 3 != 0);
1591 w.oc2m().bits((mode as u8) & 0b111)
1592
1593 });
1594 }
1595 _ => panic!()
1596 }
1597 }
1598
1599 /// Return the set duty period for a given channel. Divide by `get_max_duty()`
1600 /// to find the portion of the duty cycle used.
1601 pub fn get_duty(&self, channel: TimChannel) -> $res {
1602 cfg_if! {
1603 if #[cfg(feature = "g0")] {
1604 match channel {
1605 TimChannel::C1 => self.regs.ccr1().read().bits().try_into().unwrap(),
1606 TimChannel::C2 => self.regs.ccr2().read().bits().try_into().unwrap(),
1607 _ => panic!()
1608 }
1609 } else if #[cfg(any(feature = "wb", feature = "wl", feature = "l5"))] {
1610 match channel {
1611 TimChannel::C1 => self.regs.ccr1().read().ccr1().bits(),
1612 TimChannel::C2 => self.regs.ccr2().read().ccr2().bits(),
1613 _ => panic!()
1614 }
1615 } else {
1616 match channel {
1617 TimChannel::C1 => self.regs.ccr1().read().ccr().bits().try_into().unwrap(),
1618 TimChannel::C2 => self.regs.ccr2().read().ccr().bits().try_into().unwrap(),
1619 _ => panic!()
1620 }
1621 }
1622 }
1623 }
1624
1625 /// Set the duty cycle, as a portion of ARR (`get_max_duty()`). Note that this
1626 /// needs to be re-run if you change ARR at any point.
1627 pub fn set_duty(&mut self, channel: TimChannel, duty: $res) {
1628 cfg_if! {
1629 if #[cfg(feature = "g0")] {
1630 match channel {
1631 // TimChannel::C1 => self.regs.ccr1().write(|w| w.ccr1().bits(duty.try_into().unwrap())),
1632 // TimChannel::C2 => self.regs.ccr2().write(|w| w.ccr2().bits(duty.try_into().unwrap())),
1633 _ => panic!()
1634 };
1635 } else if #[cfg(any(feature = "wb", feature = "wl", feature = "l5"))] {
1636 unsafe {
1637 match channel {
1638 TimChannel::C1 => self.regs.ccr1().write(|w| w.ccr1().bits(duty.try_into().unwrap())),
1639 TimChannel::C2 => self.regs.ccr2().write(|w| w.ccr2().bits(duty.try_into().unwrap())),
1640 _ => panic!()
1641 };
1642 }
1643 } else {
1644 unsafe {
1645 match channel {
1646 TimChannel::C1 => self.regs.ccr1().write(|w| w.ccr().bits(duty.try_into().unwrap())),
1647 TimChannel::C2 => self.regs.ccr2().write(|w| w.ccr().bits(duty.try_into().unwrap())),
1648 _ => panic!()
1649 };
1650 }
1651 }
1652 }
1653 }
1654
1655 /// Set output polarity. See docs on the `Polarity` enum.
1656 pub fn set_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1657 match channel {
1658 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1p().bit(polarity.bit())),
1659 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2p().bit(polarity.bit())),
1660 _ => panic!()
1661 };
1662 }
1663
1664 /// Set complementary output polarity. See docs on the `Polarity` enum.
1665 pub fn set_complementary_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1666 match channel {
1667 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1np().bit(polarity.bit())),
1668 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2np().bit(polarity.bit())),
1669 _ => panic!()
1670 };
1671 }
1672 /// Disables capture compare on a specific channel.
1673 pub fn disable_capture_compare(&mut self, channel: TimChannel) {
1674 match channel {
1675 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().clear_bit()),
1676 #[cfg(not(feature = "c0"))]
1677 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2e().clear_bit()),
1678 _ => panic!()
1679 };
1680 }
1681
1682 /// Enables capture compare on a specific channel.
1683 pub fn enable_capture_compare(&mut self, channel: TimChannel) {
1684 match channel {
1685 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().bit(true)),
1686 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2e().bit(true)),
1687 _ => panic!()
1688 };
1689 }
1690
1691 /// Set Capture Compare mode in output mode. See docs on the `CaptureCompare` enum.
1692 pub fn set_capture_compare_output(&mut self, channel: TimChannel, mode: CaptureCompare) {
1693 self.disable_capture_compare(channel);
1694
1695 match channel {
1696 TimChannel::C1 => self
1697 .regs
1698 .ccmr1_output()
1699 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1700 #[cfg(not(feature = "c0"))]
1701 TimChannel::C2 => self
1702 .regs
1703 .ccmr1_output()
1704 .modify(unsafe { |_, w| w.cc2s().bits(mode as u8) }),
1705 _ => panic!()
1706 };
1707 }
1708
1709 /// Set Capture Compare mode in input mode. See docs on the `CaptureCompare` enum.
1710 pub fn set_capture_compare_input(&mut self, channel: TimChannel, mode: CaptureCompare) {
1711 self.disable_capture_compare(channel);
1712
1713 match channel {
1714 // Note: CC1S bits are writable only when the channel is OFF (CC1E = 0 in TIMx_CCER)
1715 TimChannel::C1 => self
1716 .regs
1717 .ccmr1_input()
1718 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1719
1720 #[cfg(not(feature = "c0"))]
1721 TimChannel::C2 => self
1722 .regs
1723 .ccmr1_input()
1724 .modify(unsafe { |_, w| w.cc2s().bits(mode as u8) }),
1725 _ => panic!()
1726 };
1727 }
1728
1729 /// Set preload mode.
1730 /// OC1PE: Output Compare 1 preload enable
1731 /// 0: Preload register on TIMx_CCR1 disabled. TIMx_CCR1 can be written at anytime, the
1732 /// new value is taken in account immediately.
1733 /// 1: Preload register on TIMx_CCR1 enabled. Read/Write operations access the preload
1734 /// register. TIMx_CCR1 preload value is loaded in the active register at each update event.
1735 /// Note: 1: These bits can not be modified as long as LOCK level 3 has been programmed
1736 /// (LOCK bits in TIMx_BDTR register) and CC1S=’00’ (the channel is configured in
1737 /// output).
1738 /// 2: The PWM mode can be used without validating the preload register only in one
1739 /// pulse mode (OPM bit set in TIMx_CR1 register). Else the behavior is not guaranteed.
1740 ///
1741 /// Setting preload is required to enable PWM.
1742 pub fn set_preload(&mut self, channel: TimChannel, value: bool) {
1743 match channel {
1744 TimChannel::C1 => self.regs.ccmr1_output().modify(|_, w| w.oc1pe().bit(value)),
1745 #[cfg(not(feature = "c0"))]
1746 TimChannel::C2 => self.regs.ccmr1_output().modify(|_, w| w.oc2pe().bit(value)),
1747 _ => panic!()
1748 };
1749
1750 // "As the preload registers are transferred to the shadow registers only when an update event
1751 // occurs, before starting the counter, you have to initialize all the registers by setting the UG
1752 // bit in the TIMx_EGR register."
1753 self.reinitialize();
1754 }
1755
1756 }
1757 }
1758}
1759
1760macro_rules! cc_1_channel {
1761 ($TIMX:ident, $res:ident) => {
1762 impl Timer<pac::$TIMX> {
1763 /// Function that allows us to set direction only on timers that have this option.
1764 fn set_dir(&mut self) {} // N/A with these 1-channel timers.
1765
1766 // todo: more advanced PWM modes. Asymmetric, combined, center-aligned etc.
1767
1768 /// Set up input capture, eg for PWM input.
1769 /// L4 RM, section 26.3.8. H723 RM, section 43.3.7.
1770 ///
1771 /// Note: Does not handle TISEL (timer input selection register), ICxPS (input capture prescaler),
1772 /// and ICxF (input capture filter) - you must set these manually using the PAC if hardware defaults are not appropriate.
1773 #[cfg(not(any(feature = "f", feature = "l4x5", feature = "l5", feature = "g0")))]
1774 pub fn set_input_capture(
1775 &mut self,
1776 channel: TimChannel,
1777 mode: CaptureCompare,
1778 ccp: Polarity,
1779 ccnp: Polarity,
1780 ) {
1781 self.set_capture_compare_input(channel, mode);
1782
1783 match channel {
1784 TimChannel::C1 => {
1785 self.regs.ccer().modify(|_, w| {
1786 w.cc1p().bit(ccp.bit());
1787 w.cc1np().bit(ccnp.bit())
1788 });
1789 }
1790 _ => panic!(),
1791 };
1792
1793 self.enable_capture_compare(channel);
1794 }
1795
1796 /// Set Output Compare Mode. See docs on the `OutputCompare` enum.
1797 /// Note: On TIM1 and TIM8, (And others if on C0), you must manually set the `bdtr` register,
1798 /// `moe` bit.
1799 pub fn set_output_compare(&mut self, channel: TimChannel, mode: OutputCompare) {
1800 match channel {
1801 TimChannel::C1 => {
1802 #[cfg(not(feature = "g070"))] // todo: PAC bug?
1803 self.regs.ccmr1_output().modify(|_, w| unsafe {
1804 // todo: L5/WB is probably due to a PAC error. Has oc1m_2.
1805 #[cfg(not(any(
1806 feature = "f",
1807 feature = "l4",
1808 feature = "l5",
1809 feature = "wb",
1810 feature = "g0"
1811 )))]
1812 w.oc1m_3().bit((mode as u8) >> 3 != 0);
1813 w.oc1m().bits((mode as u8) & 0b111)
1814 });
1815 }
1816 _ => panic!(),
1817 };
1818 }
1819
1820 /// Return the set duty period for a given channel. Divide by `get_max_duty()`
1821 /// to find the portion of the duty cycle used.
1822 pub fn get_duty(&self, channel: TimChannel) -> $res {
1823 match channel {
1824 TimChannel::C1 => self.regs.ccr1().read().ccr().bits().try_into().unwrap(),
1825 _ => panic!(),
1826 }
1827 }
1828
1829 /// Set the duty cycle, as a portion of ARR (`get_max_duty()`). Note that this
1830 /// needs to be re-run if you change ARR at any point.
1831 pub fn set_duty(&mut self, channel: TimChannel, duty: $res) {
1832 unsafe {
1833 match channel {
1834 TimChannel::C1 => self
1835 .regs
1836 .ccr1()
1837 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1838 _ => panic!(),
1839 };
1840 }
1841 }
1842
1843 /// Set output polarity. See docs on the `Polarity` enum.
1844 pub fn set_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1845 match channel {
1846 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1p().bit(polarity.bit())),
1847 _ => panic!(),
1848 };
1849 }
1850
1851 /// Set complementary output polarity. See docs on the `Polarity` enum.
1852 pub fn set_complementary_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1853 match channel {
1854 TimChannel::C1 => self
1855 .regs
1856 .ccer()
1857 .modify(|_, w| w.cc1np().bit(polarity.bit())),
1858 _ => panic!(),
1859 };
1860 }
1861 /// Disables capture compare on a specific channel.
1862 pub fn disable_capture_compare(&mut self, channel: TimChannel) {
1863 match channel {
1864 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().clear_bit()),
1865 _ => panic!(),
1866 };
1867 }
1868
1869 /// Enables capture compare on a specific channel.
1870 pub fn enable_capture_compare(&mut self, channel: TimChannel) {
1871 match channel {
1872 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().bit(true)),
1873 _ => panic!(),
1874 };
1875 }
1876
1877 /// Set Capture Compare mode in output mode. See docs on the `CaptureCompare` enum.
1878 pub fn set_capture_compare_output(
1879 &mut self,
1880 channel: TimChannel,
1881 mode: CaptureCompare,
1882 ) {
1883 self.disable_capture_compare(channel);
1884
1885 match channel {
1886 TimChannel::C1 => self
1887 .regs
1888 .ccmr1_output()
1889 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1890 _ => panic!(),
1891 };
1892 }
1893
1894 /// Set Capture Compare mode in input mode. See docs on the `CaptureCompare` enum.
1895 pub fn set_capture_compare_input(&mut self, channel: TimChannel, mode: CaptureCompare) {
1896 self.disable_capture_compare(channel);
1897
1898 match channel {
1899 TimChannel::C1 => self
1900 .regs
1901 .ccmr1_input()
1902 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1903 _ => panic!(),
1904 };
1905 }
1906
1907 /// Set preload mode.
1908 /// OC1PE: Output Compare 1 preload enable
1909 /// 0: Preload register on TIMx_CCR1 disabled. TIMx_CCR1 can be written at anytime, the
1910 /// new value is taken in account immediately.
1911 /// 1: Preload register on TIMx_CCR1 enabled. Read/Write operations access the preload
1912 /// register. TIMx_CCR1 preload value is loaded in the active register at each update event.
1913 /// Note: 1: These bits can not be modified as long as LOCK level 3 has been programmed
1914 /// (LOCK bits in TIMx_BDTR register) and CC1S=’00’ (the channel is configured in
1915 /// output).
1916 /// 2: The PWM mode can be used without validating the preload register only in one
1917 /// pulse mode (OPM bit set in TIMx_CR1 register). Else the behavior is not guaranteed.
1918 ///
1919 /// Setting preload is required to enable PWM.
1920 pub fn set_preload(&mut self, channel: TimChannel, value: bool) {
1921 match channel {
1922 TimChannel::C1 => self.regs.ccmr1_output().modify(|_, w| w.oc1pe().bit(value)),
1923 _ => panic!(),
1924 };
1925
1926 // "As the preload registers are transferred to the shadow registers only when an update event
1927 // occurs, before starting the counter, you have to initialize all the registers by setting the UG
1928 // bit in the TIMx_EGR register."
1929 self.reinitialize();
1930 }
1931 }
1932 };
1933}
1934
1935/// Calculate values required to set the timer frequency: `PSC` and `ARR`. This can be
1936/// used for initial timer setup, or changing the value later. If used in performance-sensitive
1937/// code or frequently, set ARR and PSC directly instead of using this.
1938fn calc_freq_vals(freq: f32, clock_speed: u32) -> Result<(u16, u16)> {
1939 // `period` and `clock_speed` are both in Hz.
1940
1941 // PSC and ARR range: 0 to 65535
1942 // (PSC+1)*(ARR+1) = TIMclk/Updatefrequency = TIMclk * period
1943 // APB1 (pclk1) is used by Tim2, 3, 4, 6, 7.
1944 // APB2 (pclk2) is used by Tim8, 15-20 etc.
1945
1946 // We need to factor the right-hand-side of the above equation
1947 // into integers. There are likely clever algorithms available to do this.
1948 // Some examples: https://cp-algorithms.com/algebra/factorization.html
1949 // We've chosen something that attempts to maximize ARR, for precision when
1950 // setting duty cycle. Alternative approaches might involve setting a frequency closest to the
1951 // requested one.
1952
1953 // If you work with pure floats, there are an infinite number of solutions: Ie for any value of PSC,
1954 // you can find an ARR to solve the equation.
1955 // The actual values are integers that must be between 0 and 65_536
1956 // Different combinations will result in different amounts of rounding error.
1957
1958 let max_val = 65_535.;
1959 let rhs = clock_speed as f32 / freq;
1960
1961 let psc = ((rhs - 1.) / (1 << 16) as f32).round();
1962 let arr = rhs / (psc + 1.) - 1.;
1963
1964 if arr > max_val || psc > max_val {
1965 return Err(Error::TimerError(TimerError::ValueError));
1966 }
1967
1968 Ok((psc as u16, arr as u16))
1969}
1970
1971cfg_if! {
1972 if #[cfg(not(any(
1973 feature = "f401",
1974 feature = "f410",
1975 feature = "f411",
1976 feature = "f413",
1977 feature = "g031",
1978 feature = "g041",
1979 feature = "g070",
1980 feature = "g030",
1981 feature = "g051",
1982 feature = "c0",
1983 feature = "wb",
1984 feature = "wl"
1985 )))] {
1986 /// Represents a Basic timer, used primarily to trigger the onboard DAC. Eg Tim6 or Tim7.
1987 pub struct BasicTimer<R> {
1988 pub regs: R,
1989 clock_speed: u32,
1990 }
1991
1992 impl<R> BasicTimer<R>
1993 where
1994 R: Deref<Target = pac::tim6::RegisterBlock> + RccPeriph,
1995 {
1996 /// Initialize a Basic timer, including enabling and resetting
1997 /// its RCC peripheral clock.
1998 pub fn new(
1999 regs: R,
2000 freq: f32,
2001 clock_cfg: &Clocks,
2002 ) -> Self {
2003 let rcc = unsafe { &(*RCC::ptr()) };
2004 R::en_reset(rcc);
2005
2006 // Self { regs, config, clock_speed: clocks.apb1_timer() }
2007 let mut result = Self { regs, clock_speed: clock_cfg.apb1_timer() };
2008
2009 result.set_freq(freq).ok();
2010 result
2011 }
2012
2013 // todo: These fns are DRY from GP timer code!
2014
2015 /// Enable the timer.
2016 pub fn enable(&mut self) {
2017 self.regs.cr1().modify(|_, w| w.cen().bit(true));
2018 }
2019
2020 /// Disable the timer.
2021 pub fn disable(&mut self) {
2022 self.regs.cr1().modify(|_, w| w.cen().clear_bit());
2023 }
2024
2025 /// Check if the timer is enabled.
2026 pub fn is_enabled(&self) -> bool {
2027 self.regs.cr1().read().cen().bit_is_set()
2028 }
2029
2030 /// Set the timer period, in seconds. Overrides the period or frequency set
2031 /// in the constructor. If changing pe riod frequently, don't use this method, as
2032 /// it has computational overhead: use `set_auto_reload` and `set_prescaler` methods instead.
2033 pub fn set_period(&mut self, time: f32) -> Result<() > {
2034 assert!(time > 0.);
2035 self.set_freq(1. / time)
2036 }
2037
2038 /// Set the timer frequency, in Hz. Overrides the period or frequency set
2039 /// in the constructor. If changing frequency frequently, don't use this method, as
2040 /// it has computational overhead: use `set_auto_reload` and `set_prescaler` methods instead.
2041 pub fn set_freq(&mut self, freq: f32) -> Result<() > {
2042 assert!(freq > 0.);
2043
2044 let (psc, arr) = calc_freq_vals(freq, self.clock_speed)?;
2045
2046 self.regs.arr().write(|w| unsafe { w.bits(arr.into()) });
2047 self.regs.psc().write(|w| unsafe { w.bits(psc.into()) });
2048
2049 Ok(())
2050 }
2051
2052 /// Return the integer associated with the maximum duty period.
2053 pub fn get_max_duty(&self) -> u32 {
2054 return self.regs.arr().read().bits()
2055 }
2056
2057 /// Set the auto-reload register value. Used for adjusting frequency.
2058 pub fn set_auto_reload(&mut self, arr: u16) {
2059 self.regs.arr().write(|w| unsafe { w.bits(arr.into()) });
2060 }
2061
2062 /// Set the prescaler value. Used for adjusting frequency.
2063 pub fn set_prescaler(&mut self, psc: u16) {
2064 self.regs.psc().write(|w| unsafe { w.bits(psc.into()) });
2065 }
2066
2067 /// Reset the count; set the counter to 0.
2068 pub fn reset_count(&mut self) {
2069 self.regs.cnt().write(|w| unsafe { w.bits(0) });
2070 }
2071
2072 /// Read the current counter value.
2073 pub fn read_count(&self) -> u16 {
2074 #[cfg(feature = "l5")]
2075 return self.regs.cnt().read().bits() as u16;
2076 #[cfg(not(feature = "l5"))]
2077 self.regs.cnt().read().cnt().bits()
2078 }
2079
2080 /// Allow selected information to be sent in master mode to slave timers for
2081 /// synchronization (TRGO).
2082 pub fn set_mastermode(&self, mode: MasterModeSelection) {
2083 self.regs.cr2().modify(|_, w| unsafe { w.mms().bits(mode as u8) });
2084 }
2085 }
2086 }
2087}
2088
2089/// A freestanding function that does not require access to a `Timer` struct. Clears the Update interrupt.
2090pub fn clear_update_interrupt(tim_num: u8) {
2091 unsafe {
2092 let periphs = pac::Peripherals::steal();
2093
2094 let bits = 0xffff_ffff;
2095
2096 // Note: `.try_into().unwrap()` is for C0.
2097
2098 match tim_num {
2099 #[cfg(not(any(feature = "f373")))]
2100 1 => {
2101 periphs.TIM1.sr().write(|w| w.bits(bits).uif().clear_bit());
2102 }
2103 #[cfg(not(any(
2104 feature = "f410",
2105 feature = "g070",
2106 feature = "g030",
2107 feature = "g031",
2108 feature = "g050",
2109 feature = "g061",
2110 feature = "c011",
2111 feature = "c031",
2112 )))]
2113 2 => {
2114 periphs
2115 .TIM2
2116 .sr()
2117 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2118 }
2119 #[cfg(not(any(
2120 feature = "f301",
2121 feature = "l4x1",
2122 // feature = "l412",
2123 feature = "l4x3",
2124 feature = "l412",
2125 feature = "f410",
2126 feature = "wb",
2127 feature = "wl"
2128 )))]
2129 3 => {
2130 periphs
2131 .TIM3
2132 .sr()
2133 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2134 }
2135 #[cfg(not(any(
2136 feature = "f301",
2137 feature = "f3x4",
2138 feature = "f410",
2139 feature = "l4x1",
2140 feature = "l4x2",
2141 feature = "l412",
2142 feature = "l4x3",
2143 feature = "g0",
2144 feature = "c0",
2145 feature = "wb",
2146 feature = "wl"
2147 )))]
2148 4 => {
2149 periphs.TIM4.sr().write(|w| w.bits(bits).uif().clear_bit());
2150 }
2151 #[cfg(any(
2152 feature = "f373",
2153 feature = "l4x5",
2154 feature = "l4x6",
2155 feature = "l5",
2156 feature = "h5",
2157 feature = "h7",
2158 feature = "g473",
2159 feature = "g474",
2160 feature = "g483",
2161 feature = "g484",
2162 all(feature = "f4", not(feature = "f410")),
2163 ))]
2164 5 => {
2165 periphs.TIM5.sr().write(|w| w.bits(bits).uif().clear_bit());
2166 }
2167 #[cfg(any(
2168 feature = "f303",
2169 feature = "l4x5",
2170 feature = "l4x6",
2171 feature = "l562",
2172 feature = "h5",
2173 feature = "h7",
2174 ))]
2175 8 => {
2176 periphs.TIM8.sr().write(|w| w.bits(bits).uif().clear_bit());
2177 }
2178 #[cfg(any(feature = "h5",))]
2179 12 => {
2180 periphs.TIM12.sr().write(|w| w.bits(bits).uif().clear_bit());
2181 }
2182 #[cfg(any(feature = "h5",))]
2183 13 => {
2184 periphs.TIM13.sr().write(|w| w.bits(bits).uif().clear_bit());
2185 }
2186 #[cfg(any(feature = "h5", feature = "c0",))]
2187 14 => {
2188 periphs
2189 .TIM14
2190 .sr()
2191 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2192 }
2193 #[cfg(not(any(
2194 feature = "f4",
2195 feature = "g031",
2196 feature = "g031",
2197 feature = "g041",
2198 feature = "g030",
2199 feature = "g051",
2200 feature = "g061",
2201 feature = "wb",
2202 feature = "wl",
2203 feature = "c0",
2204 )))]
2205 15 => {
2206 periphs
2207 .TIM15
2208 .sr()
2209 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2210 }
2211 #[cfg(not(any(feature = "f4",)))]
2212 16 => {
2213 periphs
2214 .TIM16
2215 .sr()
2216 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2217 }
2218 #[cfg(not(any(
2219 feature = "l4x1",
2220 feature = "l4x2",
2221 feature = "l412",
2222 feature = "l4x3",
2223 feature = "f4",
2224 )))]
2225 17 => {
2226 periphs
2227 .TIM17
2228 .sr()
2229 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2230 }
2231 _ => unimplemented!(),
2232 }
2233 };
2234}
2235
2236// /// Experimental approach where we set frequency without taking ownership.
2237// pub fn set_freq(timer: TimerNum, mut freq: f32) -> Result<(), ValueError> {
2238//
2239// }
2240
2241// todo: Non-macro refactor base timer reg blocks:
2242
2243// GP 32-bit: Tim2
2244// 2, 3, 4, 5
2245
2246// GP 16-bit:
2247// 15, 16, 17 // (9-14 on F4) 14 on G0
2248
2249// Basic:
2250// 6, 7
2251
2252// Advanced: 1/8/20
2253
2254#[cfg(not(any(feature = "f373")))]
2255make_timer!(TIM1, tim1, 2, u16);
2256
2257#[cfg(not(any(feature = "f373")))]
2258cc_slave_mode!(TIM1);
2259
2260#[cfg(not(any(feature = "f373", feature = "g0", feature = "g4")))]
2261cc_4_channels!(TIM1, u16);
2262// todo: PAC error?
2263// TIM1 on G4 is nominally 16-bits, but has ~20 bits on ARR, with PAC showing 32 bits?
2264#[cfg(any(feature = "g0", feature = "g4"))]
2265cc_2_channels!(TIM1, u16);
2266
2267cfg_if! {
2268 if #[cfg(not(any(
2269 feature = "f410",
2270 feature = "g070",
2271 feature = "l5", // todo PAC bug?
2272 feature = "wb55", // todo PAC bug?
2273 feature = "g030",
2274 feature = "g031",
2275 feature = "g050",
2276 feature = "g061",
2277 feature = "g031",
2278 feature = "c011",
2279 feature = "c031",
2280 )))] {
2281 make_timer!(TIM2, tim2, 1, u32);
2282 cc_slave_mode!(TIM2);
2283 cc_4_channels!(TIM2, u32);
2284 }
2285}
2286
2287// todo: Note. G4, for example, has TIM2 and 5 as 32-bit, and TIM3 and 4 as 16-bit per RM,
2288// todo: But PAC shows different.
2289cfg_if! {
2290 if #[cfg(not(any(
2291 feature = "f301",
2292 feature = "l4x1",
2293 // feature = "l412",
2294 feature = "l5", // todo PAC bug?
2295 feature = "l4x3",
2296 feature = "l412",
2297 feature = "f410",
2298 feature = "wb",
2299 feature = "wl",
2300 )))] {
2301 make_timer!(TIM3, tim3, 1, u32);
2302 cc_slave_mode!(TIM3);
2303 cc_4_channels!(TIM3, u32);
2304 }
2305}
2306
2307cfg_if! {
2308 if #[cfg(not(any(
2309 feature = "f301",
2310 feature = "f3x4",
2311 feature = "f410",
2312 feature = "l4x1",
2313 feature = "l4x2",
2314 feature = "l412",
2315 feature = "l4x3",
2316 feature = "g0",
2317 feature = "c0",
2318 feature = "wb",
2319 feature = "wl"
2320 )))] {
2321 make_timer!(TIM4, tim4, 1, u32);
2322 cc_slave_mode!(TIM4);
2323 cc_4_channels!(TIM4, u32);
2324 }
2325}
2326
2327cfg_if! {
2328 if #[cfg(any(
2329 feature = "f373",
2330 feature = "l4x5",
2331 feature = "l4x6",
2332 feature = "l562",
2333 feature = "h5",
2334 feature = "h7",
2335 feature = "g473",
2336 feature = "g474",
2337 feature = "g483",
2338 feature = "g484",
2339 all(feature = "f4", not(feature = "f410")),
2340 ))] {
2341 make_timer!(TIM5, tim5, 1, u32);
2342 cc_slave_mode!(TIM5);
2343 cc_4_channels!(TIM5, u32);
2344 }
2345}
2346
2347cfg_if! {
2348 if #[cfg(any(
2349 feature = "f303",
2350 feature = "l4x5",
2351 feature = "l4x6",
2352 feature = "l562",
2353 feature = "h5",
2354 feature = "h7",
2355 ))] {
2356 make_timer!(TIM8, tim8, 2, u16);
2357 cc_slave_mode!(TIM8);
2358 cc_4_channels!(TIM8, u16);
2359 }
2360}
2361
2362// todo: G4 should be 16-bits for TIM8. Why does the PAC use 32?
2363cfg_if! {
2364 if #[cfg(feature = "g4")] {
2365 make_timer!(TIM8, tim8, 2, u32);
2366 cc_slave_mode!(TIM8);
2367 cc_4_channels!(TIM8, u32);
2368 }
2369}
2370
2371cfg_if! {
2372 if #[cfg(feature = "h5")] {
2373 make_timer!(TIM12, tim12, 1, u32);
2374 cc_slave_mode!(TIM12);
2375 cc_2_channels!(TIM12, u32);
2376
2377 make_timer!(TIM13, tim13, 1, u32);
2378 cc_2_channels!(TIM13, u32);
2379
2380 make_timer!(TIM14, tim14, 1, u32);
2381 cc_2_channels!(TIM14, u32);
2382 }
2383}
2384
2385cfg_if! {
2386 if #[cfg(not(any(
2387 feature = "f4",
2388 feature = "g031",
2389 feature = "g031",
2390 feature = "g041",
2391 feature = "g030",
2392 feature = "g051",
2393 feature = "g061",
2394 feature = "wb",
2395 feature = "wl",
2396 // todo: Tim15 is available on c091/02, but I don't see a PAC for that.
2397 feature = "c0",
2398 )))] {
2399 make_timer!(TIM15, tim15, 2, u16);
2400 cc_slave_mode!(TIM15);
2401 // todo: TIM15 on some variant has 2 channels (Eg H7). On others, like L4x3, it appears to be 1.
2402 cc_1_channel!(TIM15, u16);
2403 }
2404}
2405
2406#[cfg(not(any(feature = "f4", feature = "c0")))]
2407make_timer!(TIM16, tim16, 2, u16);
2408#[cfg(not(any(feature = "f4", feature = "c0")))]
2409cc_1_channel!(TIM16, u16);
2410
2411#[cfg(feature = "c0")]
2412make_timer!(TIM16, tim16, 2, u32);
2413#[cfg(feature = "c0")]
2414cc_1_channel!(TIM16, u32);
2415
2416cfg_if! {
2417 if #[cfg(not(any(
2418 feature = "l4x1",
2419 feature = "l4x2",
2420 feature = "l412",
2421 feature = "l4x3",
2422 feature = "f4",
2423 )))] {
2424 make_timer!(TIM17, tim17, 2, u16);
2425 cc_1_channel!(TIM17, u16);
2426 }
2427}
2428
2429cfg_if! {
2430 if #[cfg(any(feature = "f373"))] {
2431 make_timer!(TIM12, tim12, 1, u16);
2432 make_timer!(TIM13, tim13, 1, u16);
2433 make_timer!(TIM14, tim14, 1, u16);
2434 make_timer!(TIM19, tim19, 2, u16);
2435
2436 cc_slave_mode!(TIM12);
2437 cc_slave_mode!(TIM19);
2438
2439 cc_1_channel!(TIM12, u16);
2440 cc_1_channel!(TIM13, u16);
2441 cc_1_channel!(TIM14, u16);
2442 cc_1_channel!(TIM19, u16);
2443 }
2444}
2445
2446// todo: G4 (maybe not all variants?) have TIM20.
2447#[cfg(any(feature = "f303"))]
2448make_timer!(TIM20, tim20, 2, u16);
2449#[cfg(any(feature = "f303"))]
2450cc_slave_mode!(TIM20);
2451#[cfg(any(feature = "f303"))]
2452cc_4_channels!(TIM20, u16);