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 = "c0")]
40use crate::pac::DMA as DMA1;
41#[cfg(not(feature = "c0"))]
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(any(feature = "f373", feature = "c0")))]
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 #[cfg(not(feature = "c0"))]
436 result.set_dir();
437
438 // Trigger an update event to load the prescaler value to the clock
439 // NOTE(write): uses all bits in this register. This also clears the interrupt flag,
440 // which the EGER update will generate.
441 result.reinitialize();
442
443 result
444 }
445 }
446
447 /// Enable a specific type of Timer interrupt.
448 pub fn enable_interrupt(&mut self, interrupt: TimerInterrupt) {
449 match interrupt {
450 TimerInterrupt::Update => self.regs.dier().modify(|_, w| w.uie().bit(true)),
451 // todo: Only DIER is in PAC, or some CCs. PAC BUG? Only avail on some timers/MCUs?
452 // TimerInterrupt::Trigger => self.regs.dier().modify(|_, w| w.tie().bit(true)),
453 // TimerInterrupt::CaptureCompare1 => self.regs.dier().modify(|_, w| w.cc1ie().bit(true)),
454 // TimerInterrupt::CaptureCompare2 => self.regs.dier().modify(|_, w| w.cc2ie().bit(true)),
455 // TimerInterrupt::CaptureCompare3 => self.regs.dier().modify(|_, w| w.cc3ie().bit(true)),
456 // TimerInterrupt::CaptureCompare4 => self.regs.dier().modify(|_, w| w.cc4ie().bit(true)),
457 #[cfg(not(feature = "f3"))] // todo: Not working on some variants
458 TimerInterrupt::UpdateDma => self.regs.dier().modify(|_, w| w.ude().bit(true)),
459 // TimerInterrupt::TriggerDma => self.regs.dier().modify(|_, w| w.tde().bit(true)),
460 // TimerInterrupt::CaptureCompare1Dma => self.regs.dier().modify(|_, w| w.cc1de().bit(true)),
461 // TimerInterrupt::CaptureCompare2Dma => self.regs.dier().modify(|_, w| w.ccd2de().bit(true)),
462 // TimerInterrupt::CaptureCompare3Dma => self.regs.dier().modify(|_, w| w.cc3de().bit(true)),
463 // TimerInterrupt::CaptureCompare4Dma => self.regs.dier().modify(|_, w| w.cc4de().bit(true)),
464 _ => unimplemented!("TODO TEMP PROBLEMS"),
465 };
466 }
467
468 /// Disable a specific type of Timer interrupt.
469 pub fn disable_interrupt(&mut self, interrupt: TimerInterrupt) {
470 match interrupt {
471 TimerInterrupt::Update => self.regs.dier().modify(|_, w| w.uie().clear_bit()),
472 // todo: Only DIER is in PAC, or some CCs. PAC BUG? Only avail on some timers/MCUs?
473 // TimerInterrupt::Trigger => self.regs.dier().modify(|_, w| w.tie().clear_bit()),
474 // TimerInterrupt::CaptureCompare1 => self.regs.dier().modify(|_, w| w.cc1ie().clear_bit()),
475 // TimerInterrupt::CaptureCompare2 => self.regs.dier().modify(|_, w| w.cc2ie().clear_bit()),
476 // TimerInterrupt::CaptureCompare3 => self.regs.dier().modify(|_, w| w.cc3ie().clear_bit()),
477 // TimerInterrupt::CaptureCompare4 => self.regs.dier().modify(|_, w| w.cc4ie().clear_bit()),
478 #[cfg(not(feature = "f3"))] // todo: Not working on some variants
479 TimerInterrupt::UpdateDma => self.regs.dier().modify(|_, w| w.ude().clear_bit()),
480 // TimerInterrupt::TriggerDma => self.regs.dier().modify(|_, w| w.tde().clear_bit()),
481 // TimerInterrupt::CaptureCompare1Dma => self.regs.dier().modify(|_, w| w.cc1de().clear_bit()),
482 // TimerInterrupt::CaptureCompare2Dma => self.regs.dier().modify(|_, w| w.ccd2de().clear_bit()),
483 // TimerInterrupt::CaptureCompare3Dma => self.regs.dier().modify(|_, w| w.cc3de().clear_bit()),
484 // TimerInterrupt::CaptureCompare4Dma => self.regs.dier().modify(|_, w| w.cc4de().clear_bit()),
485 _ => unimplemented!("TODO TEMP PROBLEMS"),
486 };
487 }
488
489 /// Clears interrupt associated with this timer.
490 ///
491 /// If the interrupt is not cleared, it will immediately retrigger after
492 /// the ISR has finished. For examlpe, place this at the top of your timer's
493 /// interrupt handler.
494 pub fn clear_interrupt(&mut self, interrupt: TimerInterrupt) {
495 // Note that unlike other clear interrupt functions, for this, we clear the bit instead
496 // of setting it. Due to the way our SVDs are set up not working well with this atomic clear,
497 // we need to make sure we write 1s to the rest of the bits.
498 // todo: Overcapture flags for each CC? DMA interrupts?
499 #[cfg(feature = "c0")]
500 let bits = 0xffff;
501 #[cfg(not(feature = "c0"))]
502 let bits = 0xffff_ffff;
503
504 unsafe {
505 match interrupt {
506 TimerInterrupt::Update => self
507 .regs
508 .sr()
509 .write(|w| w.bits(bits).uif().clear_bit()),
510 // todo: Only DIER is in PAC, or some CCs. PAC BUG? Only avail on some timers?
511 // TimerInterrupt::Trigger => self.regs.sr().write(|w| w.bits(bits).tif().clear_bit()),
512 // TimerInterrupt::CaptureCompare1 => self.regs.sr().write(|w| w.bits(bits).cc1if().clear_bit()),
513 // TimerInterrupt::CaptureCompare2 => self.regs.sr().write(|w| w.bits(bits).cc2if().clear_bit()),
514 // TimerInterrupt::CaptureCompare3 => self.regs.sr().write(|w| w.bits(bits).cc3if().clear_bit()),
515 // TimerInterrupt::CaptureCompare4 => self.regs.sr().write(|w| w.bits(bits).cc4if().clear_bit()),
516 _ => unimplemented!(
517 "Clearing DMA flags is unimplemented using this function."
518 ),
519 };
520 }
521 }
522
523 /// Enable (start) the timer.
524 pub fn enable(&mut self) {
525 self.regs.cr1().modify(|_,w| w.cen().bit(true));
526 }
527
528 /// Disable (stop) the timer.
529 pub fn disable(&mut self) {
530 self.regs.cr1().modify(|_, w| w.cen().clear_bit());
531 }
532
533 /// Check if the timer is enabled.
534 pub fn is_enabled(&self) -> bool {
535 self.regs.cr1().read().cen().bit_is_set()
536 }
537
538 #[cfg(not(feature = "c0"))]
539 /// Print the (raw) contents of the status register.
540 pub fn read_status(&self) -> u32 {
541 unsafe { self.regs.sr().read().bits() }
542 }
543
544 #[cfg(feature = "c0")]
545 /// Print the (raw) contents of the status register.
546 pub fn read_status(&self) -> u16 {
547 unsafe { self.regs.sr().read().bits().try_into().unwrap() }
548 }
549
550 /// Set the timer frequency, in Hz. Overrides the period or frequency set
551 /// in the constructor.
552 pub fn set_freq(&mut self, mut freq: f32) -> Result<(), ValueError> {
553 assert!(freq > 0.);
554 // todo: Take into account the `timxsw` bit in RCC CFGR3, which may also
555 // todo require an adjustment to freq.
556 match self.cfg.alignment {
557 Alignment::Edge => (),
558 _ => freq *= 2.,
559 }
560
561 let (psc, arr) = calc_freq_vals(freq, self.clock_speed)?;
562
563 self.regs.arr().write(|w| unsafe { w.bits(arr.into()) });
564 self.regs.psc().write(|w| unsafe { w.bits(psc.into()) });
565
566 // (PSC+1)*(ARR+1) = TIMclk/Updatefrequency = TIMclk * period
567 // period = (PSC+1)*(ARR+1) / TIMclk
568 // Calculate this based on our actual ARR and PSC values; don't use
569 // the requested frequency or period.
570 let arr_f32 = arr as f32;
571 let period_secs = (psc as f32 + 1.) * ( arr_f32 + 1.) / self.clock_speed as f32;
572 self.ns_per_tick = (period_secs / arr_f32 * 1_000_000_000.) as u64;
573 self.period = period_secs;
574
575 Ok(())
576 }
577
578 /// Set the timer period, in seconds. Overrides the period or frequency set
579 /// in the constructor.
580 pub fn set_period(&mut self, period: f32) -> Result<(), ValueError> {
581 assert!(period > 0.);
582 self.set_freq(1. / period)
583 }
584
585 /// Set the auto-reload register value. Used for adjusting frequency.
586 pub fn set_auto_reload(&mut self, arr: u32) {
587 // todo: Could be u16 or u32 depending on timer resolution,
588 // todo but this works for now.
589 #[cfg(not(feature = "c0"))]
590 self.regs.arr().write(|w| unsafe { w.bits(arr.into()) });
591 #[cfg(feature = "c0")]
592 self.regs.arr().write(|w| unsafe { w.bits((arr as u32).try_into().unwrap()) });
593 }
594
595 /// Set the prescaler value. Used for adjusting frequency.
596 pub fn set_prescaler(&mut self, psc: u16) {
597 self.regs.psc().write(|w| unsafe { w.bits(psc.into()) });
598 }
599
600 /// Reset the countdown; set the counter to 0.
601 pub fn reset_count(&mut self) {
602 self.regs.cnt().write(|w| unsafe { w.bits(0) });
603 }
604
605 /// UIF Flag in SR register is set when CNT reg is overflow / underflow
606 ///
607 pub fn get_uif(&self ) -> bool {
608 self.regs.sr().read().uif().bit_is_set()
609 }
610
611 pub fn clear_uif(&mut self) {
612 #[cfg(feature = "c0")]
613 let bits = 0xffff;
614 #[cfg(not(feature = "c0"))]
615 let bits = 0xffff_ffff;
616
617 unsafe {
618 self.regs
619 .sr()
620 .write(|w| w.bits(bits).uif().clear_bit());
621 }
622 }
623
624 /// Re-initialize the counter and generates an update of the registers. Note that the prescaler
625 /// counter is cleared too (anyway the prescaler ratio is not affected). The counter is cleared.
626 /// When changing timer frequency (or period) via PSC, you may need to run this. Alternatively, change
627 /// the freq in an update ISR.
628 /// Note from RM, PSC reg: PSC contains the value to be loaded in the active prescaler
629 /// register at each update event
630 /// (including when the counter is cleared through UG bit of TIMx_EGR register or through
631 /// trigger controller when configured in “reset mode”).'
632 /// If you're doing something where the updates can wait a cycle, this isn't required. (eg PWM
633 /// with changing duty period).
634 pub fn reinitialize(&mut self) {
635 self.regs.egr().write(|w| w.ug().bit(true));
636 self.clear_interrupt(TimerInterrupt::Update);
637 }
638
639 /// Read the current counter value.
640 pub fn read_count(&self) -> u32 {
641 // todo: This depends on resolution. We read the whole
642 // todo res and pass a u32 just in case.
643 // self.regs.cnt().read().cnt().bits()
644 self.regs.cnt().read().bits()
645 }
646
647
648 /// Enables PWM output for a given channel and output compare, with an initial duty cycle, in Hz.
649 pub fn enable_pwm_output(
650 &mut self,
651 channel: TimChannel,
652 compare: OutputCompare,
653 duty: f32,
654 ) {
655 self.set_capture_compare_output(channel, CaptureCompare::Output);
656 self.set_preload(channel, true);
657 self.set_output_compare(channel, compare);
658 self.set_duty(channel, (self.get_max_duty() as f32 * duty) as $res);
659 self.enable_capture_compare(channel);
660 }
661
662 /// Return the integer associated with the maximum duty period.
663 pub fn get_max_duty(&self) -> $res {
664 #[cfg(feature = "g0")]
665 return self.regs.arr().read().bits().try_into().unwrap();
666 #[cfg(not(feature = "g0"))]
667 self.regs.arr().read().arr().bits().try_into().unwrap()
668 }
669
670 /// See G4 RM, section 29.4.24: Dma burst mode. "The TIMx timers have the capability to
671 /// generate multiple DMA requests upon a single event.
672 /// The main purpose is to be able to re-program part of the timer multiple times without
673 /// software overhead, but it can also be used to read several registers in a row, at regular
674 /// intervals." This may be used to create arbitrary waveforms by modifying the CCR register
675 /// (base address = 13-16, for CCR1-4), or for implementing duty-cycle based digital protocols.
676 #[cfg(not(any(feature = "g0", feature = "f", feature = "l552", feature = "l4")))]
677 pub unsafe fn write_dma_burst(
678 &mut self,
679 buf: &[u16],
680 base_address: u8,
681 burst_len: u8,
682 dma_channel: DmaChannel,
683 channel_cfg: ChannelCfg,
684 ds_32_bits: bool,
685 dma_periph: dma::DmaPeriph,
686 ) {
687 // Note: F3 and L4 are unsupported here, since I'm not sure how to select teh
688 // correct Timer channel.
689
690 // todo: Should we disable the timer here?
691
692 let (ptr, len) = (buf.as_ptr(), buf.len());
693
694 // todo: For F3 and L4, manually set channel using PAC for now. Currently
695 // todo we don't have a way here to pick the timer. Could do it with a new macro arg.
696
697 // L44 RM, Table 41. "DMA1 requests for each channel"
698 // #[cfg(any(feature = "f3", feature = "l4"))]
699 // let dma_channel = match tim_channel {
700 // // SaiChannel::A => DmaInput::Sai1A.dma1_channel(),
701 // };
702 //
703 // #[cfg(feature = "l4")]
704 // match tim_channel {
705 // SaiChannel::B => dma.channel_select(DmaInput::Sai1B),
706 // };
707
708 // RM:
709 // This example is for the case where every CCRx register has to be updated once. If every
710 // CCRx register is to be updated twice for example, the number of data to transfer should be
711 // 6. Let's take the example of a buffer in the RAM containing data1, data2, data3, data4, data5
712 // and data6. The data is transferred to the CCRx registers as follows: on the first update DMA
713 // request, data1 is transferred to CCR2, data2 is transferred to CCR3, data3 is transferred to
714 // CCR4 and on the second update DMA request, data4 is transferred to CCR2, data5 is
715 // transferred to CCR3 and data6 is transferred to CCR4.
716
717 // 1. Configure the corresponding DMA channel as follows:
718 // –DMA channel peripheral address is the DMAR register address
719 let periph_addr = &self.regs.dmar() as *const _ as u32;
720 // –DMA channel memory address is the address of the buffer in the RAM containing
721 // the data to be transferred by DMA into CCRx registers.
722
723 // Number of data to transfer is our buffer len number of registers we're editing, x
724 // number of half-words written to each reg.
725 let num_data = len as u32;
726
727 // 2.
728 // Configure the DCR register by configuring the DBA and DBL bit fields as follows:
729 // DBL = 3 transfers, DBA = 0xE.
730
731 // The DBL[4:0] bits in the TIMx_DCR register set the DMA burst length. The timer recognizes
732 // a burst transfer when a read or a write access is done to the TIMx_DMAR address), i.e. the
733 // number of transfers (either in half-words or in bytes).
734 // The DBA[4:0] bits in the TIMx_DCR registers define the DMA base address for DMA
735 // transfers (when read/write access are done through the TIMx_DMAR address). DBA is
736 // defined as an offset starting from the address of the TIMx_CR1 register:
737 // Example:
738 // 00000: TIMx_CR1
739 // 00001: TIMx_CR2
740 // 00010: TIMx_SMCR
741 self.regs.dcr().modify(|_, w| unsafe {
742 w.dba().bits(base_address);
743 w.dbl().bits(burst_len as u8 - 1)
744 });
745
746 // 3. Enable the TIMx update DMA request (set the UDE bit in the DIER register).
747 // note: Leaving this to application code for now.
748 // self.enable_interrupt(TimerInterrupt::UpdateDma);
749
750 // 4. Enable TIMx
751 self.enable();
752
753 // 5. Enable the DMA channel
754 match dma_periph {
755 dma::DmaPeriph::Dma1 => {
756 let mut regs = unsafe { &(*DMA1::ptr()) };
757 dma::cfg_channel(
758 &mut regs,
759 dma_channel,
760 periph_addr,
761 ptr as u32,
762 num_data,
763 dma::Direction::ReadFromMem,
764 // Note: This may only be relevant if modifying a reg that changes for 32-bit
765 // timers, like AAR and CCRx
766 if ds_32_bits { dma::DataSize::S32} else { dma::DataSize::S16 },
767 dma::DataSize::S16,
768 channel_cfg,
769 );
770 }
771 #[cfg(dma2)]
772 dma::DmaPeriph::Dma2 => {
773 let mut regs = unsafe { &(*pac::DMA2::ptr()) };
774 dma::cfg_channel(
775 &mut regs,
776 dma_channel,
777 periph_addr,
778 ptr as u32,
779 num_data,
780 dma::Direction::ReadFromMem,
781 // Note: This may only be relevant if modifying a reg that changes for 32-bit
782 // timers, like AAR and CCRx
783 if ds_32_bits { dma::DataSize::S32} else { dma::DataSize::S16 },
784 dma::DataSize::S16,
785 channel_cfg,
786 );
787 }
788 }
789
790 }
791
792 #[cfg(not(any(feature = "g0", feature = "f", feature = "l552", feature = "l4")))]
793 pub unsafe fn read_dma_burst(
794 // todo: Experimenting with input capture.
795 &mut self,
796 buf: &mut [u16],
797 base_address: u8,
798 burst_len: u8,
799 dma_channel: DmaChannel,
800 channel_cfg: ChannelCfg,
801 ds_32_bits: bool,
802 dma_periph: dma::DmaPeriph,
803 ) {
804 let (ptr, len) = (buf.as_mut_ptr(), buf.len());
805
806 let periph_addr = &self.regs.dmar() as *const _ as u32;
807
808 let num_data = len as u32;
809
810 self.regs.dcr().modify(|_, w| unsafe {
811 w.dba().bits(base_address);
812 w.dbl().bits(burst_len as u8 - 1)
813 });
814
815 self.enable();
816
817 match dma_periph {
818 dma::DmaPeriph::Dma1 => {
819 #[cfg(not(feature = "c0"))]
820 let mut regs = unsafe { &(*pac::DMA1::ptr()) };
821 #[cfg(feature = "c0")]
822 let mut regs = unsafe { &(*pac::DMA::ptr()) };
823
824 dma::cfg_channel(
825 &mut regs,
826 dma_channel,
827 periph_addr,
828 ptr as u32,
829 num_data,
830 dma::Direction::ReadFromPeriph,
831 // Note: This may only be relevant if modifying a reg that changes for 32-bit
832 // timers, like AAR and CCRx
833 if ds_32_bits { dma::DataSize::S32} else { dma::DataSize::S16 },
834 dma::DataSize::S16,
835 channel_cfg,
836 );
837 }
838 #[cfg(dma2)]
839 dma::DmaPeriph::Dma2 => {
840 let mut regs = unsafe { &(*pac::DMA2::ptr()) };
841 dma::cfg_channel(
842 &mut regs,
843 dma_channel,
844 periph_addr,
845 ptr as u32,
846 num_data,
847 dma::Direction::ReadFromPeriph,
848 // Note: This may only be relevant if modifying a reg that changes for 32-bit
849 // timers, like AAR and CCRx
850 if ds_32_bits { dma::DataSize::S32} else { dma::DataSize::S16 },
851 dma::DataSize::S16,
852 channel_cfg,
853 );
854 }
855 }
856 }
857
858 /// Get the time elapsed since the start of the timer, taking overflow wraps into account.
859 ///
860 /// Important: the value returned here will only be correct if the ARR and PSC are set
861 /// only using the constructor, `set_freq`, or `set_period` methods.
862 pub fn now(&mut self) -> Instant {
863 // let wrap_count = self.wrap_count;
864 let wrap_count = TICK_OVERFLOW_COUNT.load(Ordering::Acquire);
865
866 let ticks = (self.read_count() as u64 + wrap_count as u64 *
867 self.get_max_duty() as u64);
868 let count_ns = ticks as i128 * self.ns_per_tick as i128;
869
870 Instant::new(count_ns)
871 }
872
873 pub fn elapsed(&mut self, since: Instant) -> Duration {
874 self.now() - since
875 }
876 }
877
878 #[cfg(feature = "monotonic")]
879 impl Monotonic for Timer<pac::$TIMX> {
880 type Instant = Instant;
881 type Duration = core::time::Duration;
882
883 const DISABLE_INTERRUPT_ON_EMPTY_QUEUE: bool = false;
884
885 fn now(&mut self) -> Self::Instant {
886 self.time_elapsed()
887 }
888
889 /// We use the compare 1 channel for this.
890 /// todo: Support wrapping?
891 fn set_compare(&mut self, instant: Self::Instant) {
892 self.regs
893 .ccr1()
894 .write(|w| unsafe { w.ccr().bits(((instant.count_ns as f32 / self.ns_per_tick) as u16).into()) });
895 }
896
897 /// We use the compare 1 channel for this.
898 /// todo: Support wrapping?
899 fn clear_compare_flag(&mut self) {
900 self.regs.sr().modify(|_, w| w.cc1if().clear_bit());
901 }
902
903 fn zero() -> Self::Instant {
904 Instant::default()
905 }
906
907 unsafe fn reset(&mut self) {
908 self.reset_count();
909 TICK_OVERFLOW_COUNT.store(0, Ordering::Release);
910 }
911
912 fn on_interrupt(&mut self) {
913 // self.wrap_count += 1;
914 TICK_OVERFLOW_COUNT.fetch_add(1, Ordering::Relaxed);
915 }
916 fn enable_timer(&mut self) {
917 self.enable();
918 }
919 fn disable_timer(&mut self) {
920 self.disable();
921 }
922
923 /// Print the (raw) contents of the status register.
924 pub fn read_status(&self) -> u32 {
925 unsafe { self.regs.isr().read().bits() }
926 }
927 }
928
929 // #[cfg(feature = "embedded_hal")]
930 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
931 // impl DelayMs<u32> for Timer<pac::$TIMX> {
932 // fn delay_ms(&mut self, ms: u32) {
933 // let ms_to_s = ms as f32 / 1_000.;
934 // self.set_freq(1. / (ms_to_s)).ok();
935 // self.reset_count();
936 // self.enable();
937 // while self.get_uif() == false {}
938 // self.clear_uif();
939 // self.disable();
940 // }
941 // }
942 //
943 // #[cfg(feature = "embedded_hal")]
944 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
945 // impl DelayMs<u16> for Timer<pac::$TIMX> {
946 // fn delay_ms(&mut self, ms: u16) {
947 // self.delay_ms(ms as u32)
948 // }
949 // }
950 //
951 // #[cfg(feature = "embedded_hal")]
952 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
953 // impl DelayMs<u8> for Timer<pac::$TIMX> {
954 // fn delay_ms(&mut self, ms: u8) {
955 // self.delay_ms(ms as u32)
956 // }
957 // }
958 //
959 // #[cfg(feature = "embedded_hal")]
960 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
961 // impl DelayUs<u32> for Timer<pac::$TIMX> {
962 // fn delay_us(&mut self, us: u32) {
963 // let us_to_s = us as f32 / 1_000_000.;
964 // self.set_freq(1. / (us_to_s)).ok();
965 // self.reset_count();
966 // self.enable();
967 // while self.get_uif() == false {}
968 // self.clear_uif();
969 // self.disable();
970 // }
971 // }
972 //
973 // #[cfg(feature = "embedded_hal")]
974 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
975 // impl DelayUs<u16> for Timer<pac::$TIMX> {
976 // fn delay_us(&mut self, us: u16) {
977 // self.delay_us(us as u32);
978 // }
979 // }
980 //
981 // #[cfg(feature = "embedded_hal")]
982 // // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
983 // impl DelayUs<u8> for Timer<pac::$TIMX> {
984 // fn delay_us(&mut self, us: u8) {
985 // self.delay_us(us as u32);
986 // }
987 // }
988
989 // /// Implementation of the embedded-hal CountDown trait
990 // /// To use Countdown it is prefered to configure new timer in Oneshot mode :
991 // ///
992 // /// Example :
993 // /// llet tim16_conf = TimerConfig {
994 // /// one_pulse_mode: true,
995 // /// ..Default::default()
996 // /// };
997 // ///
998 // /// Creation of timer. Here the freq arg value is not important, the freq
999 // /// will be changed for each CountDown start timer depends on delay wanted.
1000 // ///
1001 // /// let mut tim16: Timer<TIM16> = Timer::new_tim16(dp.TIM16, 1000., tim16_conf, &clocks);
1002 // ///
1003 // ///
1004 // #[cfg(feature = "embedded_hal")]
1005 // impl CountDown for Timer<pac::$TIMX>
1006 // {
1007 // type Time = duration::Generic<u32>;
1008 //
1009 // fn start<T>(&mut self, timeout: T)
1010 // where
1011 // T: Into<Self::Time>,
1012 // {
1013 //
1014 // //Disable timer and clear flag uif
1015 // self.disable();
1016 // self.clear_uif();
1017 //
1018 // //Get timeout
1019 // let timeout: Self::Time = timeout.into();
1020 //
1021 // let denom = timeout.scaling_factor().denominator();
1022 //
1023 // //Prevent a division by zero
1024 // if *denom != 0 {
1025 // //Convert time to seconds
1026 // let time_to_s = timeout.integer() as f32 / *denom as f32;
1027 //
1028 // //Configure timer
1029 // self.set_freq(1. / (time_to_s)).ok();
1030 // self.reset_count();
1031 // //Update event to setup prescale and reload registers
1032 // self.reinitialize();
1033 // self.clear_uif();
1034 //
1035 // //start the timer
1036 // self.enable();
1037 // }
1038 //
1039 // }
1040 //
1041 // /// Wait until the timer has elapsed
1042 // /// and than clear the event.
1043 // fn wait(&mut self) -> nb::Result<(), Void> {
1044 // if !self.get_uif() {
1045 // Err(nb::Error::WouldBlock)
1046 // } else {
1047 // self.clear_uif();
1048 // self.disable();
1049 // Ok(())
1050 // }
1051 // }
1052 // }
1053 }
1054}
1055
1056// We use macros to support the varying number of capture compare channels available on
1057// different timers.
1058// Note that there's lots of DRY between these implementations.
1059macro_rules! cc_4_channels {
1060 ($TIMX:ident, $res:ident) => {
1061 impl Timer<pac::$TIMX> {
1062 /// Function that allows us to set direction only on timers that have this option.
1063 pub fn set_dir(&mut self) {
1064 self.regs
1065 .cr1()
1066 .modify(|_, w| w.dir().bit(self.cfg.direction as u8 != 0));
1067 self.regs
1068 .cr1()
1069 .modify(|_, w| unsafe { w.cms().bits(self.cfg.alignment as u8) });
1070 }
1071
1072 /// Set up input capture, eg for PWM input.
1073 /// L4 RM, section 26.3.8. H723 RM, section 43.3.7.
1074 /// Note: Does not handle TISEL (timer input selection register - you must do this manually
1075 /// using the PAC.
1076 #[cfg(not(any(
1077 feature = "f",
1078 feature = "l4x5",
1079 feature = "l5",
1080 feature = "g0",
1081 feature = "wb"
1082 )))]
1083 pub fn set_input_capture(
1084 &mut self,
1085 channel: TimChannel,
1086 mode: CaptureCompare,
1087 // trigger: InputTrigger,
1088 // slave_mode: InputSlaveMode,
1089 ccp: Polarity,
1090 ccnp: Polarity,
1091 ) {
1092 // 2. Select the active input for TIMx_CCR1: write the CC1S bits to 01 in the TIMx_CCMR1
1093 // register.
1094 self.set_capture_compare_input(channel, mode);
1095
1096 // 1. Select the proper TI1x source (internal or external) with the TI1SEL[3:0] bits in the
1097 // TIMx_TISEL register.
1098 // Leaving it at its default value of 0 selects the timer input, which we'll hard-code
1099 // for now.
1100 // let tisel = 0b0000;
1101
1102 // 3.
1103 // Program the needed input filter duration in relation with the signal connected to the
1104 // timer (when the input is one of the tim_tix (ICxF bits in the TIMx_CCMRx register). Let’s
1105 // imagine that, when toggling, the input signal is not stable during at must 5 internal clock
1106 // cycles. We must program a filter duration longer than these 5 clock cycles. We can
1107 // validate a transition on tim_ti1 when 8 consecutive samples with the new level have
1108 // been detected (sampled at fDTS frequency). Then write IC1F bits to 0011 in the
1109 // TIMx_CCMR1 register.
1110 let filter = 0b0011; // todo experimenting.
1111
1112 match channel {
1113 TimChannel::C1 => {
1114 // self.regs.tisel.modify(|_, w| unsafe { w.ti1sel().bits(tisel) });
1115
1116 // 3. Select the active polarity for TI1FP1 (used both for capture in TIMx_CCR1 and counter
1117 // clear): write the CC1P and CC1NP bits to ‘0’ (active on rising edge).
1118 // (Note: We could use the `set_polarity` and `set_complementary_polarity` methods, but
1119 // this allows us to combine them in a single reg write.)
1120 self.regs.ccer().modify(|_, w| {
1121 w.cc1p().bit(ccp.bit());
1122 w.cc1np().bit(ccnp.bit())
1123 });
1124
1125 // 5.
1126 // Program the input prescaler. In our example, we wish the capture to be performed at
1127 // each valid transition, so the prescaler is disabled (write IC1PS bits to 00 in the
1128 // TIMx_CCMR1 register).
1129 self.regs.ccmr1_input().modify(|_, w| unsafe {
1130 // todo: PAC ommission?
1131 // w.ic1psc().bits(0b00);
1132 w.ic1f().bits(filter)
1133 });
1134 }
1135 TimChannel::C2 => {
1136 // self.regs.tisel.modify(|_, w| unsafe { w.ti2sel().bits(tisel) });
1137
1138 self.regs.ccer().modify(|_, w| {
1139 w.cc2p().bit(ccp.bit());
1140 w.cc2np().bit(ccnp.bit())
1141 });
1142
1143 self.regs.ccmr1_input().modify(|_, w| unsafe {
1144 w.ic2psc().bits(0b00);
1145 w.ic2f().bits(filter)
1146 });
1147 }
1148 TimChannel::C3 => {
1149 // self.regs.tisel.modify(|_, w| unsafe { w.ti3sel().bits(tisel) });
1150
1151 self.regs.ccer().modify(|_, w| {
1152 w.cc3p().bit(ccp.bit());
1153 w.cc3np().bit(ccnp.bit())
1154 });
1155
1156 self.regs.ccmr2_input().modify(|_, w| unsafe {
1157 w.ic3psc().bits(0b00);
1158 w.ic3f().bits(filter)
1159 });
1160 }
1161 #[cfg(not(feature = "wl"))]
1162 TimChannel::C4 => {
1163 // self.regs.tisel.modify(|_, w| unsafe { w.ti4sel().bits(tisel) });
1164
1165 self.regs.ccer().modify(|_, w| {
1166 #[cfg(not(any(feature = "f4", feature = "l4")))]
1167 w.cc4np().bit(ccnp.bit());
1168 w.cc4p().bit(ccp.bit())
1169 });
1170
1171 self.regs.ccmr2_input().modify(|_, w| unsafe {
1172 w.ic4psc().bits(0b00);
1173 w.ic4f().bits(filter)
1174 });
1175 }
1176 }
1177
1178 // todo: SMCR: Set in the Input PWM settings, but not normal input capture (?)
1179 // 6. Select the valid trigger input: write the TS bits to 101 in the TIMx_SMCR register
1180 // (TI1FP1 selected).
1181 // self.regs.smcr().modify(|_, w| unsafe {
1182 // w.ts().bits(trigger as u8);
1183 // // 7. Configure the slave mode controller in reset mode: write the SMS bits to 0100 in the
1184 // // TIMx_SMCR register.
1185 // w.sms().bits(slave_mode as u8)
1186 // });
1187
1188 // 6. Enable capture from the counter into the capture register by setting the CC1E bit in the
1189 // TIMx_CCER register.
1190 self.enable_capture_compare(channel);
1191
1192 // 7.If needed, enable the related interrupt request by setting the CC1IE bit in the
1193 // TIMx_DIER register, and/or the DMA request by setting the CC1DE bit in the
1194 // TIMx_DIER register.
1195 }
1196
1197 // todo: more advanced PWM modes. Asymmetric, combined, center-aligned etc.
1198
1199 /// Set Output Compare Mode. See docs on the `OutputCompare` enum.
1200 pub fn set_output_compare(&mut self, channel: TimChannel, mode: OutputCompare) {
1201 match channel {
1202 TimChannel::C1 => {
1203 self.regs.ccmr1_output().modify(|_, w| unsafe {
1204 #[cfg(not(any(feature = "f", feature = "l5", feature = "wb")))]
1205 w.oc1m_3().bit((mode as u8) >> 3 != 0);
1206 w.oc1m().bits((mode as u8) & 0b111)
1207 });
1208 }
1209 TimChannel::C2 => {
1210 self.regs.ccmr1_output().modify(|_, w| unsafe {
1211 #[cfg(not(any(feature = "f", feature = "l5", feature = "wb")))]
1212 w.oc2m_3().bit((mode as u8) >> 3 != 0);
1213 w.oc2m().bits((mode as u8) & 0b111)
1214 });
1215 }
1216 TimChannel::C3 => {
1217 self.regs.ccmr2_output().modify(|_, w| unsafe {
1218 #[cfg(not(any(feature = "f", feature = "l5", feature = "wb")))]
1219 w.oc3m_3().bit((mode as u8) >> 3 != 0);
1220 w.oc3m().bits((mode as u8) & 0b111)
1221 });
1222 }
1223 #[cfg(not(feature = "wl"))]
1224 TimChannel::C4 => {
1225 self.regs.ccmr2_output().modify(|_, w| unsafe {
1226 #[cfg(not(any(
1227 feature = "f3",
1228 feature = "f4",
1229 feature = "l5",
1230 feature = "wb",
1231 feature = "h7"
1232 )))]
1233 w.oc4m_3().bit((mode as u8) >> 3 != 0);
1234 w.oc4m().bits((mode as u8) & 0b111)
1235 });
1236 }
1237 }
1238 }
1239
1240 /// Return the set duty period for a given channel. Divide by `get_max_duty()`
1241 /// to find the portion of the duty cycle used.
1242 pub fn get_duty(&self, channel: TimChannel) -> $res {
1243 cfg_if! {
1244 if #[cfg(any(feature = "wb", feature = "wl"))] {
1245 (match channel {
1246 TimChannel::C1 => self.regs.ccr1().read().bits(),
1247 TimChannel::C2 => self.regs.ccr2().read().bits(),
1248 TimChannel::C3 => self.regs.ccr3().read().bits(),
1249 #[cfg(not(feature = "wl"))]
1250 TimChannel::C4 => self.regs.ccr4().read().bits(),
1251 }) as $res
1252 } else {
1253 match channel {
1254 TimChannel::C1 => self.regs.ccr1().read().ccr().bits().into(),
1255 TimChannel::C2 => self.regs.ccr2().read().ccr().bits().into(),
1256 TimChannel::C3 => self.regs.ccr3().read().ccr().bits().into(),
1257 #[cfg(not(feature = "wl"))]
1258 TimChannel::C4 => self.regs.ccr4().read().ccr().bits().into(),
1259 }
1260 }
1261 }
1262 }
1263
1264 /// Set the duty cycle, as a portion of ARR (`get_max_duty()`). Note that this
1265 /// needs to be re-run if you change ARR at any point.
1266 pub fn set_duty(&mut self, channel: TimChannel, duty: $res) {
1267 unsafe {
1268 match channel {
1269 TimChannel::C1 => self
1270 .regs
1271 .ccr1()
1272 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1273 TimChannel::C2 => self
1274 .regs
1275 .ccr2()
1276 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1277 TimChannel::C3 => self
1278 .regs
1279 .ccr3()
1280 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1281 #[cfg(not(feature = "wl"))]
1282 TimChannel::C4 => self
1283 .regs
1284 .ccr4()
1285 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1286 };
1287 }
1288 }
1289
1290 /// Set timer alignment to Edge, or one of 3 center modes.
1291 /// STM32F303 ref man, section 21.4.1:
1292 /// Bits 6:5 CMS: Center-aligned mode selection
1293 /// 00: Edge-aligned mode. The counter counts up or down depending on the direction bit
1294 /// (DIR).
1295 /// 01: Center-aligned mode 1. The counter counts up and down alternatively. Output compare
1296 /// interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are set
1297 /// only when the counter is counting down.
1298 /// 10: Center-aligned mode 2. The counter counts up and down alternatively. Output compare
1299 /// interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are set
1300 /// only when the counter is counting up.
1301 /// 11: Center-aligned mode 3. The counter counts up and down alternatively. Output compare
1302 /// interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are set
1303 /// both when the counter is counting up or down.
1304 pub fn set_alignment(&mut self, alignment: Alignment) {
1305 self.regs
1306 .cr1()
1307 .modify(|_, w| unsafe { w.cms().bits(alignment as u8) });
1308 self.cfg.alignment = alignment;
1309 }
1310
1311 /// Set output polarity. See docs on the `Polarity` enum.
1312 pub fn set_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1313 match channel {
1314 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1p().bit(polarity.bit())),
1315 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2p().bit(polarity.bit())),
1316 TimChannel::C3 => self.regs.ccer().modify(|_, w| w.cc3p().bit(polarity.bit())),
1317 #[cfg(not(feature = "wl"))]
1318 TimChannel::C4 => self.regs.ccer().modify(|_, w| w.cc4p().bit(polarity.bit())),
1319 };
1320 }
1321
1322 /// Set complementary output polarity. See docs on the `Polarity` enum.
1323 pub fn set_complementary_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1324 match channel {
1325 TimChannel::C1 => self
1326 .regs
1327 .ccer()
1328 .modify(|_, w| w.cc1np().bit(polarity.bit())),
1329 TimChannel::C2 => self
1330 .regs
1331 .ccer()
1332 .modify(|_, w| w.cc2np().bit(polarity.bit())),
1333 TimChannel::C3 => self
1334 .regs
1335 .ccer()
1336 .modify(|_, w| w.cc3np().bit(polarity.bit())),
1337 #[cfg(not(any(feature = "f4", feature = "wl", feature = "l4")))]
1338 TimChannel::C4 => self
1339 .regs
1340 .ccer()
1341 .modify(|_, w| w.cc4np().bit(polarity.bit())),
1342 #[cfg(any(feature = "f4", feature = "wl", feature = "l4"))] // PAC ommission
1343 _ => panic!(),
1344 };
1345 }
1346 /// Disables capture compare on a specific channel.
1347 pub fn disable_capture_compare(&mut self, channel: TimChannel) {
1348 match channel {
1349 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().clear_bit()),
1350 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2e().clear_bit()),
1351 TimChannel::C3 => self.regs.ccer().modify(|_, w| w.cc3e().clear_bit()),
1352 #[cfg(not(feature = "wl"))]
1353 TimChannel::C4 => self.regs.ccer().modify(|_, w| w.cc4e().clear_bit()),
1354 };
1355 }
1356
1357 /// Enables capture compare on a specific channel.
1358 pub fn enable_capture_compare(&mut self, channel: TimChannel) {
1359 match channel {
1360 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().bit(true)),
1361 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2e().bit(true)),
1362 TimChannel::C3 => self.regs.ccer().modify(|_, w| w.cc3e().bit(true)),
1363 #[cfg(not(feature = "wl"))]
1364 TimChannel::C4 => self.regs.ccer().modify(|_, w| w.cc4e().bit(true)),
1365 };
1366 }
1367
1368 /// Set Capture Compare mode in output mode. See docs on the `CaptureCompare` enum.
1369 pub fn set_capture_compare_output(
1370 &mut self,
1371 channel: TimChannel,
1372 mode: CaptureCompare,
1373 ) {
1374 // Note: CC1S bits are writable only when the channel is OFF (CC1E = 0 in TIMx_CCER)
1375 self.disable_capture_compare(channel);
1376
1377 match channel {
1378 TimChannel::C1 => self
1379 .regs
1380 .ccmr1_output()
1381 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1382 TimChannel::C2 => self
1383 .regs
1384 .ccmr1_output()
1385 .modify(unsafe { |_, w| w.cc2s().bits(mode as u8) }),
1386 TimChannel::C3 => self
1387 .regs
1388 .ccmr2_output()
1389 .modify(unsafe { |_, w| w.cc3s().bits(mode as u8) }),
1390 #[cfg(not(feature = "wl"))]
1391 TimChannel::C4 => self
1392 .regs
1393 .ccmr2_output()
1394 .modify(unsafe { |_, w| w.cc4s().bits(mode as u8) }),
1395 };
1396 }
1397
1398 /// Set Capture Compare mode in input mode. See docs on the `CaptureCompare` enum.
1399 pub fn set_capture_compare_input(&mut self, channel: TimChannel, mode: CaptureCompare) {
1400 // Note: CC1S bits are writable only when the channel is OFF (CC1E = 0 in TIMx_CCER)
1401 self.disable_capture_compare(channel);
1402
1403 match channel {
1404 TimChannel::C1 => self
1405 .regs
1406 .ccmr1_input()
1407 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1408 TimChannel::C2 => self
1409 .regs
1410 .ccmr1_input()
1411 .modify(unsafe { |_, w| w.cc2s().bits(mode as u8) }),
1412 TimChannel::C3 => self
1413 .regs
1414 .ccmr2_input()
1415 .modify(unsafe { |_, w| w.cc3s().bits(mode as u8) }),
1416 #[cfg(not(feature = "wl"))]
1417 TimChannel::C4 => self
1418 .regs
1419 .ccmr2_input()
1420 .modify(unsafe { |_, w| w.cc4s().bits(mode as u8) }),
1421 };
1422 }
1423
1424 /// Set preload mode.
1425 /// OC1PE: Output Compare 1 preload enable
1426 /// 0: Preload register on TIMx_CCR1 disabled. TIMx_CCR1 can be written at anytime, the
1427 /// new value is taken in account immediately.
1428 /// 1: Preload register on TIMx_CCR1 enabled. Read/Write operations access the preload
1429 /// register. TIMx_CCR1 preload value is loaded in the active register at each update event.
1430 /// Note: 1: These bits can not be modified as long as LOCK level 3 has been programmed
1431 /// (LOCK bits in TIMx_BDTR register) and CC1S=’00’ (the channel is configured in
1432 /// output).
1433 /// 2: The PWM mode can be used without validating the preload register only in one
1434 /// pulse mode (OPM bit set in TIMx_CR1 register). Else the behavior is not guaranteed.
1435 ///
1436 /// Setting preload is required to enable PWM.
1437 pub fn set_preload(&mut self, channel: TimChannel, value: bool) {
1438 match channel {
1439 TimChannel::C1 => self.regs.ccmr1_output().modify(|_, w| w.oc1pe().bit(value)),
1440 TimChannel::C2 => self.regs.ccmr1_output().modify(|_, w| w.oc2pe().bit(value)),
1441 TimChannel::C3 => self.regs.ccmr2_output().modify(|_, w| w.oc3pe().bit(value)),
1442 #[cfg(not(feature = "wl"))]
1443 TimChannel::C4 => self.regs.ccmr2_output().modify(|_, w| w.oc4pe().bit(value)),
1444 };
1445
1446 // "As the preload registers are transferred to the shadow registers only when an update event
1447 // occurs, before starting the counter, you have to initialize all the registers by setting the UG
1448 // bit in the TIMx_EGR register."
1449 self.reinitialize();
1450 }
1451 }
1452 };
1453}
1454
1455#[cfg(any(feature = "g0", feature = "g4", feature = "c0"))]
1456macro_rules! cc_2_channels {
1457 ($TIMX:ident, $res:ident) => {
1458 impl Timer<pac::$TIMX> {
1459 /// Function that allows us to set direction only on timers that have this option.
1460 fn set_dir(&mut self) {
1461 // self.regs.cr1().modify(|_, w| w.dir().bit(self.cfg.direction as u8 != 0));
1462 }
1463
1464 // todo: more advanced PWM modes. Asymmetric, combined, center-aligned etc.
1465
1466 /// Set up input capture, eg for PWM input.
1467 /// L4 RM, section 26.3.8. H723 RM, section 43.3.7.
1468 /// Note: Does not handle TISEL (timer input selection register - you must do this manually
1469 /// using the PAC.
1470 #[cfg(not(any(feature = "f", feature = "l4x5", feature = "l5", feature = "g0")))]
1471 pub fn set_input_capture(
1472 &mut self,
1473 channel: TimChannel,
1474 mode: CaptureCompare,
1475 // trigger: InputTrigger,
1476 // slave_mode: InputSlaveMode,
1477 ccp: Polarity,
1478 ccnp: Polarity,
1479 ) {
1480 self.set_capture_compare_input(channel, mode);
1481
1482 let filter = 0b00;
1483
1484 match channel {
1485 TimChannel::C1 => {
1486 self.regs.ccer().modify(|_, w| {
1487 w.cc1p().bit(ccp.bit());
1488 w.cc1np().bit(ccnp.bit())
1489 });
1490
1491 self.regs.ccmr1_input().modify(|_, w| unsafe {
1492 // w.ic1psc().bits(0b00);
1493 w.ic1f().bits(filter)
1494 });
1495 }
1496 TimChannel::C2 => {
1497 #[cfg(not(feature = "c0"))]
1498 self.regs.ccer().modify(|_, w| {
1499 w.cc2p().bit(ccp.bit());
1500 w.cc2np().bit(ccnp.bit())
1501 });
1502
1503 self.regs.ccmr1_input().modify(|_, w| unsafe {
1504 w.ic2psc().bits(0b00);
1505 w.ic2f().bits(filter)
1506 });
1507 }
1508 _ => panic!()
1509 }
1510
1511 // self.regs.smcr().modify(|_, w| unsafe {
1512 // w.ts().bits(trigger as u8);
1513 // w.sms().bits(slave_mode as u8)
1514 // });
1515
1516 self.enable_capture_compare(channel);
1517 }
1518
1519 /// Set Output Compare Mode. See docs on the `OutputCompare` enum.
1520 pub fn set_output_compare(&mut self, channel: TimChannel, mode: OutputCompare) {
1521 match channel {
1522 TimChannel::C1 => {
1523 self.regs.ccmr1_output().modify(|_, w| unsafe {
1524 #[cfg(not(any(feature = "f4", feature = "l5", feature = "wb")))]
1525 w.oc1m_3().bit((mode as u8) >> 3 != 0);
1526 w.oc1m().bits((mode as u8) & 0b111)
1527
1528 });
1529 }
1530 TimChannel::C2 => {
1531 self.regs.ccmr1_output().modify(|_, w| unsafe {
1532 #[cfg(not(any(feature = "f4", feature = "l5", feature = "wb")))]
1533 w.oc2m_3().bit((mode as u8) >> 3 != 0);
1534 w.oc2m().bits((mode as u8) & 0b111)
1535
1536 });
1537 }
1538 _ => panic!()
1539 }
1540 }
1541
1542 /// Return the set duty period for a given channel. Divide by `get_max_duty()`
1543 /// to find the portion of the duty cycle used.
1544 pub fn get_duty(&self, channel: TimChannel) -> $res {
1545 cfg_if! {
1546 if #[cfg(feature = "g0")] {
1547 match channel {
1548 TimChannel::C1 => self.regs.ccr1().read().bits().try_into().unwrap(),
1549 TimChannel::C2 => self.regs.ccr2().read().bits().try_into().unwrap(),
1550 _ => panic!()
1551 }
1552 } else if #[cfg(any(feature = "wb", feature = "wl", feature = "l5"))] {
1553 match channel {
1554 TimChannel::C1 => self.regs.ccr1().read().ccr1().bits(),
1555 TimChannel::C2 => self.regs.ccr2().read().ccr2().bits(),
1556 _ => panic!()
1557 }
1558 } else {
1559 match channel {
1560 TimChannel::C1 => self.regs.ccr1().read().ccr().bits().try_into().unwrap(),
1561 TimChannel::C2 => self.regs.ccr2().read().ccr().bits().try_into().unwrap(),
1562 _ => panic!()
1563 }
1564 }
1565 }
1566 }
1567
1568 /// Set the duty cycle, as a portion of ARR (`get_max_duty()`). Note that this
1569 /// needs to be re-run if you change ARR at any point.
1570 pub fn set_duty(&mut self, channel: TimChannel, duty: $res) {
1571 cfg_if! {
1572 if #[cfg(feature = "g0")] {
1573 match channel {
1574 // TimChannel::C1 => self.regs.ccr1().write(|w| w.ccr1().bits(duty.try_into().unwrap())),
1575 // TimChannel::C2 => self.regs.ccr2().write(|w| w.ccr2().bits(duty.try_into().unwrap())),
1576 _ => panic!()
1577 };
1578 } else if #[cfg(any(feature = "wb", feature = "wl", feature = "l5"))] {
1579 unsafe {
1580 match channel {
1581 TimChannel::C1 => self.regs.ccr1().write(|w| w.ccr1().bits(duty.try_into().unwrap())),
1582 TimChannel::C2 => self.regs.ccr2().write(|w| w.ccr2().bits(duty.try_into().unwrap())),
1583 _ => panic!()
1584 };
1585 }
1586 } else {
1587 unsafe {
1588 match channel {
1589 TimChannel::C1 => self.regs.ccr1().write(|w| w.ccr().bits(duty.try_into().unwrap())),
1590 TimChannel::C2 => self.regs.ccr2().write(|w| w.ccr().bits(duty.try_into().unwrap())),
1591 _ => panic!()
1592 };
1593 }
1594 }
1595 }
1596 }
1597
1598 /// Set output polarity. See docs on the `Polarity` enum.
1599 pub fn set_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1600 match channel {
1601 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1p().bit(polarity.bit())),
1602 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2p().bit(polarity.bit())),
1603 _ => panic!()
1604 };
1605 }
1606
1607 /// Set complementary output polarity. See docs on the `Polarity` enum.
1608 pub fn set_complementary_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1609 match channel {
1610 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1np().bit(polarity.bit())),
1611 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2np().bit(polarity.bit())),
1612 _ => panic!()
1613 };
1614 }
1615 /// Disables capture compare on a specific channel.
1616 pub fn disable_capture_compare(&mut self, channel: TimChannel) {
1617 match channel {
1618 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().clear_bit()),
1619 #[cfg(not(feature = "c0"))]
1620 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2e().clear_bit()),
1621 _ => panic!()
1622 };
1623 }
1624
1625 /// Enables capture compare on a specific channel.
1626 pub fn enable_capture_compare(&mut self, channel: TimChannel) {
1627 match channel {
1628 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().bit(true)),
1629 TimChannel::C2 => self.regs.ccer().modify(|_, w| w.cc2e().bit(true)),
1630 _ => panic!()
1631 };
1632 }
1633
1634 /// Set Capture Compare mode in output mode. See docs on the `CaptureCompare` enum.
1635 pub fn set_capture_compare_output(&mut self, channel: TimChannel, mode: CaptureCompare) {
1636 self.disable_capture_compare(channel);
1637
1638 match channel {
1639 TimChannel::C1 => self
1640 .regs
1641 .ccmr1_output()
1642 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1643 #[cfg(not(feature = "c0"))]
1644 TimChannel::C2 => self
1645 .regs
1646 .ccmr1_output()
1647 .modify(unsafe { |_, w| w.cc2s().bits(mode as u8) }),
1648 _ => panic!()
1649 };
1650 }
1651
1652 /// Set Capture Compare mode in input mode. See docs on the `CaptureCompare` enum.
1653 pub fn set_capture_compare_input(&mut self, channel: TimChannel, mode: CaptureCompare) {
1654 self.disable_capture_compare(channel);
1655
1656 match channel {
1657 // Note: CC1S bits are writable only when the channel is OFF (CC1E = 0 in TIMx_CCER)
1658 TimChannel::C1 => self
1659 .regs
1660 .ccmr1_input()
1661 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1662
1663 #[cfg(not(feature = "c0"))]
1664 TimChannel::C2 => self
1665 .regs
1666 .ccmr1_input()
1667 .modify(unsafe { |_, w| w.cc2s().bits(mode as u8) }),
1668 _ => panic!()
1669 };
1670 }
1671
1672 /// Set preload mode.
1673 /// OC1PE: Output Compare 1 preload enable
1674 /// 0: Preload register on TIMx_CCR1 disabled. TIMx_CCR1 can be written at anytime, the
1675 /// new value is taken in account immediately.
1676 /// 1: Preload register on TIMx_CCR1 enabled. Read/Write operations access the preload
1677 /// register. TIMx_CCR1 preload value is loaded in the active register at each update event.
1678 /// Note: 1: These bits can not be modified as long as LOCK level 3 has been programmed
1679 /// (LOCK bits in TIMx_BDTR register) and CC1S=’00’ (the channel is configured in
1680 /// output).
1681 /// 2: The PWM mode can be used without validating the preload register only in one
1682 /// pulse mode (OPM bit set in TIMx_CR1 register). Else the behavior is not guaranteed.
1683 ///
1684 /// Setting preload is required to enable PWM.
1685 pub fn set_preload(&mut self, channel: TimChannel, value: bool) {
1686 match channel {
1687 TimChannel::C1 => self.regs.ccmr1_output().modify(|_, w| w.oc1pe().bit(value)),
1688 #[cfg(not(feature = "c0"))]
1689 TimChannel::C2 => self.regs.ccmr1_output().modify(|_, w| w.oc2pe().bit(value)),
1690 _ => panic!()
1691 };
1692
1693 // "As the preload registers are transferred to the shadow registers only when an update event
1694 // occurs, before starting the counter, you have to initialize all the registers by setting the UG
1695 // bit in the TIMx_EGR register."
1696 self.reinitialize();
1697 }
1698
1699 }
1700 }
1701}
1702
1703macro_rules! cc_1_channel {
1704 ($TIMX:ident, $res:ident) => {
1705 impl Timer<pac::$TIMX> {
1706 /// Function that allows us to set direction only on timers that have this option.
1707 fn set_dir(&mut self) {} // N/A with these 1-channel timers.
1708
1709 // todo: more advanced PWM modes. Asymmetric, combined, center-aligned etc.
1710
1711 /// Set up input capture, eg for PWM input.
1712 /// L4 RM, section 26.3.8. H723 RM, section 43.3.7.
1713 /// Note: Does not handle TISEL (timer input selection register - you must do this manually
1714 /// using the PAC.
1715 #[cfg(not(any(feature = "f", feature = "l4x5", feature = "l5", feature = "g0")))]
1716 pub fn set_input_capture(
1717 &mut self,
1718 channel: TimChannel,
1719 mode: CaptureCompare,
1720 // trigger: InputTrigger,
1721 // slave_mode: InputSlaveMode,
1722 ccp: Polarity,
1723 ccnp: Polarity,
1724 ) {
1725 self.set_capture_compare_input(channel, mode);
1726
1727 let filter = 0b00;
1728
1729 match channel {
1730 TimChannel::C1 => {
1731 self.regs.ccer().modify(|_, w| {
1732 w.cc1p().bit(ccp.bit());
1733 w.cc1np().bit(ccnp.bit())
1734 });
1735
1736 self.regs.ccmr1_input().modify(|_, w| unsafe {
1737 w.ic1psc().bits(0b00);
1738 w.ic1f().bits(filter)
1739 });
1740 }
1741 _ => panic!(),
1742 };
1743
1744 // todo?
1745 // self.regs.smcr().modify(|_, w| unsafe {
1746 // w.ts().bits(trigger as u8);
1747 // w.sms().bits(slave_mode as u8)
1748 // });
1749
1750 self.enable_capture_compare(channel);
1751 }
1752
1753 /// Set Output Compare Mode. See docs on the `OutputCompare` enum.
1754 pub fn set_output_compare(&mut self, channel: TimChannel, mode: OutputCompare) {
1755 match channel {
1756 TimChannel::C1 => {
1757 #[cfg(not(feature = "g070"))] // todo: PAC bug?
1758 self.regs.ccmr1_output().modify(|_, w| unsafe {
1759 // todo: L5/WB is probably due to a PAC error. Has oc1m_2.
1760 #[cfg(not(any(
1761 feature = "f",
1762 feature = "l4",
1763 feature = "l5",
1764 feature = "wb",
1765 feature = "g0"
1766 )))]
1767 w.oc1m_3().bit((mode as u8) >> 3 != 0);
1768 w.oc1m().bits((mode as u8) & 0b111)
1769 });
1770 }
1771 _ => panic!(),
1772 };
1773 }
1774
1775 /// Return the set duty period for a given channel. Divide by `get_max_duty()`
1776 /// to find the portion of the duty cycle used.
1777 pub fn get_duty(&self, channel: TimChannel) -> $res {
1778 match channel {
1779 TimChannel::C1 => self.regs.ccr1().read().ccr().bits().try_into().unwrap(),
1780 _ => panic!(),
1781 }
1782 }
1783
1784 /// Set the duty cycle, as a portion of ARR (`get_max_duty()`). Note that this
1785 /// needs to be re-run if you change ARR at any point.
1786 pub fn set_duty(&mut self, channel: TimChannel, duty: $res) {
1787 unsafe {
1788 match channel {
1789 TimChannel::C1 => self
1790 .regs
1791 .ccr1()
1792 .write(|w| w.ccr().bits(duty.try_into().unwrap())),
1793 _ => panic!(),
1794 };
1795 }
1796 }
1797
1798 /// Set output polarity. See docs on the `Polarity` enum.
1799 pub fn set_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1800 match channel {
1801 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1p().bit(polarity.bit())),
1802 _ => panic!(),
1803 };
1804 }
1805
1806 /// Set complementary output polarity. See docs on the `Polarity` enum.
1807 pub fn set_complementary_polarity(&mut self, channel: TimChannel, polarity: Polarity) {
1808 match channel {
1809 TimChannel::C1 => self
1810 .regs
1811 .ccer()
1812 .modify(|_, w| w.cc1np().bit(polarity.bit())),
1813 _ => panic!(),
1814 };
1815 }
1816 /// Disables capture compare on a specific channel.
1817 pub fn disable_capture_compare(&mut self, channel: TimChannel) {
1818 match channel {
1819 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().clear_bit()),
1820 _ => panic!(),
1821 };
1822 }
1823
1824 /// Enables capture compare on a specific channel.
1825 pub fn enable_capture_compare(&mut self, channel: TimChannel) {
1826 match channel {
1827 TimChannel::C1 => self.regs.ccer().modify(|_, w| w.cc1e().bit(true)),
1828 _ => panic!(),
1829 };
1830 }
1831
1832 /// Set Capture Compare mode in output mode. See docs on the `CaptureCompare` enum.
1833 pub fn set_capture_compare_output(
1834 &mut self,
1835 channel: TimChannel,
1836 mode: CaptureCompare,
1837 ) {
1838 self.disable_capture_compare(channel);
1839
1840 match channel {
1841 TimChannel::C1 => self
1842 .regs
1843 .ccmr1_output()
1844 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1845 _ => panic!(),
1846 };
1847 }
1848
1849 /// Set Capture Compare mode in input mode. See docs on the `CaptureCompare` enum.
1850 pub fn set_capture_compare_input(&mut self, channel: TimChannel, mode: CaptureCompare) {
1851 self.disable_capture_compare(channel);
1852
1853 match channel {
1854 TimChannel::C1 => self
1855 .regs
1856 .ccmr1_input()
1857 .modify(unsafe { |_, w| w.cc1s().bits(mode as u8) }),
1858 _ => panic!(),
1859 };
1860 }
1861
1862 /// Set preload mode.
1863 /// OC1PE: Output Compare 1 preload enable
1864 /// 0: Preload register on TIMx_CCR1 disabled. TIMx_CCR1 can be written at anytime, the
1865 /// new value is taken in account immediately.
1866 /// 1: Preload register on TIMx_CCR1 enabled. Read/Write operations access the preload
1867 /// register. TIMx_CCR1 preload value is loaded in the active register at each update event.
1868 /// Note: 1: These bits can not be modified as long as LOCK level 3 has been programmed
1869 /// (LOCK bits in TIMx_BDTR register) and CC1S=’00’ (the channel is configured in
1870 /// output).
1871 /// 2: The PWM mode can be used without validating the preload register only in one
1872 /// pulse mode (OPM bit set in TIMx_CR1 register). Else the behavior is not guaranteed.
1873 ///
1874 /// Setting preload is required to enable PWM.
1875 pub fn set_preload(&mut self, channel: TimChannel, value: bool) {
1876 match channel {
1877 TimChannel::C1 => self.regs.ccmr1_output().modify(|_, w| w.oc1pe().bit(value)),
1878 _ => panic!(),
1879 };
1880
1881 // "As the preload registers are transferred to the shadow registers only when an update event
1882 // occurs, before starting the counter, you have to initialize all the registers by setting the UG
1883 // bit in the TIMx_EGR register."
1884 self.reinitialize();
1885 }
1886 }
1887 };
1888}
1889
1890/// Calculate values required to set the timer frequency: `PSC` and `ARR`. This can be
1891/// used for initial timer setup, or changing the value later. If used in performance-sensitive
1892/// code or frequently, set ARR and PSC directly instead of using this.
1893fn calc_freq_vals(freq: f32, clock_speed: u32) -> Result<(u16, u16), ValueError> {
1894 // `period` and `clock_speed` are both in Hz.
1895
1896 // PSC and ARR range: 0 to 65535
1897 // (PSC+1)*(ARR+1) = TIMclk/Updatefrequency = TIMclk * period
1898 // APB1 (pclk1) is used by Tim2, 3, 4, 6, 7.
1899 // APB2 (pclk2) is used by Tim8, 15-20 etc.
1900
1901 // We need to factor the right-hand-side of the above equation
1902 // into integers. There are likely clever algorithms available to do this.
1903 // Some examples: https://cp-algorithms.com/algebra/factorization.html
1904 // We've chosen something that attempts to maximize ARR, for precision when
1905 // setting duty cycle. Alternative approaches might involve setting a frequency closest to the
1906 // requested one.
1907
1908 // If you work with pure floats, there are an infinite number of solutions: Ie for any value of PSC,
1909 // you can find an ARR to solve the equation.
1910 // The actual values are integers that must be between 0 and 65_536
1911 // Different combinations will result in different amounts of rounding error.
1912
1913 let max_val = 65_535.;
1914 let rhs = clock_speed as f32 / freq;
1915
1916 let psc = ((rhs - 1.) / (1 << 16) as f32).round();
1917 let arr = rhs / (psc + 1.) - 1.;
1918
1919 if arr > max_val || psc > max_val {
1920 return Err(ValueError {});
1921 }
1922
1923 Ok((psc as u16, arr as u16))
1924}
1925
1926cfg_if! {
1927 if #[cfg(not(any(
1928 feature = "f401",
1929 feature = "f410",
1930 feature = "f411",
1931 feature = "f413",
1932 feature = "g031",
1933 feature = "g041",
1934 feature = "g070",
1935 feature = "g030",
1936 feature = "g051",
1937 feature = "c0",
1938 feature = "wb",
1939 feature = "wl"
1940 )))] {
1941 /// Represents a Basic timer, used primarily to trigger the onboard DAC. Eg Tim6 or Tim7.
1942 pub struct BasicTimer<R> {
1943 pub regs: R,
1944 clock_speed: u32,
1945 }
1946
1947 impl<R> BasicTimer<R>
1948 where
1949 R: Deref<Target = pac::tim6::RegisterBlock> + RccPeriph,
1950 {
1951 /// Initialize a Basic timer, including enabling and resetting
1952 /// its RCC peripheral clock.
1953 pub fn new(
1954 regs: R,
1955 freq: f32,
1956 clock_cfg: &Clocks,
1957 ) -> Self {
1958 let rcc = unsafe { &(*RCC::ptr()) };
1959 R::en_reset(rcc);
1960
1961 // Self { regs, config, clock_speed: clocks.apb1_timer() }
1962 let mut result = Self { regs, clock_speed: clock_cfg.apb1_timer() };
1963
1964 result.set_freq(freq).ok();
1965 result
1966 }
1967
1968 // todo: These fns are DRY from GP timer code!
1969
1970 /// Enable the timer.
1971 pub fn enable(&mut self) {
1972 self.regs.cr1().modify(|_, w| w.cen().bit(true));
1973 }
1974
1975 /// Disable the timer.
1976 pub fn disable(&mut self) {
1977 self.regs.cr1().modify(|_, w| w.cen().clear_bit());
1978 }
1979
1980 /// Check if the timer is enabled.
1981 pub fn is_enabled(&self) -> bool {
1982 self.regs.cr1().read().cen().bit_is_set()
1983 }
1984
1985 /// Set the timer period, in seconds. Overrides the period or frequency set
1986 /// in the constructor. If changing pe riod frequently, don't use this method, as
1987 /// it has computational overhead: use `set_auto_reload` and `set_prescaler` methods instead.
1988 pub fn set_period(&mut self, time: f32) -> Result<(), ValueError> {
1989 assert!(time > 0.);
1990 self.set_freq(1. / time)
1991 }
1992
1993 /// Set the timer frequency, in Hz. Overrides the period or frequency set
1994 /// in the constructor. If changing frequency frequently, don't use this method, as
1995 /// it has computational overhead: use `set_auto_reload` and `set_prescaler` methods instead.
1996 pub fn set_freq(&mut self, freq: f32) -> Result<(), ValueError> {
1997 assert!(freq > 0.);
1998
1999 let (psc, arr) = calc_freq_vals(freq, self.clock_speed)?;
2000
2001 self.regs.arr().write(|w| unsafe { w.bits(arr.into()) });
2002 self.regs.psc().write(|w| unsafe { w.bits(psc.into()) });
2003
2004 Ok(())
2005 }
2006
2007 /// Return the integer associated with the maximum duty period.
2008 pub fn get_max_duty(&self) -> u32 {
2009 return self.regs.arr().read().bits()
2010 }
2011
2012 /// Set the auto-reload register value. Used for adjusting frequency.
2013 pub fn set_auto_reload(&mut self, arr: u16) {
2014 self.regs.arr().write(|w| unsafe { w.bits(arr.into()) });
2015 }
2016
2017 /// Set the prescaler value. Used for adjusting frequency.
2018 pub fn set_prescaler(&mut self, psc: u16) {
2019 self.regs.psc().write(|w| unsafe { w.bits(psc.into()) });
2020 }
2021
2022 /// Reset the count; set the counter to 0.
2023 pub fn reset_count(&mut self) {
2024 self.regs.cnt().write(|w| unsafe { w.bits(0) });
2025 }
2026
2027 /// Read the current counter value.
2028 pub fn read_count(&self) -> u16 {
2029 #[cfg(feature = "l5")]
2030 return self.regs.cnt().read().bits() as u16;
2031 #[cfg(not(feature = "l5"))]
2032 self.regs.cnt().read().cnt().bits()
2033 }
2034
2035 /// Allow selected information to be sent in master mode to slave timers for
2036 /// synchronization (TRGO).
2037 pub fn set_mastermode(&self, mode: MasterModeSelection) {
2038 self.regs.cr2().modify(|_, w| unsafe { w.mms().bits(mode as u8) });
2039 }
2040 }
2041 }
2042}
2043
2044/// A freestanding function that does not require access to a `Timer` struct. Clears the Update interrupt.
2045pub fn clear_update_interrupt(tim_num: u8) {
2046 unsafe {
2047 let periphs = pac::Peripherals::steal();
2048
2049 let bits = 0xffff_ffff;
2050
2051 // Note: `.try_into().unwrap()` is for C0.
2052
2053 match tim_num {
2054 #[cfg(not(any(feature = "f373")))]
2055 1 => {
2056 periphs.TIM1.sr().write(|w| w.bits(bits).uif().clear_bit());
2057 }
2058 #[cfg(not(any(
2059 feature = "f410",
2060 feature = "g070",
2061 feature = "g030",
2062 feature = "g031",
2063 feature = "g050",
2064 feature = "g061",
2065 feature = "c011",
2066 feature = "c031",
2067 )))]
2068 2 => {
2069 periphs
2070 .TIM2
2071 .sr()
2072 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2073 }
2074 #[cfg(not(any(
2075 feature = "f301",
2076 feature = "l4x1",
2077 // feature = "l412",
2078 feature = "l4x3",
2079 feature = "l412",
2080 feature = "f410",
2081 feature = "wb",
2082 feature = "wl"
2083 )))]
2084 3 => {
2085 periphs
2086 .TIM3
2087 .sr()
2088 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2089 }
2090 #[cfg(not(any(
2091 feature = "f301",
2092 feature = "f3x4",
2093 feature = "f410",
2094 feature = "l4x1",
2095 feature = "l4x2",
2096 feature = "l412",
2097 feature = "l4x3",
2098 feature = "g0",
2099 feature = "c0",
2100 feature = "wb",
2101 feature = "wl"
2102 )))]
2103 4 => {
2104 periphs.TIM4.sr().write(|w| w.bits(bits).uif().clear_bit());
2105 }
2106 #[cfg(any(
2107 feature = "f373",
2108 feature = "l4x5",
2109 feature = "l4x6",
2110 feature = "l5",
2111 feature = "h5",
2112 feature = "h7",
2113 feature = "g473",
2114 feature = "g474",
2115 feature = "g483",
2116 feature = "g484",
2117 all(feature = "f4", not(feature = "f410")),
2118 ))]
2119 5 => {
2120 periphs.TIM5.sr().write(|w| w.bits(bits).uif().clear_bit());
2121 }
2122 #[cfg(any(
2123 feature = "f303",
2124 feature = "l4x5",
2125 feature = "l4x6",
2126 feature = "l562",
2127 feature = "h5",
2128 feature = "h7",
2129 ))]
2130 8 => {
2131 periphs.TIM8.sr().write(|w| w.bits(bits).uif().clear_bit());
2132 }
2133 #[cfg(any(feature = "h5",))]
2134 12 => {
2135 periphs.TIM12.sr().write(|w| w.bits(bits).uif().clear_bit());
2136 }
2137 #[cfg(any(feature = "h5",))]
2138 13 => {
2139 periphs.TIM13.sr().write(|w| w.bits(bits).uif().clear_bit());
2140 }
2141 #[cfg(any(feature = "h5", feature = "c0",))]
2142 14 => {
2143 periphs
2144 .TIM14
2145 .sr()
2146 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2147 }
2148 #[cfg(not(any(
2149 feature = "f4",
2150 feature = "g031",
2151 feature = "g031",
2152 feature = "g041",
2153 feature = "g030",
2154 feature = "g051",
2155 feature = "g061",
2156 feature = "wb",
2157 feature = "wl",
2158 feature = "c0",
2159 )))]
2160 15 => {
2161 periphs
2162 .TIM15
2163 .sr()
2164 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2165 }
2166 #[cfg(not(any(feature = "f4",)))]
2167 16 => {
2168 periphs
2169 .TIM16
2170 .sr()
2171 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2172 }
2173 #[cfg(not(any(
2174 feature = "l4x1",
2175 feature = "l4x2",
2176 feature = "l412",
2177 feature = "l4x3",
2178 feature = "f4",
2179 )))]
2180 17 => {
2181 periphs
2182 .TIM17
2183 .sr()
2184 .write(|w| w.bits(bits.try_into().unwrap()).uif().clear_bit());
2185 }
2186 _ => unimplemented!(),
2187 }
2188 };
2189}
2190
2191// /// Experimental approach where we set frequency without taking ownership.
2192// pub fn set_freq(timer: TimerNum, mut freq: f32) -> Result<(), ValueError> {
2193//
2194// }
2195
2196// todo: Non-macro refactor base timer reg blocks:
2197
2198// GP 32-bit: Tim2
2199// 2, 3, 4, 5
2200
2201// GP 16-bit:
2202// 15, 16, 17 // (9-14 on F4) 14 on G0
2203
2204// Basic:
2205// 6, 7
2206
2207// Advanced: 1/8/20
2208
2209#[cfg(not(any(feature = "f373")))]
2210make_timer!(TIM1, tim1, 2, u16);
2211
2212#[cfg(not(any(feature = "f373", feature = "g0", feature = "g4")))]
2213cc_4_channels!(TIM1, u16);
2214// todo: PAC error?
2215// TIM1 on G4 is nominally 16-bits, but has ~20 bits on ARR, with PAC showing 32 bits?
2216#[cfg(any(feature = "g0", feature = "g4"))]
2217cc_2_channels!(TIM1, u16);
2218
2219cfg_if! {
2220 if #[cfg(not(any(
2221 feature = "f410",
2222 feature = "g070",
2223 feature = "l5", // todo PAC bug?
2224 feature = "wb55", // todo PAC bug?
2225 feature = "g030",
2226 feature = "g031",
2227 feature = "g050",
2228 feature = "g061",
2229 feature = "g031",
2230 feature = "c011",
2231 feature = "c031",
2232 )))] {
2233 make_timer!(TIM2, tim2, 1, u32);
2234 cc_4_channels!(TIM2, u32);
2235 }
2236}
2237
2238// todo: Note. G4, for example, has TIM2 and 5 as 32-bit, and TIM3 and 4 as 16-bit per RM,
2239// todo: But PAC shows different.
2240cfg_if! {
2241 if #[cfg(not(any(
2242 feature = "f301",
2243 feature = "l4x1",
2244 // feature = "l412",
2245 feature = "l5", // todo PAC bug?
2246 feature = "l4x3",
2247 feature = "l412",
2248 feature = "f410",
2249 feature = "wb",
2250 feature = "wl",
2251 // feature = "c0",
2252 )))] {
2253 make_timer!(TIM3, tim3, 1, u32);
2254 cc_4_channels!(TIM3, u32);
2255 }
2256}
2257
2258// #[cfg(feature = "c0")]
2259// make_timer!(TIM3, tim3, 1, u16);
2260// #[cfg(feature = "c0")]
2261// cc_4_channels!(TIM3, u16);
2262
2263cfg_if! {
2264 if #[cfg(not(any(
2265 feature = "f301",
2266 feature = "f3x4",
2267 feature = "f410",
2268 feature = "l4x1",
2269 feature = "l4x2",
2270 feature = "l412",
2271 feature = "l4x3",
2272 feature = "g0",
2273 feature = "c0",
2274 feature = "wb",
2275 feature = "wl"
2276 )))] {
2277 make_timer!(TIM4, tim4, 1, u32);
2278 cc_4_channels!(TIM4, u32);
2279 }
2280}
2281
2282cfg_if! {
2283 if #[cfg(any(
2284 feature = "f373",
2285 feature = "l4x5",
2286 feature = "l4x6",
2287 feature = "l562",
2288 feature = "h5",
2289 feature = "h7",
2290 feature = "g473",
2291 feature = "g474",
2292 feature = "g483",
2293 feature = "g484",
2294 all(feature = "f4", not(feature = "f410")),
2295 ))] {
2296 make_timer!(TIM5, tim5, 1, u32);
2297 cc_4_channels!(TIM5, u32);
2298 }
2299}
2300
2301cfg_if! {
2302 if #[cfg(any(
2303 feature = "f303",
2304 feature = "l4x5",
2305 feature = "l4x6",
2306 feature = "l562",
2307 feature = "h5",
2308 feature = "h7",
2309 ))] {
2310 make_timer!(TIM8, tim8, 2, u16);
2311 // todo: Some issues with field names or something on l562 here.
2312 #[cfg(not(feature = "l5"))] // PAC bug.
2313 cc_4_channels!(TIM8, u16);
2314 #[cfg(feature = "l5")] // PAC bug.
2315 cc_1_channel!(TIM8, u16);
2316 }
2317}
2318
2319// todo: G4 should be 16-bits for TIM8. Why does the PAC use 32?
2320cfg_if! {
2321 if #[cfg(feature = "g4")] {
2322 make_timer!(TIM8, tim8, 2, u32);
2323 cc_4_channels!(TIM8, u32);
2324 }
2325}
2326
2327cfg_if! {
2328 if #[cfg(feature = "h5")] {
2329 make_timer!(TIM12, tim12, 1, u32);
2330 cc_2_channels!(TIM12, u32);
2331
2332 make_timer!(TIM13, tim13, 1, u32);
2333 cc_2_channels!(TIM13, u32);
2334
2335 make_timer!(TIM14, tim14, 1, u32);
2336 cc_2_channels!(TIM14, u32);
2337 }
2338}
2339
2340// #[cfg(feature = "c0")]
2341// make_timer!(TIM14, tim14, 1, u32);
2342// #[cfg(feature = "c0")]
2343// cc_2_channels!(TIM14, u16);
2344
2345cfg_if! {
2346 if #[cfg(not(any(
2347 feature = "f4",
2348 feature = "g031",
2349 feature = "g031",
2350 feature = "g041",
2351 feature = "g030",
2352 feature = "g051",
2353 feature = "g061",
2354 feature = "wb",
2355 feature = "wl",
2356 // todo: Tim15 is available on c091/02, but I don't see a PAC for that.
2357 feature = "c0",
2358 )))] {
2359 make_timer!(TIM15, tim15, 2, u16);
2360 // todo: TIM15 on some variant has 2 channels (Eg H7). On others, like L4x3, it appears to be 1.
2361 cc_1_channel!(TIM15, u16);
2362 }
2363}
2364
2365#[cfg(not(any(feature = "f4", feature = "c0")))]
2366make_timer!(TIM16, tim16, 2, u16);
2367#[cfg(not(any(feature = "f4", feature = "c0")))]
2368cc_1_channel!(TIM16, u16);
2369
2370#[cfg(feature = "c0")]
2371make_timer!(TIM16, tim16, 2, u32);
2372#[cfg(feature = "c0")]
2373cc_1_channel!(TIM16, u32);
2374
2375cfg_if! {
2376 if #[cfg(not(any(
2377 feature = "l4x1",
2378 feature = "l4x2",
2379 feature = "l412",
2380 feature = "l4x3",
2381 feature = "f4",
2382 // feature = "c0"
2383 )))] {
2384 make_timer!(TIM17, tim17, 2, u16);
2385 cc_1_channel!(TIM17, u16);
2386 }
2387}
2388
2389// cfg_if! {
2390// if #[cfg(any(
2391// feature = "c0"
2392// ))] {
2393// make_timer!(TIM17, tim17, 2, u32);
2394// cc_1_channel!(TIM17, u32);
2395// }
2396// }
2397
2398// { todo: tim18
2399// TIM18: (tim18, apb2, enr, rstr),
2400// },
2401
2402cfg_if! {
2403 if #[cfg(any(feature = "f373"))] {
2404 make_timer!(TIM12, tim12, 1, u16);
2405 make_timer!(TIM13, tim13, 1, u16);
2406 make_timer!(TIM14, tim14, 1, u16);
2407 make_timer!(TIM19, tim19, 2, u16);
2408
2409 cc_1_channel!(TIM12, u16);
2410 cc_1_channel!(TIM13, u16);
2411 cc_1_channel!(TIM14, u16);
2412 cc_1_channel!(TIM19, u16);
2413 }
2414}
2415
2416// todo: G4 (maybe not all variants?) have TIM20.
2417#[cfg(any(feature = "f303"))]
2418make_timer!(TIM20, tim20, 2, u16);
2419#[cfg(any(feature = "f303"))]
2420cc_4_channels!(TIM20, u16);
2421
2422// todo: Remove the final "true/false" for adv ctrl. You need a sep macro like you do for ccx_channel!.