aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-03-23 00:35:06 +0100
committerDario Nieuwenhuis <[email protected]>2024-03-23 01:37:28 +0100
commit389cbc0a77daea15decae706818f104d89446020 (patch)
tree4f65728f3d898b779810b6355bce8e46c26e8d0f
parentc2aa95016a6891782bf4e04d7c78e30bcb3afd9c (diff)
stm32/timer: simplify traits, convert from trait methods to struct.
-rwxr-xr-xci.sh1
-rw-r--r--embassy-stm32/src/time_driver.rs34
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs38
-rw-r--r--embassy-stm32/src/timer/low_level.rs638
-rw-r--r--embassy-stm32/src/timer/mod.rs1005
-rw-r--r--embassy-stm32/src/timer/qei.rs33
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs46
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm.rs5
-rw-r--r--examples/stm32h7/src/bin/dac_dma.rs26
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs34
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs26
11 files changed, 882 insertions, 1004 deletions
diff --git a/ci.sh b/ci.sh
index cd82af2f1..d17f4e13e 100755
--- a/ci.sh
+++ b/ci.sh
@@ -124,6 +124,7 @@ cargo batch \
124 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ 124 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \
125 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ 125 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \
126 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ 126 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \
127 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-tim1,time \
127 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \ 128 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \
128 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ 129 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
129 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \ 130 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index e78f81dca..c961fc14b 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -8,7 +8,7 @@ use critical_section::CriticalSection;
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_sync::blocking_mutex::Mutex; 9use embassy_sync::blocking_mutex::Mutex;
10use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; 10use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ};
11use stm32_metapac::timer::regs; 11use stm32_metapac::timer::{regs, TimGp16};
12 12
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::timer::vals; 14use crate::pac::timer::vals;
@@ -16,8 +16,8 @@ use crate::rcc::sealed::RccPeripheral;
16#[cfg(feature = "low-power")] 16#[cfg(feature = "low-power")]
17use crate::rtc::Rtc; 17use crate::rtc::Rtc;
18#[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] 18#[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))]
19use crate::timer::sealed::AdvancedControlInstance; 19use crate::timer::AdvancedInstance1Channel;
20use crate::timer::sealed::{CoreInstance, GeneralPurpose16bitInstance as Instance}; 20use crate::timer::CoreInstance;
21use crate::{interrupt, peripherals}; 21use crate::{interrupt, peripherals};
22 22
23// NOTE regarding ALARM_COUNT: 23// NOTE regarding ALARM_COUNT:
@@ -207,6 +207,10 @@ foreach_interrupt! {
207 }; 207 };
208} 208}
209 209
210fn regs_gp16() -> TimGp16 {
211 unsafe { TimGp16::from_ptr(T::regs()) }
212}
213
210// Clock timekeeping works with something we call "periods", which are time intervals 214// Clock timekeeping works with something we call "periods", which are time intervals
211// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods. 215// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods.
212// 216//
@@ -271,7 +275,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
271 275
272impl RtcDriver { 276impl RtcDriver {
273 fn init(&'static self, cs: critical_section::CriticalSection) { 277 fn init(&'static self, cs: critical_section::CriticalSection) {
274 let r = T::regs_gp16(); 278 let r = regs_gp16();
275 279
276 <T as RccPeripheral>::enable_and_reset_with_cs(cs); 280 <T as RccPeripheral>::enable_and_reset_with_cs(cs);
277 281
@@ -308,9 +312,9 @@ impl RtcDriver {
308 312
309 #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] 313 #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))]
310 { 314 {
311 <T as AdvancedControlInstance>::CaptureCompareInterrupt::unpend(); 315 <T as AdvancedInstance1Channel>::CaptureCompareInterrupt::unpend();
312 unsafe { 316 unsafe {
313 <T as AdvancedControlInstance>::CaptureCompareInterrupt::enable(); 317 <T as AdvancedInstance1Channel>::CaptureCompareInterrupt::enable();
314 } 318 }
315 } 319 }
316 320
@@ -318,7 +322,7 @@ impl RtcDriver {
318 } 322 }
319 323
320 fn on_interrupt(&self) { 324 fn on_interrupt(&self) {
321 let r = T::regs_gp16(); 325 let r = regs_gp16();
322 326
323 // XXX: reduce the size of this critical section ? 327 // XXX: reduce the size of this critical section ?
324 critical_section::with(|cs| { 328 critical_section::with(|cs| {
@@ -349,7 +353,7 @@ impl RtcDriver {
349 } 353 }
350 354
351 fn next_period(&self) { 355 fn next_period(&self) {
352 let r = T::regs_gp16(); 356 let r = regs_gp16();
353 357
354 // We only modify the period from the timer interrupt, so we know this can't race. 358 // We only modify the period from the timer interrupt, so we know this can't race.
355 let period = self.period.load(Ordering::Relaxed) + 1; 359 let period = self.period.load(Ordering::Relaxed) + 1;
@@ -413,7 +417,7 @@ impl RtcDriver {
413 /// Add the given offset to the current time 417 /// Add the given offset to the current time
414 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) { 418 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
415 let offset = offset.as_ticks(); 419 let offset = offset.as_ticks();
416 let cnt = T::regs_gp16().cnt().read().cnt() as u32; 420 let cnt = regs_gp16().cnt().read().cnt() as u32;
417 let period = self.period.load(Ordering::SeqCst); 421 let period = self.period.load(Ordering::SeqCst);
418 422
419 // Correct the race, if it exists 423 // Correct the race, if it exists
@@ -439,7 +443,7 @@ impl RtcDriver {
439 let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period }; 443 let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period };
440 444
441 self.period.store(period, Ordering::SeqCst); 445 self.period.store(period, Ordering::SeqCst);
442 T::regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); 446 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16));
443 447
444 // Now, recompute all alarms 448 // Now, recompute all alarms
445 for i in 0..ALARM_COUNT { 449 for i in 0..ALARM_COUNT {
@@ -496,7 +500,7 @@ impl RtcDriver {
496 .unwrap() 500 .unwrap()
497 .start_wakeup_alarm(time_until_next_alarm, cs); 501 .start_wakeup_alarm(time_until_next_alarm, cs);
498 502
499 T::regs_gp16().cr1().modify(|w| w.set_cen(false)); 503 regs_gp16().cr1().modify(|w| w.set_cen(false));
500 504
501 Ok(()) 505 Ok(())
502 } 506 }
@@ -506,7 +510,7 @@ impl RtcDriver {
506 #[cfg(feature = "low-power")] 510 #[cfg(feature = "low-power")]
507 /// Resume the timer with the given offset 511 /// Resume the timer with the given offset
508 pub(crate) fn resume_time(&self) { 512 pub(crate) fn resume_time(&self) {
509 if T::regs_gp16().cr1().read().cen() { 513 if regs_gp16().cr1().read().cen() {
510 // Time isn't currently stopped 514 // Time isn't currently stopped
511 515
512 return; 516 return;
@@ -515,14 +519,14 @@ impl RtcDriver {
515 critical_section::with(|cs| { 519 critical_section::with(|cs| {
516 self.stop_wakeup_alarm(cs); 520 self.stop_wakeup_alarm(cs);
517 521
518 T::regs_gp16().cr1().modify(|w| w.set_cen(true)); 522 regs_gp16().cr1().modify(|w| w.set_cen(true));
519 }) 523 })
520 } 524 }
521} 525}
522 526
523impl Driver for RtcDriver { 527impl Driver for RtcDriver {
524 fn now(&self) -> u64 { 528 fn now(&self) -> u64 {
525 let r = T::regs_gp16(); 529 let r = regs_gp16();
526 530
527 let period = self.period.load(Ordering::Relaxed); 531 let period = self.period.load(Ordering::Relaxed);
528 compiler_fence(Ordering::Acquire); 532 compiler_fence(Ordering::Acquire);
@@ -553,7 +557,7 @@ impl Driver for RtcDriver {
553 557
554 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { 558 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
555 critical_section::with(|cs| { 559 critical_section::with(|cs| {
556 let r = T::regs_gp16(); 560 let r = regs_gp16();
557 561
558 let n = alarm.id() as usize; 562 let n = alarm.id() as usize;
559 let alarm = self.get_alarm(cs, alarm); 563 let alarm = self.get_alarm(cs, alarm);
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 723e8506b..a892646cf 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -5,11 +5,15 @@ use core::marker::PhantomData;
5use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
6use stm32_metapac::timer::vals::Ckd; 6use stm32_metapac::timer::vals::Ckd;
7 7
8use super::simple_pwm::*; 8use super::low_level::{CountingMode, OutputPolarity, Timer};
9use super::*; 9use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin};
10#[allow(unused_imports)] 10use super::{
11use crate::gpio::sealed::{AFType, Pin}; 11 AdvancedInstance4Channel, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin, Channel3ComplementaryPin,
12 Channel4ComplementaryPin,
13};
12use crate::gpio::{AnyPin, OutputType}; 14use crate::gpio::{AnyPin, OutputType};
15use crate::time::Hertz;
16use crate::timer::low_level::OutputCompareMode;
13use crate::Peripheral; 17use crate::Peripheral;
14 18
15/// Complementary PWM pin wrapper. 19/// Complementary PWM pin wrapper.
@@ -22,7 +26,7 @@ pub struct ComplementaryPwmPin<'d, T, C> {
22 26
23macro_rules! complementary_channel_impl { 27macro_rules! complementary_channel_impl {
24 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 28 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
25 impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { 29 impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> {
26 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] 30 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
27 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { 31 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
28 into_ref!(pin); 32 into_ref!(pin);
@@ -47,11 +51,11 @@ complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
47complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); 51complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
48 52
49/// PWM driver with support for standard and complementary outputs. 53/// PWM driver with support for standard and complementary outputs.
50pub struct ComplementaryPwm<'d, T> { 54pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> {
51 inner: PeripheralRef<'d, T>, 55 inner: Timer<'d, T>,
52} 56}
53 57
54impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { 58impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
55 /// Create a new complementary PWM driver. 59 /// Create a new complementary PWM driver.
56 #[allow(clippy::too_many_arguments)] 60 #[allow(clippy::too_many_arguments)]
57 pub fn new( 61 pub fn new(
@@ -71,11 +75,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
71 } 75 }
72 76
73 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { 77 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self {
74 into_ref!(tim); 78 let mut this = Self { inner: Timer::new(tim) };
75
76 T::enable_and_reset();
77
78 let mut this = Self { inner: tim };
79 79
80 this.inner.set_counting_mode(counting_mode); 80 this.inner.set_counting_mode(counting_mode);
81 this.set_frequency(freq); 81 this.set_frequency(freq);
@@ -122,7 +122,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
122 /// 122 ///
123 /// This value depends on the configured frequency and the timer's clock rate from RCC. 123 /// This value depends on the configured frequency and the timer's clock rate from RCC.
124 pub fn get_max_duty(&self) -> u16 { 124 pub fn get_max_duty(&self) -> u16 {
125 self.inner.get_max_compare_value() + 1 125 self.inner.get_max_compare_value() as u16 + 1
126 } 126 }
127 127
128 /// Set the duty for a given channel. 128 /// Set the duty for a given channel.
@@ -130,7 +130,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
130 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. 130 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
131 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 131 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
132 assert!(duty <= self.get_max_duty()); 132 assert!(duty <= self.get_max_duty());
133 self.inner.set_compare_value(channel, duty) 133 self.inner.set_compare_value(channel, duty as _)
134 } 134 }
135 135
136 /// Set the output polarity for a given channel. 136 /// Set the output polarity for a given channel.
@@ -148,7 +148,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
148 } 148 }
149} 149}
150 150
151impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> { 151impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> {
152 type Channel = Channel; 152 type Channel = Channel;
153 type Time = Hertz; 153 type Time = Hertz;
154 type Duty = u16; 154 type Duty = u16;
@@ -168,16 +168,16 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C
168 } 168 }
169 169
170 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 170 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
171 self.inner.get_compare_value(channel) 171 self.inner.get_compare_value(channel) as u16
172 } 172 }
173 173
174 fn get_max_duty(&self) -> Self::Duty { 174 fn get_max_duty(&self) -> Self::Duty {
175 self.inner.get_max_compare_value() + 1 175 self.inner.get_max_compare_value() as u16 + 1
176 } 176 }
177 177
178 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 178 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
179 assert!(duty <= self.get_max_duty()); 179 assert!(duty <= self.get_max_duty());
180 self.inner.set_compare_value(channel, duty) 180 self.inner.set_compare_value(channel, duty as u32)
181 } 181 }
182 182
183 fn set_period<P>(&mut self, period: P) 183 fn set_period<P>(&mut self, period: P)
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
new file mode 100644
index 000000000..a5d942314
--- /dev/null
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -0,0 +1,638 @@
1//! Low-level timer driver.
2//!
3//! This is an unopinionated, very low-level driver for all STM32 timers. It allows direct register
4//! manipulation with the `regs_*()` methods, and has utility functions that are thin wrappers
5//! over the registers.
6//!
7//! The available functionality depends on the timer type.
8
9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
10
11use super::*;
12use crate::pac::timer::vals;
13use crate::time::Hertz;
14
15/// Input capture mode.
16#[derive(Clone, Copy)]
17pub enum InputCaptureMode {
18 /// Rising edge only.
19 Rising,
20 /// Falling edge only.
21 Falling,
22 /// Both rising or falling edges.
23 BothEdges,
24}
25
26/// Input TI selection.
27#[derive(Clone, Copy)]
28pub enum InputTISelection {
29 /// Normal
30 Normal,
31 /// Alternate
32 Alternate,
33 /// TRC
34 TRC,
35}
36
37impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
38 fn from(tisel: InputTISelection) -> Self {
39 match tisel {
40 InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4,
41 InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3,
42 InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC,
43 }
44 }
45}
46
47/// Timer counting mode.
48#[repr(u8)]
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
50pub enum CountingMode {
51 #[default]
52 /// The timer counts up to the reload value and then resets back to 0.
53 EdgeAlignedUp,
54 /// The timer counts down to 0 and then resets back to the reload value.
55 EdgeAlignedDown,
56 /// The timer counts up to the reload value and then counts back to 0.
57 ///
58 /// The output compare interrupt flags of channels configured in output are
59 /// set when the counter is counting down.
60 CenterAlignedDownInterrupts,
61 /// The timer counts up to the reload value and then counts back to 0.
62 ///
63 /// The output compare interrupt flags of channels configured in output are
64 /// set when the counter is counting up.
65 CenterAlignedUpInterrupts,
66 /// The timer counts up to the reload value and then counts back to 0.
67 ///
68 /// The output compare interrupt flags of channels configured in output are
69 /// set when the counter is counting both up or down.
70 CenterAlignedBothInterrupts,
71}
72
73impl CountingMode {
74 /// Return whether this mode is edge-aligned (up or down).
75 pub fn is_edge_aligned(&self) -> bool {
76 matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown)
77 }
78
79 /// Return whether this mode is center-aligned.
80 pub fn is_center_aligned(&self) -> bool {
81 matches!(
82 self,
83 CountingMode::CenterAlignedDownInterrupts
84 | CountingMode::CenterAlignedUpInterrupts
85 | CountingMode::CenterAlignedBothInterrupts
86 )
87 }
88}
89
90impl From<CountingMode> for (vals::Cms, vals::Dir) {
91 fn from(value: CountingMode) -> Self {
92 match value {
93 CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP),
94 CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN),
95 CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP),
96 CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP),
97 CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP),
98 }
99 }
100}
101
102impl From<(vals::Cms, vals::Dir)> for CountingMode {
103 fn from(value: (vals::Cms, vals::Dir)) -> Self {
104 match value {
105 (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp,
106 (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown,
107 (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts,
108 (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts,
109 (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts,
110 }
111 }
112}
113
114/// Output compare mode.
115#[derive(Clone, Copy)]
116pub enum OutputCompareMode {
117 /// The comparison between the output compare register TIMx_CCRx and
118 /// the counter TIMx_CNT has no effect on the outputs.
119 /// (this mode is used to generate a timing base).
120 Frozen,
121 /// Set channel to active level on match. OCxREF signal is forced high when the
122 /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
123 ActiveOnMatch,
124 /// Set channel to inactive level on match. OCxREF signal is forced low when the
125 /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
126 InactiveOnMatch,
127 /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
128 Toggle,
129 /// Force inactive level - OCxREF is forced low.
130 ForceInactive,
131 /// Force active level - OCxREF is forced high.
132 ForceActive,
133 /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx
134 /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as
135 /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1).
136 PwmMode1,
137 /// PWM mode 2 - In upcounting, channel is inactive as long as
138 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
139 /// TIMx_CNT>TIMx_CCRx else inactive.
140 PwmMode2,
141 // TODO: there's more modes here depending on the chip family.
142}
143
144impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
145 fn from(mode: OutputCompareMode) -> Self {
146 match mode {
147 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN,
148 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH,
149 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH,
150 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE,
151 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE,
152 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE,
153 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1,
154 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2,
155 }
156 }
157}
158
159/// Timer output pin polarity.
160#[derive(Clone, Copy)]
161pub enum OutputPolarity {
162 /// Active high (higher duty value makes the pin spend more time high).
163 ActiveHigh,
164 /// Active low (higher duty value makes the pin spend more time low).
165 ActiveLow,
166}
167
168impl From<OutputPolarity> for bool {
169 fn from(mode: OutputPolarity) -> Self {
170 match mode {
171 OutputPolarity::ActiveHigh => false,
172 OutputPolarity::ActiveLow => true,
173 }
174 }
175}
176
177/// Low-level timer driver.
178pub struct Timer<'d, T: CoreInstance> {
179 tim: PeripheralRef<'d, T>,
180}
181
182impl<'d, T: CoreInstance> Drop for Timer<'d, T> {
183 fn drop(&mut self) {
184 T::disable()
185 }
186}
187
188impl<'d, T: CoreInstance> Timer<'d, T> {
189 /// Create a new timer driver.
190 pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self {
191 into_ref!(tim);
192
193 T::enable_and_reset();
194
195 Self { tim }
196 }
197
198 /// Get access to the virutal core 16bit timer registers.
199 ///
200 /// Note: This works even if the timer is more capable, because registers
201 /// for the less capable timers are a subset. This allows writing a driver
202 /// for a given set of capabilities, and having it transparently work with
203 /// more capable timers.
204 pub fn regs_core(&self) -> crate::pac::timer::TimCore {
205 unsafe { crate::pac::timer::TimCore::from_ptr(T::regs()) }
206 }
207
208 #[cfg(not(stm32l0))]
209 fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp32 {
210 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
211 }
212
213 /// Start the timer.
214 pub fn start(&self) {
215 self.regs_core().cr1().modify(|r| r.set_cen(true));
216 }
217
218 /// Stop the timer.
219 pub fn stop(&self) {
220 self.regs_core().cr1().modify(|r| r.set_cen(false));
221 }
222
223 /// Reset the counter value to 0
224 pub fn reset(&self) {
225 self.regs_core().cnt().write(|r| r.set_cnt(0));
226 }
227
228 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
229 ///
230 /// This means that in the default edge-aligned mode,
231 /// the timer counter will wrap around at the same frequency as is being set.
232 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
233 /// because it needs to count up and down.
234 pub fn set_frequency(&self, frequency: Hertz) {
235 let f = frequency.0;
236 assert!(f > 0);
237 let timer_f = T::frequency().0;
238
239 match T::BITS {
240 TimerBits::Bits16 => {
241 let pclk_ticks_per_timer_period = timer_f / f;
242 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
243 let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1);
244
245 // the timer counts `0..=arr`, we want it to count `0..divide_by`
246 let arr = unwrap!(u16::try_from(divide_by - 1));
247
248 let regs = self.regs_core();
249 regs.psc().write_value(psc);
250 regs.arr().write(|r| r.set_arr(arr));
251
252 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
253 regs.egr().write(|r| r.set_ug(true));
254 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
255 }
256 #[cfg(not(stm32l0))]
257 TimerBits::Bits32 => {
258 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
259 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
260 let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into());
261
262 let regs = self.regs_gp32_unchecked();
263 regs.psc().write_value(psc);
264 regs.arr().write_value(arr);
265
266 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
267 regs.egr().write(|r| r.set_ug(true));
268 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
269 }
270 }
271 }
272
273 /// Clear update interrupt.
274 ///
275 /// Returns whether the update interrupt flag was set.
276 pub fn clear_update_interrupt(&self) -> bool {
277 let regs = self.regs_core();
278 let sr = regs.sr().read();
279 if sr.uif() {
280 regs.sr().modify(|r| {
281 r.set_uif(false);
282 });
283 true
284 } else {
285 false
286 }
287 }
288
289 /// Enable/disable the update interrupt.
290 pub fn enable_update_interrupt(&self, enable: bool) {
291 self.regs_core().dier().modify(|r| r.set_uie(enable));
292 }
293
294 /// Enable/disable autoreload preload.
295 pub fn set_autoreload_preload(&self, enable: bool) {
296 self.regs_core().cr1().modify(|r| r.set_arpe(enable));
297 }
298
299 /// Get the timer frequency.
300 pub fn get_frequency(&self) -> Hertz {
301 let timer_f = T::frequency();
302
303 match T::BITS {
304 TimerBits::Bits16 => {
305 let regs = self.regs_core();
306 let arr = regs.arr().read().arr();
307 let psc = regs.psc().read();
308
309 timer_f / arr / (psc + 1)
310 }
311 #[cfg(not(stm32l0))]
312 TimerBits::Bits32 => {
313 let regs = self.regs_gp32_unchecked();
314 let arr = regs.arr().read();
315 let psc = regs.psc().read();
316
317 timer_f / arr / (psc + 1)
318 }
319 }
320 }
321}
322
323impl<'d, T: BasicNoCr2Instance> Timer<'d, T> {
324 /// Get access to the Baisc 16bit timer registers.
325 ///
326 /// Note: This works even if the timer is more capable, because registers
327 /// for the less capable timers are a subset. This allows writing a driver
328 /// for a given set of capabilities, and having it transparently work with
329 /// more capable timers.
330 pub fn regs_basic_no_cr2(&self) -> crate::pac::timer::TimBasicNoCr2 {
331 unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(T::regs()) }
332 }
333
334 /// Enable/disable the update dma.
335 pub fn enable_update_dma(&self, enable: bool) {
336 self.regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable));
337 }
338
339 /// Get the update dma enable/disable state.
340 pub fn get_update_dma_state(&self) -> bool {
341 self.regs_basic_no_cr2().dier().read().ude()
342 }
343}
344
345impl<'d, T: BasicInstance> Timer<'d, T> {
346 /// Get access to the Baisc 16bit timer registers.
347 ///
348 /// Note: This works even if the timer is more capable, because registers
349 /// for the less capable timers are a subset. This allows writing a driver
350 /// for a given set of capabilities, and having it transparently work with
351 /// more capable timers.
352 pub fn regs_basic(&self) -> crate::pac::timer::TimBasic {
353 unsafe { crate::pac::timer::TimBasic::from_ptr(T::regs()) }
354 }
355}
356
357impl<'d, T: GeneralInstance1Channel> Timer<'d, T> {
358 /// Get access to the general purpose 1 channel 16bit timer registers.
359 ///
360 /// Note: This works even if the timer is more capable, because registers
361 /// for the less capable timers are a subset. This allows writing a driver
362 /// for a given set of capabilities, and having it transparently work with
363 /// more capable timers.
364 pub fn regs_1ch(&self) -> crate::pac::timer::Tim1ch {
365 unsafe { crate::pac::timer::Tim1ch::from_ptr(T::regs()) }
366 }
367
368 /// Set clock divider.
369 pub fn set_clock_division(&self, ckd: vals::Ckd) {
370 self.regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
371 }
372
373 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
374 pub fn get_max_compare_value(&self) -> u32 {
375 match T::BITS {
376 TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32,
377 #[cfg(not(stm32l0))]
378 TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(),
379 }
380 }
381}
382
383impl<'d, T: GeneralInstance2Channel> Timer<'d, T> {
384 /// Get access to the general purpose 2 channel 16bit timer registers.
385 ///
386 /// Note: This works even if the timer is more capable, because registers
387 /// for the less capable timers are a subset. This allows writing a driver
388 /// for a given set of capabilities, and having it transparently work with
389 /// more capable timers.
390 pub fn regs_2ch(&self) -> crate::pac::timer::Tim2ch {
391 unsafe { crate::pac::timer::Tim2ch::from_ptr(T::regs()) }
392 }
393}
394
395impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
396 /// Get access to the general purpose 16bit timer registers.
397 ///
398 /// Note: This works even if the timer is more capable, because registers
399 /// for the less capable timers are a subset. This allows writing a driver
400 /// for a given set of capabilities, and having it transparently work with
401 /// more capable timers.
402 pub fn regs_gp16(&self) -> crate::pac::timer::TimGp16 {
403 unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }
404 }
405
406 /// Enable timer outputs.
407 pub fn enable_outputs(&self) {
408 self.tim.enable_outputs()
409 }
410
411 /// Set counting mode.
412 pub fn set_counting_mode(&self, mode: CountingMode) {
413 let (cms, dir) = mode.into();
414
415 let timer_enabled = self.regs_core().cr1().read().cen();
416 // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
417 // Changing direction is discouraged while the timer is running.
418 assert!(!timer_enabled);
419
420 self.regs_gp16().cr1().modify(|r| r.set_dir(dir));
421 self.regs_gp16().cr1().modify(|r| r.set_cms(cms))
422 }
423
424 /// Get counting mode.
425 pub fn get_counting_mode(&self) -> CountingMode {
426 let cr1 = self.regs_gp16().cr1().read();
427 (cr1.cms(), cr1.dir()).into()
428 }
429
430 /// Set input capture filter.
431 pub fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) {
432 let raw_channel = channel.index();
433 self.regs_gp16()
434 .ccmr_input(raw_channel / 2)
435 .modify(|r| r.set_icf(raw_channel % 2, icf));
436 }
437
438 /// Clear input interrupt.
439 pub fn clear_input_interrupt(&self, channel: Channel) {
440 self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
441 }
442
443 /// Enable input interrupt.
444 pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) {
445 self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
446 }
447
448 /// Set input capture prescaler.
449 pub fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) {
450 let raw_channel = channel.index();
451 self.regs_gp16()
452 .ccmr_input(raw_channel / 2)
453 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
454 }
455
456 /// Set input TI selection.
457 pub fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) {
458 let raw_channel = channel.index();
459 self.regs_gp16()
460 .ccmr_input(raw_channel / 2)
461 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
462 }
463
464 /// Set input capture mode.
465 pub fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) {
466 self.regs_gp16().ccer().modify(|r| match mode {
467 InputCaptureMode::Rising => {
468 r.set_ccnp(channel.index(), false);
469 r.set_ccp(channel.index(), false);
470 }
471 InputCaptureMode::Falling => {
472 r.set_ccnp(channel.index(), false);
473 r.set_ccp(channel.index(), true);
474 }
475 InputCaptureMode::BothEdges => {
476 r.set_ccnp(channel.index(), true);
477 r.set_ccp(channel.index(), true);
478 }
479 });
480 }
481
482 /// Set output compare mode.
483 pub fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) {
484 let raw_channel: usize = channel.index();
485 self.regs_gp16()
486 .ccmr_output(raw_channel / 2)
487 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
488 }
489
490 /// Set output polarity.
491 pub fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
492 self.regs_gp16()
493 .ccer()
494 .modify(|w| w.set_ccp(channel.index(), polarity.into()));
495 }
496
497 /// Enable/disable a channel.
498 pub fn enable_channel(&self, channel: Channel, enable: bool) {
499 self.regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
500 }
501
502 /// Get enable/disable state of a channel
503 pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
504 self.regs_gp16().ccer().read().cce(channel.index())
505 }
506
507 /// Set compare value for a channel.
508 pub fn set_compare_value(&self, channel: Channel, value: u32) {
509 match T::BITS {
510 TimerBits::Bits16 => {
511 let value = unwrap!(u16::try_from(value));
512 self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
513 }
514 #[cfg(not(stm32l0))]
515 TimerBits::Bits32 => {
516 self.regs_gp32_unchecked().ccr(channel.index()).write_value(value);
517 }
518 }
519 }
520
521 /// Get compare value for a channel.
522 pub fn get_compare_value(&self, channel: Channel) -> u32 {
523 match T::BITS {
524 TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32,
525 #[cfg(not(stm32l0))]
526 TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(),
527 }
528 }
529
530 /// Get capture value for a channel.
531 pub fn get_capture_value(&self, channel: Channel) -> u32 {
532 self.get_compare_value(channel)
533 }
534
535 /// Set output compare preload.
536 pub fn set_output_compare_preload(&self, channel: Channel, preload: bool) {
537 let channel_index = channel.index();
538 self.regs_gp16()
539 .ccmr_output(channel_index / 2)
540 .modify(|w| w.set_ocpe(channel_index % 2, preload));
541 }
542
543 /// Get capture compare DMA selection
544 pub fn get_cc_dma_selection(&self) -> vals::Ccds {
545 self.regs_gp16().cr2().read().ccds()
546 }
547
548 /// Set capture compare DMA selection
549 pub fn set_cc_dma_selection(&self, ccds: vals::Ccds) {
550 self.regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
551 }
552
553 /// Get capture compare DMA enable state
554 pub fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
555 self.regs_gp16().dier().read().ccde(channel.index())
556 }
557
558 /// Set capture compare DMA enable state
559 pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) {
560 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
561 }
562}
563
564#[cfg(not(stm32l0))]
565impl<'d, T: GeneralInstance32bit4Channel> Timer<'d, T> {
566 /// Get access to the general purpose 32bit timer registers.
567 ///
568 /// Note: This works even if the timer is more capable, because registers
569 /// for the less capable timers are a subset. This allows writing a driver
570 /// for a given set of capabilities, and having it transparently work with
571 /// more capable timers.
572 pub fn regs_gp32(&self) -> crate::pac::timer::TimGp32 {
573 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
574 }
575}
576
577#[cfg(not(stm32l0))]
578impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> {
579 /// Get access to the general purpose 1 channel with one complementary 16bit timer registers.
580 ///
581 /// Note: This works even if the timer is more capable, because registers
582 /// for the less capable timers are a subset. This allows writing a driver
583 /// for a given set of capabilities, and having it transparently work with
584 /// more capable timers.
585 pub fn regs_1ch_cmp(&self) -> crate::pac::timer::Tim1chCmp {
586 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
587 }
588
589 /// Set clock divider for the dead time.
590 pub fn set_dead_time_clock_division(&self, value: vals::Ckd) {
591 self.regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value));
592 }
593
594 /// Set dead time, as a fraction of the max duty value.
595 pub fn set_dead_time_value(&self, value: u8) {
596 self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
597 }
598
599 /// Set state of MOE-bit in BDTR register to en-/disable output
600 pub fn set_moe(&self, enable: bool) {
601 self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable));
602 }
603}
604
605#[cfg(not(stm32l0))]
606impl<'d, T: AdvancedInstance2Channel> Timer<'d, T> {
607 /// Get access to the general purpose 2 channel with one complementary 16bit timer registers.
608 ///
609 /// Note: This works even if the timer is more capable, because registers
610 /// for the less capable timers are a subset. This allows writing a driver
611 /// for a given set of capabilities, and having it transparently work with
612 /// more capable timers.
613 pub fn regs_2ch_cmp(&self) -> crate::pac::timer::Tim2chCmp {
614 unsafe { crate::pac::timer::Tim2chCmp::from_ptr(T::regs()) }
615 }
616}
617
618#[cfg(not(stm32l0))]
619impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
620 /// Get access to the advanced timer registers.
621 pub fn regs_advanced(&self) -> crate::pac::timer::TimAdv {
622 unsafe { crate::pac::timer::TimAdv::from_ptr(T::regs()) }
623 }
624
625 /// Set complementary output polarity.
626 pub fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
627 self.regs_advanced()
628 .ccer()
629 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
630 }
631
632 /// Enable/disable a complementary channel.
633 pub fn enable_complementary_channel(&self, channel: Channel, enable: bool) {
634 self.regs_advanced()
635 .ccer()
636 .modify(|w| w.set_ccne(channel.index(), enable));
637 }
638}
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index e5e84c255..2ba6b3f11 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,490 +1,13 @@
1//! Timers, PWM, quadrature decoder. 1//! Timers, PWM, quadrature decoder.
2//!
3
4//! Timer inheritance
5//!
6
7// sealed:
8//
9// Core -------------------------> 1CH -------------------------> 1CH_CMP
10// | | ^ |
11// +--> Basic_NoCr2 --> Basic +--> 2CH --> GP16 --> GP32 | +--> 2CH_CMP --> ADV
12// | | | ^ | | ^ ^
13// | | +------|--|--------------|-----------+ |
14// | +--------------------+ +--------------|-----------|---------+
15// | | | |
16// | +--------------------------------------|-----------+
17// +----------------------------------------------------+
18
19//! ```text
20//! BasicInstance --> CaptureCompare16bitInstance --+--> ComplementaryCaptureCompare16bitInstance
21//! |
22//! +--> CaptureCompare32bitInstance
23//! ```
24//!
25//! Mapping:
26//!
27//! | trait | timer |
28//! | :----------------------------------------: | ------------------------------------------------------------------------------------------------- |
29//! | [BasicInstance] | Basic Timer |
30//! | [CaptureCompare16bitInstance] | 1-channel Timer, 2-channel Timer, General Purpose 16-bit Timer |
31//! | [CaptureCompare32bitInstance] | General Purpose 32-bit Timer |
32//! | [ComplementaryCaptureCompare16bitInstance] | 1-channel with one complentary Timer, 2-channel with one complentary Timer, Advance Control Timer |
33 2
34#[cfg(not(stm32l0))] 3#[cfg(not(stm32l0))]
35pub mod complementary_pwm; 4pub mod complementary_pwm;
5pub mod low_level;
36pub mod qei; 6pub mod qei;
37pub mod simple_pwm; 7pub mod simple_pwm;
38 8
39use stm32_metapac::timer::vals;
40
41use crate::interrupt; 9use crate::interrupt;
42use crate::rcc::RccPeripheral; 10use crate::rcc::RccPeripheral;
43use crate::time::Hertz;
44
45/// Low-level timer access.
46#[cfg(feature = "unstable-pac")]
47pub mod low_level {
48 pub use super::sealed::*;
49}
50
51pub(crate) mod sealed {
52 use super::*;
53
54 /// Virtual Core 16-bit timer instance.
55 pub trait CoreInstance: RccPeripheral {
56 /// Interrupt for this timer.
57 type Interrupt: interrupt::typelevel::Interrupt;
58
59 /// Get access to the virutal core 16bit timer registers.
60 ///
61 /// Note: This works even if the timer is more capable, because registers
62 /// for the less capable timers are a subset. This allows writing a driver
63 /// for a given set of capabilities, and having it transparently work with
64 /// more capable timers.
65 fn regs_core() -> crate::pac::timer::TimCore;
66
67 /// Start the timer.
68 fn start(&self) {
69 Self::regs_core().cr1().modify(|r| r.set_cen(true));
70 }
71
72 /// Stop the timer.
73 fn stop(&self) {
74 Self::regs_core().cr1().modify(|r| r.set_cen(false));
75 }
76
77 /// Reset the counter value to 0
78 fn reset(&self) {
79 Self::regs_core().cnt().write(|r| r.set_cnt(0));
80 }
81
82 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
83 ///
84 /// This means that in the default edge-aligned mode,
85 /// the timer counter will wrap around at the same frequency as is being set.
86 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
87 /// because it needs to count up and down.
88 fn set_frequency(&self, frequency: Hertz) {
89 let f = frequency.0;
90 let timer_f = Self::frequency().0;
91 assert!(f > 0);
92 let pclk_ticks_per_timer_period = timer_f / f;
93 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into());
94 let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1);
95
96 // the timer counts `0..=arr`, we want it to count `0..divide_by`
97 let arr = unwrap!(u16::try_from(divide_by - 1));
98
99 let regs = Self::regs_core();
100 regs.psc().write_value(psc);
101 regs.arr().write(|r| r.set_arr(arr));
102
103 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
104 regs.egr().write(|r| r.set_ug(true));
105 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
106 }
107
108 /// Clear update interrupt.
109 ///
110 /// Returns whether the update interrupt flag was set.
111 fn clear_update_interrupt(&self) -> bool {
112 let regs = Self::regs_core();
113 let sr = regs.sr().read();
114 if sr.uif() {
115 regs.sr().modify(|r| {
116 r.set_uif(false);
117 });
118 true
119 } else {
120 false
121 }
122 }
123
124 /// Enable/disable the update interrupt.
125 fn enable_update_interrupt(&self, enable: bool) {
126 Self::regs_core().dier().modify(|r| r.set_uie(enable));
127 }
128
129 /// Enable/disable autoreload preload.
130 fn set_autoreload_preload(&self, enable: bool) {
131 Self::regs_core().cr1().modify(|r| r.set_arpe(enable));
132 }
133
134 /// Get the timer frequency.
135 fn get_frequency(&self) -> Hertz {
136 let timer_f = Self::frequency();
137
138 let regs = Self::regs_core();
139 let arr = regs.arr().read().arr();
140 let psc = regs.psc().read();
141
142 timer_f / arr / (psc + 1)
143 }
144 }
145
146 /// Virtual Basic without CR2 16-bit timer instance.
147 pub trait BasicNoCr2Instance: CoreInstance {
148 /// Get access to the Baisc 16bit timer registers.
149 ///
150 /// Note: This works even if the timer is more capable, because registers
151 /// for the less capable timers are a subset. This allows writing a driver
152 /// for a given set of capabilities, and having it transparently work with
153 /// more capable timers.
154 fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2;
155
156 /// Enable/disable the update dma.
157 fn enable_update_dma(&self, enable: bool) {
158 Self::regs_basic_no_cr2().dier().modify(|r| r.set_ude(enable));
159 }
160
161 /// Get the update dma enable/disable state.
162 fn get_update_dma_state(&self) -> bool {
163 Self::regs_basic_no_cr2().dier().read().ude()
164 }
165 }
166
167 /// Basic 16-bit timer instance.
168 pub trait BasicInstance: BasicNoCr2Instance {
169 /// Get access to the Baisc 16bit timer registers.
170 ///
171 /// Note: This works even if the timer is more capable, because registers
172 /// for the less capable timers are a subset. This allows writing a driver
173 /// for a given set of capabilities, and having it transparently work with
174 /// more capable timers.
175 fn regs_basic() -> crate::pac::timer::TimBasic;
176 }
177
178 /// Gneral-purpose 1 channel 16-bit timer instance.
179 pub trait GeneralPurpose1ChannelInstance: CoreInstance {
180 /// Get access to the general purpose 1 channel 16bit timer registers.
181 ///
182 /// Note: This works even if the timer is more capable, because registers
183 /// for the less capable timers are a subset. This allows writing a driver
184 /// for a given set of capabilities, and having it transparently work with
185 /// more capable timers.
186 fn regs_1ch() -> crate::pac::timer::Tim1ch;
187
188 /// Set clock divider.
189 fn set_clock_division(&self, ckd: vals::Ckd) {
190 Self::regs_1ch().cr1().modify(|r| r.set_ckd(ckd));
191 }
192
193 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
194 fn get_max_compare_value(&self) -> u16 {
195 Self::regs_1ch().arr().read().arr()
196 }
197 }
198
199 /// Gneral-purpose 1 channel 16-bit timer instance.
200 pub trait GeneralPurpose2ChannelInstance: GeneralPurpose1ChannelInstance {
201 /// Get access to the general purpose 2 channel 16bit timer registers.
202 ///
203 /// Note: This works even if the timer is more capable, because registers
204 /// for the less capable timers are a subset. This allows writing a driver
205 /// for a given set of capabilities, and having it transparently work with
206 /// more capable timers.
207 fn regs_2ch() -> crate::pac::timer::Tim2ch;
208 }
209
210 /// Gneral-purpose 16-bit timer instance.
211 pub trait GeneralPurpose16bitInstance: BasicInstance + GeneralPurpose2ChannelInstance {
212 /// Get access to the general purpose 16bit timer registers.
213 ///
214 /// Note: This works even if the timer is more capable, because registers
215 /// for the less capable timers are a subset. This allows writing a driver
216 /// for a given set of capabilities, and having it transparently work with
217 /// more capable timers.
218 fn regs_gp16() -> crate::pac::timer::TimGp16;
219
220 /// Set counting mode.
221 fn set_counting_mode(&self, mode: CountingMode) {
222 let (cms, dir) = mode.into();
223
224 let timer_enabled = Self::regs_core().cr1().read().cen();
225 // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
226 // Changing direction is discouraged while the timer is running.
227 assert!(!timer_enabled);
228
229 Self::regs_gp16().cr1().modify(|r| r.set_dir(dir));
230 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
231 }
232
233 /// Get counting mode.
234 fn get_counting_mode(&self) -> CountingMode {
235 let cr1 = Self::regs_gp16().cr1().read();
236 (cr1.cms(), cr1.dir()).into()
237 }
238
239 /// Set input capture filter.
240 fn set_input_capture_filter(&self, channel: Channel, icf: vals::FilterValue) {
241 let raw_channel = channel.index();
242 Self::regs_gp16()
243 .ccmr_input(raw_channel / 2)
244 .modify(|r| r.set_icf(raw_channel % 2, icf));
245 }
246
247 /// Clear input interrupt.
248 fn clear_input_interrupt(&self, channel: Channel) {
249 Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
250 }
251
252 /// Enable input interrupt.
253 fn enable_input_interrupt(&self, channel: Channel, enable: bool) {
254 Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
255 }
256
257 /// Set input capture prescaler.
258 fn set_input_capture_prescaler(&self, channel: Channel, factor: u8) {
259 let raw_channel = channel.index();
260 Self::regs_gp16()
261 .ccmr_input(raw_channel / 2)
262 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
263 }
264
265 /// Set input TI selection.
266 fn set_input_ti_selection(&self, channel: Channel, tisel: InputTISelection) {
267 let raw_channel = channel.index();
268 Self::regs_gp16()
269 .ccmr_input(raw_channel / 2)
270 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
271 }
272
273 /// Set input capture mode.
274 fn set_input_capture_mode(&self, channel: Channel, mode: InputCaptureMode) {
275 Self::regs_gp16().ccer().modify(|r| match mode {
276 InputCaptureMode::Rising => {
277 r.set_ccnp(channel.index(), false);
278 r.set_ccp(channel.index(), false);
279 }
280 InputCaptureMode::Falling => {
281 r.set_ccnp(channel.index(), false);
282 r.set_ccp(channel.index(), true);
283 }
284 InputCaptureMode::BothEdges => {
285 r.set_ccnp(channel.index(), true);
286 r.set_ccp(channel.index(), true);
287 }
288 });
289 }
290
291 /// Set output compare mode.
292 fn set_output_compare_mode(&self, channel: Channel, mode: OutputCompareMode) {
293 let raw_channel: usize = channel.index();
294 Self::regs_gp16()
295 .ccmr_output(raw_channel / 2)
296 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
297 }
298
299 /// Set output polarity.
300 fn set_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
301 Self::regs_gp16()
302 .ccer()
303 .modify(|w| w.set_ccp(channel.index(), polarity.into()));
304 }
305
306 /// Enable/disable a channel.
307 fn enable_channel(&self, channel: Channel, enable: bool) {
308 Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
309 }
310
311 /// Get enable/disable state of a channel
312 fn get_channel_enable_state(&self, channel: Channel) -> bool {
313 Self::regs_gp16().ccer().read().cce(channel.index())
314 }
315
316 /// Set compare value for a channel.
317 fn set_compare_value(&self, channel: Channel, value: u16) {
318 Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
319 }
320
321 /// Get capture value for a channel.
322 fn get_capture_value(&self, channel: Channel) -> u16 {
323 Self::regs_gp16().ccr(channel.index()).read().ccr()
324 }
325
326 /// Get compare value for a channel.
327 fn get_compare_value(&self, channel: Channel) -> u16 {
328 Self::regs_gp16().ccr(channel.index()).read().ccr()
329 }
330
331 /// Set output compare preload.
332 fn set_output_compare_preload(&self, channel: Channel, preload: bool) {
333 let channel_index = channel.index();
334 Self::regs_gp16()
335 .ccmr_output(channel_index / 2)
336 .modify(|w| w.set_ocpe(channel_index % 2, preload));
337 }
338
339 /// Get capture compare DMA selection
340 fn get_cc_dma_selection(&self) -> super::vals::Ccds {
341 Self::regs_gp16().cr2().read().ccds()
342 }
343
344 /// Set capture compare DMA selection
345 fn set_cc_dma_selection(&self, ccds: super::vals::Ccds) {
346 Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
347 }
348
349 /// Get capture compare DMA enable state
350 fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
351 Self::regs_gp16().dier().read().ccde(channel.index())
352 }
353
354 /// Set capture compare DMA enable state
355 fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) {
356 Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
357 }
358 }
359
360 #[cfg(not(stm32l0))]
361 /// Gneral-purpose 32-bit timer instance.
362 pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
363 /// Get access to the general purpose 32bit timer registers.
364 ///
365 /// Note: This works even if the timer is more capable, because registers
366 /// for the less capable timers are a subset. This allows writing a driver
367 /// for a given set of capabilities, and having it transparently work with
368 /// more capable timers.
369 fn regs_gp32() -> crate::pac::timer::TimGp32;
370
371 /// Set timer frequency.
372 fn set_frequency(&self, frequency: Hertz) {
373 let f = frequency.0;
374 assert!(f > 0);
375 let timer_f = Self::frequency().0;
376 let pclk_ticks_per_timer_period = (timer_f / f) as u64;
377 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into());
378 let arr: u32 = unwrap!((pclk_ticks_per_timer_period / (psc as u64 + 1)).try_into());
379
380 let regs = Self::regs_gp32();
381 regs.psc().write_value(psc);
382 regs.arr().write_value(arr);
383
384 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY));
385 regs.egr().write(|r| r.set_ug(true));
386 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
387 }
388
389 /// Get timer frequency.
390 fn get_frequency(&self) -> Hertz {
391 let timer_f = Self::frequency();
392
393 let regs = Self::regs_gp32();
394 let arr = regs.arr().read();
395 let psc = regs.psc().read();
396
397 timer_f / arr / (psc + 1)
398 }
399
400 /// Set comapre value for a channel.
401 fn set_compare_value(&self, channel: Channel, value: u32) {
402 Self::regs_gp32().ccr(channel.index()).write_value(value);
403 }
404
405 /// Get capture value for a channel.
406 fn get_capture_value(&self, channel: Channel) -> u32 {
407 Self::regs_gp32().ccr(channel.index()).read()
408 }
409
410 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
411 fn get_max_compare_value(&self) -> u32 {
412 Self::regs_gp32().arr().read()
413 }
414
415 /// Get compare value for a channel.
416 fn get_compare_value(&self, channel: Channel) -> u32 {
417 Self::regs_gp32().ccr(channel.index()).read()
418 }
419 }
420
421 #[cfg(not(stm32l0))]
422 /// Gneral-purpose 1 channel with one complementary 16-bit timer instance.
423 pub trait GeneralPurpose1ChannelComplementaryInstance: BasicNoCr2Instance + GeneralPurpose1ChannelInstance {
424 /// Get access to the general purpose 1 channel with one complementary 16bit timer registers.
425 ///
426 /// Note: This works even if the timer is more capable, because registers
427 /// for the less capable timers are a subset. This allows writing a driver
428 /// for a given set of capabilities, and having it transparently work with
429 /// more capable timers.
430 fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp;
431
432 /// Set clock divider for the dead time.
433 fn set_dead_time_clock_division(&self, value: vals::Ckd) {
434 Self::regs_1ch_cmp().cr1().modify(|w| w.set_ckd(value));
435 }
436
437 /// Set dead time, as a fraction of the max duty value.
438 fn set_dead_time_value(&self, value: u8) {
439 Self::regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value));
440 }
441
442 /// Set state of MOE-bit in BDTR register to en-/disable output
443 fn set_moe(&self, enable: bool) {
444 Self::regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable));
445 }
446 }
447
448 #[cfg(not(stm32l0))]
449 /// Gneral-purpose 2 channel with one complementary 16-bit timer instance.
450 pub trait GeneralPurpose2ChannelComplementaryInstance:
451 BasicInstance + GeneralPurpose2ChannelInstance + GeneralPurpose1ChannelComplementaryInstance
452 {
453 /// Get access to the general purpose 2 channel with one complementary 16bit timer registers.
454 ///
455 /// Note: This works even if the timer is more capable, because registers
456 /// for the less capable timers are a subset. This allows writing a driver
457 /// for a given set of capabilities, and having it transparently work with
458 /// more capable timers.
459 fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp;
460 }
461
462 #[cfg(not(stm32l0))]
463 /// Advanced control timer instance.
464 pub trait AdvancedControlInstance:
465 GeneralPurpose2ChannelComplementaryInstance + GeneralPurpose16bitInstance
466 {
467 /// Capture compare interrupt for this timer.
468 type CaptureCompareInterrupt: interrupt::typelevel::Interrupt;
469
470 /// Get access to the advanced timer registers.
471 fn regs_advanced() -> crate::pac::timer::TimAdv;
472
473 /// Set complementary output polarity.
474 fn set_complementary_output_polarity(&self, channel: Channel, polarity: OutputPolarity) {
475 Self::regs_advanced()
476 .ccer()
477 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
478 }
479
480 /// Enable/disable a complementary channel.
481 fn enable_complementary_channel(&self, channel: Channel, enable: bool) {
482 Self::regs_advanced()
483 .ccer()
484 .modify(|w| w.set_ccne(channel.index(), enable));
485 }
486 }
487}
488 11
489/// Timer channel. 12/// Timer channel.
490#[derive(Clone, Copy)] 13#[derive(Clone, Copy)]
@@ -511,181 +34,44 @@ impl Channel {
511 } 34 }
512} 35}
513 36
514/// Input capture mode. 37/// Amount of bits of a timer.
515#[derive(Clone, Copy)] 38#[derive(Clone, Copy, PartialEq, Eq, Debug)]
516pub enum InputCaptureMode { 39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
517 /// Rising edge only. 40pub enum TimerBits {
518 Rising, 41 /// 16 bits.
519 /// Falling edge only. 42 Bits16,
520 Falling, 43 /// 32 bits.
521 /// Both rising or falling edges. 44 #[cfg(not(stm32l0))]
522 BothEdges, 45 Bits32,
523} 46}
524 47
525/// Input TI selection. 48/// Core timer instance.
526#[derive(Clone, Copy)] 49pub trait CoreInstance: RccPeripheral + 'static {
527pub enum InputTISelection { 50 /// Interrupt for this timer.
528 /// Normal 51 type Interrupt: interrupt::typelevel::Interrupt;
529 Normal,
530 /// Alternate
531 Alternate,
532 /// TRC
533 TRC,
534}
535 52
536impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs { 53 /// Amount of bits this timer has.
537 fn from(tisel: InputTISelection) -> Self { 54 const BITS: TimerBits;
538 match tisel {
539 InputTISelection::Normal => stm32_metapac::timer::vals::CcmrInputCcs::TI4,
540 InputTISelection::Alternate => stm32_metapac::timer::vals::CcmrInputCcs::TI3,
541 InputTISelection::TRC => stm32_metapac::timer::vals::CcmrInputCcs::TRC,
542 }
543 }
544}
545 55
546/// Timer counting mode. 56 /// Registers for this timer.
547#[repr(u8)]
548#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
549pub enum CountingMode {
550 #[default]
551 /// The timer counts up to the reload value and then resets back to 0.
552 EdgeAlignedUp,
553 /// The timer counts down to 0 and then resets back to the reload value.
554 EdgeAlignedDown,
555 /// The timer counts up to the reload value and then counts back to 0.
556 /// 57 ///
557 /// The output compare interrupt flags of channels configured in output are 58 /// This is a raw pointer to the register block. The actual register block layout varies depending on the timer type.
558 /// set when the counter is counting down. 59 fn regs() -> *mut ();
559 CenterAlignedDownInterrupts,
560 /// The timer counts up to the reload value and then counts back to 0.
561 ///
562 /// The output compare interrupt flags of channels configured in output are
563 /// set when the counter is counting up.
564 CenterAlignedUpInterrupts,
565 /// The timer counts up to the reload value and then counts back to 0.
566 ///
567 /// The output compare interrupt flags of channels configured in output are
568 /// set when the counter is counting both up or down.
569 CenterAlignedBothInterrupts,
570}
571
572impl CountingMode {
573 /// Return whether this mode is edge-aligned (up or down).
574 pub fn is_edge_aligned(&self) -> bool {
575 matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown)
576 }
577
578 /// Return whether this mode is center-aligned.
579 pub fn is_center_aligned(&self) -> bool {
580 matches!(
581 self,
582 CountingMode::CenterAlignedDownInterrupts
583 | CountingMode::CenterAlignedUpInterrupts
584 | CountingMode::CenterAlignedBothInterrupts
585 )
586 }
587}
588
589impl From<CountingMode> for (vals::Cms, vals::Dir) {
590 fn from(value: CountingMode) -> Self {
591 match value {
592 CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP),
593 CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN),
594 CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP),
595 CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP),
596 CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP),
597 }
598 }
599}
600
601impl From<(vals::Cms, vals::Dir)> for CountingMode {
602 fn from(value: (vals::Cms, vals::Dir)) -> Self {
603 match value {
604 (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp,
605 (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown,
606 (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts,
607 (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts,
608 (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts,
609 }
610 }
611}
612
613/// Output compare mode.
614#[derive(Clone, Copy)]
615pub enum OutputCompareMode {
616 /// The comparison between the output compare register TIMx_CCRx and
617 /// the counter TIMx_CNT has no effect on the outputs.
618 /// (this mode is used to generate a timing base).
619 Frozen,
620 /// Set channel to active level on match. OCxREF signal is forced high when the
621 /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
622 ActiveOnMatch,
623 /// Set channel to inactive level on match. OCxREF signal is forced low when the
624 /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
625 InactiveOnMatch,
626 /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
627 Toggle,
628 /// Force inactive level - OCxREF is forced low.
629 ForceInactive,
630 /// Force active level - OCxREF is forced high.
631 ForceActive,
632 /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx
633 /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as
634 /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1).
635 PwmMode1,
636 /// PWM mode 2 - In upcounting, channel is inactive as long as
637 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
638 /// TIMx_CNT>TIMx_CCRx else inactive.
639 PwmMode2,
640 // TODO: there's more modes here depending on the chip family.
641}
642
643impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
644 fn from(mode: OutputCompareMode) -> Self {
645 match mode {
646 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN,
647 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH,
648 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH,
649 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE,
650 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE,
651 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE,
652 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1,
653 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2,
654 }
655 }
656} 60}
61/// Cut-down basic timer instance.
62pub trait BasicNoCr2Instance: CoreInstance {}
63/// Basic timer instance.
64pub trait BasicInstance: BasicNoCr2Instance {}
657 65
658/// Timer output pin polarity. 66/// General-purpose 16-bit timer with 1 channel instance.
659#[derive(Clone, Copy)] 67pub trait GeneralInstance1Channel: CoreInstance {}
660pub enum OutputPolarity {
661 /// Active high (higher duty value makes the pin spend more time high).
662 ActiveHigh,
663 /// Active low (higher duty value makes the pin spend more time low).
664 ActiveLow,
665}
666 68
667impl From<OutputPolarity> for bool { 69/// General-purpose 16-bit timer with 2 channels instance.
668 fn from(mode: OutputPolarity) -> Self { 70pub trait GeneralInstance2Channel: GeneralInstance1Channel {}
669 match mode {
670 OutputPolarity::ActiveHigh => false,
671 OutputPolarity::ActiveLow => true,
672 }
673 }
674}
675 71
676/// Basic 16-bit timer instance. 72/// General-purpose 16-bit timer with 4 channels instance.
677pub trait BasicInstance: sealed::BasicInstance + sealed::BasicNoCr2Instance + sealed::CoreInstance + 'static {} 73pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel {
678 74 // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel
679// It's just a General-purpose 16-bit timer instance.
680/// Capture Compare timer instance.
681pub trait CaptureCompare16bitInstance:
682 BasicInstance
683 + sealed::GeneralPurpose2ChannelInstance
684 + sealed::GeneralPurpose1ChannelInstance
685 + sealed::GeneralPurpose16bitInstance
686 + 'static
687{
688 // SimplePwm<'d, T> is implemented for T: CaptureCompare16bitInstance
689 // Advanced timers implement this trait, but the output needs to be 75 // Advanced timers implement this trait, but the output needs to be
690 // enabled explicitly. 76 // enabled explicitly.
691 // To support general-purpose and advanced timers, this function is added 77 // To support general-purpose and advanced timers, this function is added
@@ -694,296 +80,149 @@ pub trait CaptureCompare16bitInstance:
694 fn enable_outputs(&self) {} 80 fn enable_outputs(&self) {}
695} 81}
696 82
697#[cfg(not(stm32l0))] 83/// General-purpose 32-bit timer with 4 channels instance.
698// It's just a General-purpose 32-bit timer instance. 84pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {}
699/// Capture Compare 32-bit timer instance.
700pub trait CaptureCompare32bitInstance:
701 CaptureCompare16bitInstance + sealed::GeneralPurpose32bitInstance + 'static
702{
703}
704
705#[cfg(not(stm32l0))]
706// It's just a Advanced Control timer instance.
707/// Complementary Capture Compare 32-bit timer instance.
708pub trait ComplementaryCaptureCompare16bitInstance:
709 CaptureCompare16bitInstance
710 + sealed::GeneralPurpose1ChannelComplementaryInstance
711 + sealed::GeneralPurpose2ChannelComplementaryInstance
712 + sealed::AdvancedControlInstance
713 + 'static
714{
715}
716
717pin_trait!(Channel1Pin, CaptureCompare16bitInstance);
718pin_trait!(Channel2Pin, CaptureCompare16bitInstance);
719pin_trait!(Channel3Pin, CaptureCompare16bitInstance);
720pin_trait!(Channel4Pin, CaptureCompare16bitInstance);
721pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance);
722
723cfg_if::cfg_if! {
724 if #[cfg(not(stm32l0))] {
725 pin_trait!(Channel1ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
726 pin_trait!(Channel2ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
727 pin_trait!(Channel3ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
728 pin_trait!(Channel4ComplementaryPin, ComplementaryCaptureCompare16bitInstance);
729
730 pin_trait!(BreakInputPin, ComplementaryCaptureCompare16bitInstance);
731 pin_trait!(BreakInput2Pin, ComplementaryCaptureCompare16bitInstance);
732 85
733 pin_trait!(BreakInputComparator1Pin, ComplementaryCaptureCompare16bitInstance); 86/// Advanced 16-bit timer with 1 channel instance.
734 pin_trait!(BreakInputComparator2Pin, ComplementaryCaptureCompare16bitInstance); 87pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel {
735 88 /// Capture compare interrupt for this timer.
736 pin_trait!(BreakInput2Comparator1Pin, ComplementaryCaptureCompare16bitInstance); 89 type CaptureCompareInterrupt: interrupt::typelevel::Interrupt;
737 pin_trait!(BreakInput2Comparator2Pin, ComplementaryCaptureCompare16bitInstance);
738 }
739} 90}
91/// Advanced 16-bit timer with 2 channels instance.
740 92
741#[allow(unused)] 93pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + AdvancedInstance1Channel {}
742macro_rules! impl_core_timer {
743 ($inst:ident, $irq:ident) => {
744 impl sealed::CoreInstance for crate::peripherals::$inst {
745 type Interrupt = crate::interrupt::typelevel::$irq;
746 94
747 fn regs_core() -> crate::pac::timer::TimCore { 95/// Advanced 16-bit timer with 4 channels instance.
748 unsafe { crate::pac::timer::TimCore::from_ptr(crate::pac::$inst.as_ptr()) } 96pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {}
749 }
750 }
751 };
752}
753 97
754#[allow(unused)] 98pin_trait!(Channel1Pin, GeneralInstance4Channel);
755macro_rules! impl_basic_no_cr2_timer { 99pin_trait!(Channel2Pin, GeneralInstance4Channel);
756 ($inst:ident) => { 100pin_trait!(Channel3Pin, GeneralInstance4Channel);
757 impl sealed::BasicNoCr2Instance for crate::peripherals::$inst { 101pin_trait!(Channel4Pin, GeneralInstance4Channel);
758 fn regs_basic_no_cr2() -> crate::pac::timer::TimBasicNoCr2 { 102pin_trait!(ExternalTriggerPin, GeneralInstance4Channel);
759 unsafe { crate::pac::timer::TimBasicNoCr2::from_ptr(crate::pac::$inst.as_ptr()) }
760 }
761 }
762 };
763}
764 103
765#[allow(unused)] 104pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel);
766macro_rules! impl_basic_timer { 105pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel);
767 ($inst:ident) => { 106pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel);
768 impl sealed::BasicInstance for crate::peripherals::$inst { 107pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel);
769 fn regs_basic() -> crate::pac::timer::TimBasic {
770 unsafe { crate::pac::timer::TimBasic::from_ptr(crate::pac::$inst.as_ptr()) }
771 }
772 }
773 };
774}
775 108
776#[allow(unused)] 109pin_trait!(BreakInputPin, AdvancedInstance4Channel);
777macro_rules! impl_1ch_timer { 110pin_trait!(BreakInput2Pin, AdvancedInstance4Channel);
778 ($inst:ident) => {
779 impl sealed::GeneralPurpose1ChannelInstance for crate::peripherals::$inst {
780 fn regs_1ch() -> crate::pac::timer::Tim1ch {
781 unsafe { crate::pac::timer::Tim1ch::from_ptr(crate::pac::$inst.as_ptr()) }
782 }
783 }
784 };
785}
786 111
787#[allow(unused)] 112pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel);
788macro_rules! impl_2ch_timer { 113pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel);
789 ($inst:ident) => {
790 impl sealed::GeneralPurpose2ChannelInstance for crate::peripherals::$inst {
791 fn regs_2ch() -> crate::pac::timer::Tim2ch {
792 unsafe { crate::pac::timer::Tim2ch::from_ptr(crate::pac::$inst.as_ptr()) }
793 }
794 }
795 };
796}
797 114
798#[allow(unused)] 115pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel);
799macro_rules! impl_gp16_timer { 116pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel);
800 ($inst:ident) => {
801 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
802 fn regs_gp16() -> crate::pac::timer::TimGp16 {
803 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
804 }
805 }
806 };
807}
808 117
809#[allow(unused)] 118// Update Event trigger DMA for every timer
810macro_rules! impl_gp32_timer { 119dma_trait!(UpDma, BasicInstance);
811 ($inst:ident) => {
812 impl sealed::GeneralPurpose32bitInstance for crate::peripherals::$inst {
813 fn regs_gp32() -> crate::pac::timer::TimGp32 {
814 crate::pac::$inst
815 }
816 }
817 };
818}
819 120
820#[allow(unused)] 121dma_trait!(Ch1Dma, GeneralInstance4Channel);
821macro_rules! impl_1ch_cmp_timer { 122dma_trait!(Ch2Dma, GeneralInstance4Channel);
822 ($inst:ident) => { 123dma_trait!(Ch3Dma, GeneralInstance4Channel);
823 impl sealed::GeneralPurpose1ChannelComplementaryInstance for crate::peripherals::$inst { 124dma_trait!(Ch4Dma, GeneralInstance4Channel);
824 fn regs_1ch_cmp() -> crate::pac::timer::Tim1chCmp {
825 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
826 }
827 }
828 };
829}
830 125
831#[allow(unused)] 126#[allow(unused)]
832macro_rules! impl_2ch_cmp_timer { 127macro_rules! impl_core_timer {
833 ($inst:ident) => { 128 ($inst:ident, $bits:expr) => {
834 impl sealed::GeneralPurpose2ChannelComplementaryInstance for crate::peripherals::$inst { 129 impl CoreInstance for crate::peripherals::$inst {
835 fn regs_2ch_cmp() -> crate::pac::timer::Tim2chCmp { 130 type Interrupt = crate::_generated::peripheral_interrupts::$inst::UP;
836 unsafe { crate::pac::timer::Tim2chCmp::from_ptr(crate::pac::$inst.as_ptr()) }
837 }
838 }
839 };
840}
841 131
842#[allow(unused)] 132 const BITS: TimerBits = $bits;
843macro_rules! impl_adv_timer {
844 ($inst:ident, $irq:ident) => {
845 impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
846 type CaptureCompareInterrupt = crate::interrupt::typelevel::$irq;
847 133
848 fn regs_advanced() -> crate::pac::timer::TimAdv { 134 fn regs() -> *mut () {
849 unsafe { crate::pac::timer::TimAdv::from_ptr(crate::pac::$inst.as_ptr()) } 135 crate::pac::$inst.as_ptr()
850 } 136 }
851 } 137 }
852 }; 138 };
853} 139}
854 140
855foreach_interrupt! { 141foreach_interrupt! {
856
857 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { 142 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
858 impl_core_timer!($inst, $irq); 143 impl_core_timer!($inst, TimerBits::Bits16);
859 impl_basic_no_cr2_timer!($inst); 144 impl BasicNoCr2Instance for crate::peripherals::$inst {}
860 impl_basic_timer!($inst);
861 impl BasicInstance for crate::peripherals::$inst {} 145 impl BasicInstance for crate::peripherals::$inst {}
862 }; 146 };
863 147
864 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { 148 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => {
865 impl_core_timer!($inst, $irq); 149 impl_core_timer!($inst, TimerBits::Bits16);
866 impl_basic_no_cr2_timer!($inst); 150 impl BasicNoCr2Instance for crate::peripherals::$inst {}
867 impl_basic_timer!($inst);
868 impl_1ch_timer!($inst);
869 impl_2ch_timer!($inst);
870 impl_gp16_timer!($inst);
871 impl BasicInstance for crate::peripherals::$inst {} 151 impl BasicInstance for crate::peripherals::$inst {}
872 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 152 impl GeneralInstance1Channel for crate::peripherals::$inst {}
153 impl GeneralInstance2Channel for crate::peripherals::$inst {}
154 impl GeneralInstance4Channel for crate::peripherals::$inst {}
873 }; 155 };
874 156
875
876 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { 157 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => {
877 impl_core_timer!($inst, $irq); 158 impl_core_timer!($inst, TimerBits::Bits16);
878 impl_basic_no_cr2_timer!($inst); 159 impl BasicNoCr2Instance for crate::peripherals::$inst {}
879 impl_basic_timer!($inst);
880 impl_1ch_timer!($inst);
881 impl_2ch_timer!($inst);
882 impl_gp16_timer!($inst);
883 impl BasicInstance for crate::peripherals::$inst {} 160 impl BasicInstance for crate::peripherals::$inst {}
884 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 161 impl GeneralInstance1Channel for crate::peripherals::$inst {}
162 impl GeneralInstance2Channel for crate::peripherals::$inst {}
163 impl GeneralInstance4Channel for crate::peripherals::$inst {}
885 }; 164 };
886 165
887 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { 166 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
888 impl_core_timer!($inst, $irq); 167 impl_core_timer!($inst, TimerBits::Bits16);
889 impl_basic_no_cr2_timer!($inst); 168 impl BasicNoCr2Instance for crate::peripherals::$inst {}
890 impl_basic_timer!($inst);
891 impl_1ch_timer!($inst);
892 impl_2ch_timer!($inst);
893 impl_gp16_timer!($inst);
894 impl BasicInstance for crate::peripherals::$inst {} 169 impl BasicInstance for crate::peripherals::$inst {}
895 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 170 impl GeneralInstance1Channel for crate::peripherals::$inst {}
171 impl GeneralInstance2Channel for crate::peripherals::$inst {}
172 impl GeneralInstance4Channel for crate::peripherals::$inst {}
896 }; 173 };
897 174
898 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 175 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
899 impl_core_timer!($inst, $irq); 176 impl_core_timer!($inst, TimerBits::Bits32);
900 impl_basic_no_cr2_timer!($inst); 177 impl BasicNoCr2Instance for crate::peripherals::$inst {}
901 impl_basic_timer!($inst);
902 impl_1ch_timer!($inst);
903 impl_2ch_timer!($inst);
904 impl_gp16_timer!($inst);
905 impl_gp32_timer!($inst);
906 impl BasicInstance for crate::peripherals::$inst {} 178 impl BasicInstance for crate::peripherals::$inst {}
907 impl CaptureCompare16bitInstance for crate::peripherals::$inst {} 179 impl GeneralInstance1Channel for crate::peripherals::$inst {}
908 impl CaptureCompare32bitInstance for crate::peripherals::$inst {} 180 impl GeneralInstance2Channel for crate::peripherals::$inst {}
181 impl GeneralInstance4Channel for crate::peripherals::$inst {}
182 impl GeneralInstance32bit4Channel for crate::peripherals::$inst {}
909 }; 183 };
910 184
911 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { 185 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => {
912 impl_core_timer!($inst, $irq); 186 impl_core_timer!($inst, TimerBits::Bits16);
913 impl_basic_no_cr2_timer!($inst); 187 impl BasicNoCr2Instance for crate::peripherals::$inst {}
914 impl_basic_timer!($inst);
915 impl_1ch_timer!($inst);
916 impl_2ch_timer!($inst);
917 impl_gp16_timer!($inst);
918 impl_1ch_cmp_timer!($inst);
919 impl_2ch_cmp_timer!($inst);
920 impl BasicInstance for crate::peripherals::$inst {} 188 impl BasicInstance for crate::peripherals::$inst {}
921 impl CaptureCompare16bitInstance for crate::peripherals::$inst { 189 impl GeneralInstance1Channel for crate::peripherals::$inst {}
922 /// Enable timer outputs. 190 impl GeneralInstance2Channel for crate::peripherals::$inst {}
923 fn enable_outputs(&self) { 191 impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }}
924 use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; 192 impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; }
925 self.set_moe(true); 193 impl AdvancedInstance2Channel for crate::peripherals::$inst {}
926 } 194 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
927 }
928 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
929 };
930 ($inst:ident, timer, TIM_1CH_CMP, CC, $irq:ident) => {
931 impl_adv_timer!($inst, $irq);
932 }; 195 };
933 196
934
935 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { 197 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => {
936 impl_core_timer!($inst, $irq); 198 impl_core_timer!($inst, TimerBits::Bits16);
937 impl_basic_no_cr2_timer!($inst); 199 impl BasicNoCr2Instance for crate::peripherals::$inst {}
938 impl_basic_timer!($inst);
939 impl_1ch_timer!($inst);
940 impl_2ch_timer!($inst);
941 impl_gp16_timer!($inst);
942 impl_1ch_cmp_timer!($inst);
943 impl_2ch_cmp_timer!($inst);
944 impl BasicInstance for crate::peripherals::$inst {} 200 impl BasicInstance for crate::peripherals::$inst {}
945 impl CaptureCompare16bitInstance for crate::peripherals::$inst { 201 impl GeneralInstance1Channel for crate::peripherals::$inst {}
946 /// Enable timer outputs. 202 impl GeneralInstance2Channel for crate::peripherals::$inst {}
947 fn enable_outputs(&self) { 203 impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }}
948 use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; 204 impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; }
949 self.set_moe(true); 205 impl AdvancedInstance2Channel for crate::peripherals::$inst {}
950 } 206 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
951 }
952 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
953 };
954 ($inst:ident, timer, TIM_2CH_CMP, CC, $irq:ident) => {
955 impl_adv_timer!($inst, $irq);
956 }; 207 };
957 208
958
959 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 209 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
960 impl_core_timer!($inst, $irq); 210 impl_core_timer!($inst, TimerBits::Bits16);
961 impl_basic_no_cr2_timer!($inst); 211 impl BasicNoCr2Instance for crate::peripherals::$inst {}
962 impl_basic_timer!($inst);
963 impl_1ch_timer!($inst);
964 impl_2ch_timer!($inst);
965 impl_gp16_timer!($inst);
966 impl_1ch_cmp_timer!($inst);
967 impl_2ch_cmp_timer!($inst);
968 impl BasicInstance for crate::peripherals::$inst {} 212 impl BasicInstance for crate::peripherals::$inst {}
969 impl CaptureCompare16bitInstance for crate::peripherals::$inst { 213 impl GeneralInstance1Channel for crate::peripherals::$inst {}
970 /// Enable timer outputs. 214 impl GeneralInstance2Channel for crate::peripherals::$inst {}
971 fn enable_outputs(&self) { 215 impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }}
972 use crate::timer::sealed::GeneralPurpose1ChannelComplementaryInstance; 216 impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; }
973 self.set_moe(true); 217 impl AdvancedInstance2Channel for crate::peripherals::$inst {}
974 } 218 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
975 }
976 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
977 };
978 ($inst:ident, timer, TIM_ADV, CC, $irq:ident) => {
979 impl_adv_timer!($inst, $irq);
980 }; 219 };
981} 220}
982 221
983// Update Event trigger DMA for every timer 222#[cfg(not(stm32l0))]
984dma_trait!(UpDma, BasicInstance); 223#[allow(unused)]
985 224fn set_moe<T: GeneralInstance4Channel>() {
986dma_trait!(Ch1Dma, CaptureCompare16bitInstance); 225 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
987dma_trait!(Ch2Dma, CaptureCompare16bitInstance); 226 .bdtr()
988dma_trait!(Ch3Dma, CaptureCompare16bitInstance); 227 .modify(|w| w.set_moe(true));
989dma_trait!(Ch4Dma, CaptureCompare16bitInstance); 228}
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index 59efb72ba..b6ab939cc 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -3,8 +3,10 @@
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
6use stm32_metapac::timer::vals;
6 7
7use super::*; 8use super::low_level::Timer;
9use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel};
8use crate::gpio::sealed::AFType; 10use crate::gpio::sealed::AFType;
9use crate::gpio::AnyPin; 11use crate::gpio::AnyPin;
10use crate::Peripheral; 12use crate::Peripheral;
@@ -30,7 +32,7 @@ pub struct QeiPin<'d, T, Channel> {
30 32
31macro_rules! channel_impl { 33macro_rules! channel_impl {
32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 34 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
33 impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { 35 impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> {
34 #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] 36 #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")]
35 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { 37 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
36 into_ref!(pin); 38 into_ref!(pin);
@@ -53,29 +55,28 @@ channel_impl!(new_ch1, Ch1, Channel1Pin);
53channel_impl!(new_ch2, Ch2, Channel2Pin); 55channel_impl!(new_ch2, Ch2, Channel2Pin);
54 56
55/// Quadrature decoder driver. 57/// Quadrature decoder driver.
56pub struct Qei<'d, T> { 58pub struct Qei<'d, T: GeneralInstance4Channel> {
57 _inner: PeripheralRef<'d, T>, 59 inner: Timer<'d, T>,
58} 60}
59 61
60impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { 62impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
61 /// Create a new quadrature decoder driver. 63 /// Create a new quadrature decoder driver.
62 pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { 64 pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self {
63 Self::new_inner(tim) 65 Self::new_inner(tim)
64 } 66 }
65 67
66 fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { 68 fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self {
67 into_ref!(tim); 69 let inner = Timer::new(tim);
68 70 let r = inner.regs_gp16();
69 T::enable_and_reset();
70 71
71 // Configure TxC1 and TxC2 as captures 72 // Configure TxC1 and TxC2 as captures
72 T::regs_gp16().ccmr_input(0).modify(|w| { 73 r.ccmr_input(0).modify(|w| {
73 w.set_ccs(0, vals::CcmrInputCcs::TI4); 74 w.set_ccs(0, vals::CcmrInputCcs::TI4);
74 w.set_ccs(1, vals::CcmrInputCcs::TI4); 75 w.set_ccs(1, vals::CcmrInputCcs::TI4);
75 }); 76 });
76 77
77 // enable and configure to capture on rising edge 78 // enable and configure to capture on rising edge
78 T::regs_gp16().ccer().modify(|w| { 79 r.ccer().modify(|w| {
79 w.set_cce(0, true); 80 w.set_cce(0, true);
80 w.set_cce(1, true); 81 w.set_cce(1, true);
81 82
@@ -83,19 +84,19 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
83 w.set_ccp(1, false); 84 w.set_ccp(1, false);
84 }); 85 });
85 86
86 T::regs_gp16().smcr().modify(|w| { 87 r.smcr().modify(|w| {
87 w.set_sms(vals::Sms::ENCODER_MODE_3); 88 w.set_sms(vals::Sms::ENCODER_MODE_3);
88 }); 89 });
89 90
90 T::regs_gp16().arr().modify(|w| w.set_arr(u16::MAX)); 91 r.arr().modify(|w| w.set_arr(u16::MAX));
91 T::regs_gp16().cr1().modify(|w| w.set_cen(true)); 92 r.cr1().modify(|w| w.set_cen(true));
92 93
93 Self { _inner: tim } 94 Self { inner }
94 } 95 }
95 96
96 /// Get direction. 97 /// Get direction.
97 pub fn read_direction(&self) -> Direction { 98 pub fn read_direction(&self) -> Direction {
98 match T::regs_gp16().cr1().read().dir() { 99 match self.inner.regs_gp16().cr1().read().dir() {
99 vals::Dir::DOWN => Direction::Downcounting, 100 vals::Dir::DOWN => Direction::Downcounting,
100 vals::Dir::UP => Direction::Upcounting, 101 vals::Dir::UP => Direction::Upcounting,
101 } 102 }
@@ -103,6 +104,6 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
103 104
104 /// Get count. 105 /// Get count.
105 pub fn count(&self) -> u16 { 106 pub fn count(&self) -> u16 {
106 T::regs_gp16().cnt().read().cnt() 107 self.inner.regs_gp16().cnt().read().cnt()
107 } 108 }
108} 109}
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 4669fc6cc..b54e9a0d6 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -4,10 +4,10 @@ use core::marker::PhantomData;
4 4
5use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
6 6
7use super::*; 7use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
8#[allow(unused_imports)] 8use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel};
9use crate::gpio::sealed::{AFType, Pin};
10use crate::gpio::{AnyPin, OutputType}; 9use crate::gpio::{AnyPin, OutputType};
10use crate::time::Hertz;
11use crate::Peripheral; 11use crate::Peripheral;
12 12
13/// Channel 1 marker type. 13/// Channel 1 marker type.
@@ -29,7 +29,7 @@ pub struct PwmPin<'d, T, C> {
29 29
30macro_rules! channel_impl { 30macro_rules! channel_impl {
31 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 31 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
32 impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { 32 impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> {
33 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 33 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
34 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { 34 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
35 into_ref!(pin); 35 into_ref!(pin);
@@ -54,11 +54,11 @@ channel_impl!(new_ch3, Ch3, Channel3Pin);
54channel_impl!(new_ch4, Ch4, Channel4Pin); 54channel_impl!(new_ch4, Ch4, Channel4Pin);
55 55
56/// Simple PWM driver. 56/// Simple PWM driver.
57pub struct SimplePwm<'d, T> { 57pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
58 inner: PeripheralRef<'d, T>, 58 inner: Timer<'d, T>,
59} 59}
60 60
61impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 61impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
62 /// Create a new simple PWM driver. 62 /// Create a new simple PWM driver.
63 pub fn new( 63 pub fn new(
64 tim: impl Peripheral<P = T> + 'd, 64 tim: impl Peripheral<P = T> + 'd,
@@ -73,15 +73,11 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
73 } 73 }
74 74
75 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self { 75 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self {
76 into_ref!(tim); 76 let mut this = Self { inner: Timer::new(tim) };
77
78 T::enable_and_reset();
79
80 let mut this = Self { inner: tim };
81 77
82 this.inner.set_counting_mode(counting_mode); 78 this.inner.set_counting_mode(counting_mode);
83 this.set_frequency(freq); 79 this.set_frequency(freq);
84 this.inner.enable_outputs(); // Required for advanced timers, see CaptureCompare16bitInstance for details 80 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
85 this.inner.start(); 81 this.inner.start();
86 82
87 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] 83 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
@@ -126,14 +122,14 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
126 /// Get max duty value. 122 /// Get max duty value.
127 /// 123 ///
128 /// This value depends on the configured frequency and the timer's clock rate from RCC. 124 /// This value depends on the configured frequency and the timer's clock rate from RCC.
129 pub fn get_max_duty(&self) -> u16 { 125 pub fn get_max_duty(&self) -> u32 {
130 self.inner.get_max_compare_value() + 1 126 self.inner.get_max_compare_value() + 1
131 } 127 }
132 128
133 /// Set the duty for a given channel. 129 /// Set the duty for a given channel.
134 /// 130 ///
135 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. 131 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
136 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 132 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
137 assert!(duty <= self.get_max_duty()); 133 assert!(duty <= self.get_max_duty());
138 self.inner.set_compare_value(channel, duty) 134 self.inner.set_compare_value(channel, duty)
139 } 135 }
@@ -141,7 +137,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
141 /// Get the duty for a given channel. 137 /// Get the duty for a given channel.
142 /// 138 ///
143 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. 139 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
144 pub fn get_duty(&self, channel: Channel) -> u16 { 140 pub fn get_duty(&self, channel: Channel) -> u32 {
145 self.inner.get_compare_value(channel) 141 self.inner.get_compare_value(channel)
146 } 142 }
147 143
@@ -165,8 +161,6 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
165 channel: Channel, 161 channel: Channel,
166 duty: &[u16], 162 duty: &[u16],
167 ) { 163 ) {
168 assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
169
170 into_ref!(dma); 164 into_ref!(dma);
171 165
172 #[allow(clippy::let_unit_value)] // eg. stm32f334 166 #[allow(clippy::let_unit_value)] // eg. stm32f334
@@ -201,7 +195,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
201 &mut dma, 195 &mut dma,
202 req, 196 req,
203 duty, 197 duty,
204 T::regs_1ch().ccr(channel.index()).as_ptr() as *mut _, 198 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut _,
205 dma_transfer_option, 199 dma_transfer_option,
206 ) 200 )
207 .await 201 .await
@@ -227,22 +221,20 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
227 221
228macro_rules! impl_waveform_chx { 222macro_rules! impl_waveform_chx {
229 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { 223 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => {
230 impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 224 impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
231 /// Generate a sequence of PWM waveform 225 /// Generate a sequence of PWM waveform
232 /// 226 ///
233 /// Note: 227 /// Note:
234 /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. 228 /// you will need to provide corresponding TIMx_CHy DMA channel to use this method.
235 pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) { 229 pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) {
236 use super::vals::Ccds; 230 use crate::pac::timer::vals::Ccds;
237
238 assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
239 231
240 into_ref!(dma); 232 into_ref!(dma);
241 233
242 #[allow(clippy::let_unit_value)] // eg. stm32f334 234 #[allow(clippy::let_unit_value)] // eg. stm32f334
243 let req = dma.request(); 235 let req = dma.request();
244 236
245 let cc_channel = super::Channel::$cc_ch; 237 let cc_channel = Channel::$cc_ch;
246 238
247 let original_duty_state = self.get_duty(cc_channel); 239 let original_duty_state = self.get_duty(cc_channel);
248 let original_enable_state = self.is_enabled(cc_channel); 240 let original_enable_state = self.is_enabled(cc_channel);
@@ -279,7 +271,7 @@ macro_rules! impl_waveform_chx {
279 &mut dma, 271 &mut dma,
280 req, 272 req,
281 duty, 273 duty,
282 T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, 274 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _,
283 dma_transfer_option, 275 dma_transfer_option,
284 ) 276 )
285 .await 277 .await
@@ -314,10 +306,10 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
314impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); 306impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
315impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); 307impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
316 308
317impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> { 309impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
318 type Channel = Channel; 310 type Channel = Channel;
319 type Time = Hertz; 311 type Time = Hertz;
320 type Duty = u16; 312 type Duty = u32;
321 313
322 fn disable(&mut self, channel: Self::Channel) { 314 fn disable(&mut self, channel: Self::Channel) {
323 self.inner.enable_channel(channel, false); 315 self.inner.enable_channel(channel, false);
diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs
index 6122cea2d..cbaff75fc 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm.rs
@@ -15,8 +15,9 @@
15use embassy_executor::Spawner; 15use embassy_executor::Spawner;
16use embassy_stm32::gpio::OutputType; 16use embassy_stm32::gpio::OutputType;
17use embassy_stm32::time::khz; 17use embassy_stm32::time::khz;
18use embassy_stm32::timer::low_level::CountingMode;
18use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 19use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
19use embassy_stm32::timer::{Channel, CountingMode}; 20use embassy_stm32::timer::Channel;
20use embassy_time::{Duration, Ticker, Timer}; 21use embassy_time::{Duration, Ticker, Timer};
21use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
22 23
@@ -60,7 +61,7 @@ async fn main(_spawner: Spawner) {
60 // construct ws2812 non-return-to-zero (NRZ) code bit by bit 61 // construct ws2812 non-return-to-zero (NRZ) code bit by bit
61 // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low 62 // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low
62 63
63 let max_duty = ws2812_pwm.get_max_duty(); 64 let max_duty = ws2812_pwm.get_max_duty() as u16;
64 let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing 65 let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing
65 let n1 = 2 * n0; // ws2812 Bit 1 high level timing 66 let n1 = 2 * n0; // ws2812 Bit 1 high level timing
66 67
diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs
index feec28993..c45747f35 100644
--- a/examples/stm32h7/src/bin/dac_dma.rs
+++ b/examples/stm32h7/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::low_level::RccPeripheral;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::BasicInstance; 11use embassy_stm32::timer::low_level::Timer;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
@@ -51,12 +51,12 @@ async fn main(spawner: Spawner) {
51 // Obtain two independent channels (p.DAC1 can only be consumed once, though!) 51 // Obtain two independent channels (p.DAC1 can only be consumed once, though!)
52 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); 52 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
53 53
54 spawner.spawn(dac_task1(dac_ch1)).ok(); 54 spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok();
55 spawner.spawn(dac_task2(dac_ch2)).ok(); 55 spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok();
56} 56}
57 57
58#[embassy_executor::task] 58#[embassy_executor::task]
59async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { 59async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
60 let data: &[u8; 256] = &calculate_array::<256>(); 60 let data: &[u8; 256] = &calculate_array::<256>();
61 61
62 info!("TIM6 frequency is {}", TIM6::frequency()); 62 info!("TIM6 frequency is {}", TIM6::frequency());
@@ -74,10 +74,10 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
74 dac.set_triggering(true); 74 dac.set_triggering(true);
75 dac.enable(); 75 dac.enable();
76 76
77 TIM6::enable_and_reset(); 77 let tim = Timer::new(tim);
78 TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); 78 tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
79 TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 79 tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
80 TIM6::regs_basic().cr1().modify(|w| { 80 tim.regs_basic().cr1().modify(|w| {
81 w.set_opm(false); 81 w.set_opm(false);
82 w.set_cen(true); 82 w.set_cen(true);
83 }); 83 });
@@ -99,7 +99,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
99} 99}
100 100
101#[embassy_executor::task] 101#[embassy_executor::task]
102async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { 102async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
103 let data: &[u8; 256] = &calculate_array::<256>(); 103 let data: &[u8; 256] = &calculate_array::<256>();
104 104
105 info!("TIM7 frequency is {}", TIM7::frequency()); 105 info!("TIM7 frequency is {}", TIM7::frequency());
@@ -111,10 +111,10 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
111 error!("Reload value {} below threshold!", reload); 111 error!("Reload value {} below threshold!", reload);
112 } 112 }
113 113
114 TIM7::enable_and_reset(); 114 let tim = Timer::new(tim);
115 TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); 115 tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
116 TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 116 tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
117 TIM7::regs_basic().cr1().modify(|w| { 117 tim.regs_basic().cr1().modify(|w| {
118 w.set_opm(false); 118 w.set_opm(false);
119 w.set_cen(true); 119 w.set_cen(true);
120 }); 120 });
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index 049d9967d..780fbc6f0 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -6,8 +6,9 @@ use embassy_executor::Spawner;
6use embassy_stm32::gpio::low_level::AFType; 6use embassy_stm32::gpio::low_level::AFType;
7use embassy_stm32::gpio::Speed; 7use embassy_stm32::gpio::Speed;
8use embassy_stm32::time::{khz, Hertz}; 8use embassy_stm32::time::{khz, Hertz};
9use embassy_stm32::timer::*; 9use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer};
10use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; 10use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel};
11use embassy_stm32::{into_ref, Config, Peripheral};
11use embassy_time::Timer; 12use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
@@ -56,11 +57,11 @@ async fn main(_spawner: Spawner) {
56 Timer::after_millis(300).await; 57 Timer::after_millis(300).await;
57 } 58 }
58} 59}
59pub struct SimplePwm32<'d, T: CaptureCompare32bitInstance> { 60pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> {
60 inner: PeripheralRef<'d, T>, 61 tim: LLTimer<'d, T>,
61} 62}
62 63
63impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { 64impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> {
64 pub fn new( 65 pub fn new(
65 tim: impl Peripheral<P = T> + 'd, 66 tim: impl Peripheral<P = T> + 'd,
66 ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd, 67 ch1: impl Peripheral<P = impl Channel1Pin<T>> + 'd,
@@ -69,9 +70,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
69 ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd, 70 ch4: impl Peripheral<P = impl Channel4Pin<T>> + 'd,
70 freq: Hertz, 71 freq: Hertz,
71 ) -> Self { 72 ) -> Self {
72 into_ref!(tim, ch1, ch2, ch3, ch4); 73 into_ref!(ch1, ch2, ch3, ch4);
73
74 T::enable_and_reset();
75 74
76 ch1.set_speed(Speed::VeryHigh); 75 ch1.set_speed(Speed::VeryHigh);
77 ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); 76 ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull);
@@ -82,12 +81,12 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
82 ch4.set_speed(Speed::VeryHigh); 81 ch4.set_speed(Speed::VeryHigh);
83 ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull); 82 ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull);
84 83
85 let mut this = Self { inner: tim }; 84 let mut this = Self { tim: LLTimer::new(tim) };
86 85
87 this.set_frequency(freq); 86 this.set_frequency(freq);
88 this.inner.start(); 87 this.tim.start();
89 88
90 let r = T::regs_gp32(); 89 let r = this.tim.regs_gp32();
91 r.ccmr_output(0) 90 r.ccmr_output(0)
92 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); 91 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
93 r.ccmr_output(0) 92 r.ccmr_output(0)
@@ -101,23 +100,26 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
101 } 100 }
102 101
103 pub fn enable(&mut self, channel: Channel) { 102 pub fn enable(&mut self, channel: Channel) {
104 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true)); 103 self.tim.regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true));
105 } 104 }
106 105
107 pub fn disable(&mut self, channel: Channel) { 106 pub fn disable(&mut self, channel: Channel) {
108 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false)); 107 self.tim
108 .regs_gp32()
109 .ccer()
110 .modify(|w| w.set_cce(channel.index(), false));
109 } 111 }
110 112
111 pub fn set_frequency(&mut self, freq: Hertz) { 113 pub fn set_frequency(&mut self, freq: Hertz) {
112 <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); 114 self.tim.set_frequency(freq);
113 } 115 }
114 116
115 pub fn get_max_duty(&self) -> u32 { 117 pub fn get_max_duty(&self) -> u32 {
116 T::regs_gp32().arr().read() 118 self.tim.regs_gp32().arr().read()
117 } 119 }
118 120
119 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 121 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
120 defmt::assert!(duty < self.get_max_duty()); 122 defmt::assert!(duty < self.get_max_duty());
121 T::regs_gp32().ccr(channel.index()).write_value(duty) 123 self.tim.regs_gp32().ccr(channel.index()).write_value(duty)
122 } 124 }
123} 125}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index f227812cd..98edd39c0 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -8,7 +8,7 @@ use embassy_stm32::pac::timer::vals::Mms;
8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; 8use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7};
9use embassy_stm32::rcc::low_level::RccPeripheral; 9use embassy_stm32::rcc::low_level::RccPeripheral;
10use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::timer::low_level::BasicInstance; 11use embassy_stm32::timer::low_level::Timer;
12use micromath::F32Ext; 12use micromath::F32Ext;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
@@ -22,12 +22,12 @@ async fn main(spawner: Spawner) {
22 // Obtain two independent channels (p.DAC1 can only be consumed once, though!) 22 // Obtain two independent channels (p.DAC1 can only be consumed once, though!)
23 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); 23 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
24 24
25 spawner.spawn(dac_task1(dac_ch1)).ok(); 25 spawner.spawn(dac_task1(p.TIM6, dac_ch1)).ok();
26 spawner.spawn(dac_task2(dac_ch2)).ok(); 26 spawner.spawn(dac_task2(p.TIM7, dac_ch2)).ok();
27} 27}
28 28
29#[embassy_executor::task] 29#[embassy_executor::task]
30async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { 30async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
31 let data: &[u8; 256] = &calculate_array::<256>(); 31 let data: &[u8; 256] = &calculate_array::<256>();
32 32
33 info!("TIM6 frequency is {}", TIM6::frequency()); 33 info!("TIM6 frequency is {}", TIM6::frequency());
@@ -45,10 +45,10 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
45 dac.set_triggering(true); 45 dac.set_triggering(true);
46 dac.enable(); 46 dac.enable();
47 47
48 TIM6::enable_and_reset(); 48 let tim = Timer::new(tim);
49 TIM6::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); 49 tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
50 TIM6::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 50 tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
51 TIM6::regs_basic().cr1().modify(|w| { 51 tim.regs_basic().cr1().modify(|w| {
52 w.set_opm(false); 52 w.set_opm(false);
53 w.set_cen(true); 53 w.set_cen(true);
54 }); 54 });
@@ -70,7 +70,7 @@ async fn dac_task1(mut dac: DacCh1<'static, DAC1, DMA1_CH3>) {
70} 70}
71 71
72#[embassy_executor::task] 72#[embassy_executor::task]
73async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { 73async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
74 let data: &[u8; 256] = &calculate_array::<256>(); 74 let data: &[u8; 256] = &calculate_array::<256>();
75 75
76 info!("TIM7 frequency is {}", TIM7::frequency()); 76 info!("TIM7 frequency is {}", TIM7::frequency());
@@ -82,10 +82,10 @@ async fn dac_task2(mut dac: DacCh2<'static, DAC1, DMA1_CH4>) {
82 error!("Reload value {} below threshold!", reload); 82 error!("Reload value {} below threshold!", reload);
83 } 83 }
84 84
85 TIM7::enable_and_reset(); 85 let tim = Timer::new(tim);
86 TIM7::regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1)); 86 tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
87 TIM7::regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE)); 87 tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
88 TIM7::regs_basic().cr1().modify(|w| { 88 tim.regs_basic().cr1().modify(|w| {
89 w.set_opm(false); 89 w.set_opm(false);
90 w.set_cen(true); 90 w.set_cen(true);
91 }); 91 });