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