aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-07-28 15:29:27 +0200
committerGitHub <[email protected]>2023-07-28 15:29:27 +0200
commit3690af9bea5968653780d296146a91c63994d89d (patch)
tree02baa484846448186a13b28c52cc4221b4111b74 /embassy-stm32/src/timer
parentb1242226494bfdeed13c2f80c5df239687a398ac (diff)
stm32/timer: merge pwm module into timer. (#1703)
The traits there are applicable to timer use cases other than PWM. It doesn't make sense to keep them separated.
Diffstat (limited to 'embassy-stm32/src/timer')
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs250
-rw-r--r--embassy-stm32/src/timer/mod.rs271
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs107
3 files changed, 603 insertions, 25 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
new file mode 100644
index 000000000..64bb32c39
--- /dev/null
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -0,0 +1,250 @@
1use core::marker::PhantomData;
2
3use embassy_hal_internal::{into_ref, PeripheralRef};
4use stm32_metapac::timer::vals::Ckd;
5
6use super::simple_pwm::*;
7use super::*;
8#[allow(unused_imports)]
9use crate::gpio::sealed::{AFType, Pin};
10use crate::gpio::AnyPin;
11use crate::time::Hertz;
12use crate::Peripheral;
13
14pub struct ComplementaryPwmPin<'d, Perip, Channel> {
15 _pin: PeripheralRef<'d, AnyPin>,
16 phantom: PhantomData<(Perip, Channel)>,
17}
18
19macro_rules! complementary_channel_impl {
20 ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => {
21 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
22 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
23 into_ref!(pin);
24 critical_section::with(|_| {
25 pin.set_low();
26 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
27 #[cfg(gpio_v2)]
28 pin.set_speed(crate::gpio::Speed::VeryHigh);
29 });
30 ComplementaryPwmPin {
31 _pin: pin.map_into(),
32 phantom: PhantomData,
33 }
34 }
35 }
36 };
37}
38
39complementary_channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin);
40complementary_channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin);
41complementary_channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin);
42complementary_channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin);
43
44pub struct ComplementaryPwm<'d, T> {
45 inner: PeripheralRef<'d, T>,
46}
47
48impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
49 pub fn new(
50 tim: impl Peripheral<P = T> + 'd,
51 _ch1: Option<PwmPin<'d, T, Ch1>>,
52 _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>,
53 _ch2: Option<PwmPin<'d, T, Ch2>>,
54 _ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>,
55 _ch3: Option<PwmPin<'d, T, Ch3>>,
56 _ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>,
57 _ch4: Option<PwmPin<'d, T, Ch4>>,
58 _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>,
59 freq: Hertz,
60 ) -> Self {
61 Self::new_inner(tim, freq)
62 }
63
64 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self {
65 into_ref!(tim);
66
67 T::enable();
68 <T as crate::rcc::sealed::RccPeripheral>::reset();
69
70 let mut this = Self { inner: tim };
71
72 this.inner.set_frequency(freq);
73 this.inner.start();
74
75 this.inner.enable_outputs(true);
76
77 this.inner
78 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
79 this.inner
80 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
81 this.inner
82 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
83 this.inner
84 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
85 this
86 }
87
88 pub fn enable(&mut self, channel: Channel) {
89 self.inner.enable_channel(channel, true);
90 self.inner.enable_complementary_channel(channel, true);
91 }
92
93 pub fn disable(&mut self, channel: Channel) {
94 self.inner.enable_complementary_channel(channel, false);
95 self.inner.enable_channel(channel, false);
96 }
97
98 pub fn set_freq(&mut self, freq: Hertz) {
99 self.inner.set_frequency(freq);
100 }
101
102 pub fn get_max_duty(&self) -> u16 {
103 self.inner.get_max_compare_value()
104 }
105
106 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
107 assert!(duty < self.get_max_duty());
108 self.inner.set_compare_value(channel, duty)
109 }
110
111 /// Set the dead time as a proportion of max_duty
112 pub fn set_dead_time(&mut self, value: u16) {
113 let (ckd, value) = compute_dead_time_value(value);
114
115 self.inner.set_dead_time_clock_division(ckd);
116 self.inner.set_dead_time_value(value);
117 }
118}
119
120fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
121 /*
122 Dead-time = T_clk * T_dts * T_dtg
123
124 T_dts:
125 This bit-field indicates the division ratio between the timer clock (CK_INT) frequency and the
126 dead-time and sampling clock (tDTS)used by the dead-time generators and the digital filters
127 (ETR, TIx),
128 00: tDTS=tCK_INT
129 01: tDTS=2*tCK_INT
130 10: tDTS=4*tCK_INT
131
132 T_dtg:
133 This bit-field defines the duration of the dead-time inserted between the complementary
134 outputs. DT correspond to this duration.
135 DTG[7:5]=0xx => DT=DTG[7:0]x tdtg with tdtg=tDTS.
136 DTG[7:5]=10x => DT=(64+DTG[5:0])xtdtg with Tdtg=2xtDTS.
137 DTG[7:5]=110 => DT=(32+DTG[4:0])xtdtg with Tdtg=8xtDTS.
138 DTG[7:5]=111 => DT=(32+DTG[4:0])xtdtg with Tdtg=16xtDTS.
139 Example if TDTS=125ns (8MHz), dead-time possible values are:
140 0 to 15875 ns by 125 ns steps,
141 16 us to 31750 ns by 250 ns steps,
142 32 us to 63us by 1 us steps,
143 64 us to 126 us by 2 us steps
144 */
145
146 let mut error = u16::MAX;
147 let mut ckd = Ckd::DIV1;
148 let mut bits = 0u8;
149
150 for this_ckd in [Ckd::DIV1, Ckd::DIV2, Ckd::DIV4] {
151 let outdiv = match this_ckd {
152 Ckd::DIV1 => 1,
153 Ckd::DIV2 => 2,
154 Ckd::DIV4 => 4,
155 _ => unreachable!(),
156 };
157
158 // 127
159 // 128
160 // ..
161 // 254
162 // 256
163 // ..
164 // 504
165 // 512
166 // ..
167 // 1008
168
169 let target = value / outdiv;
170 let (these_bits, result) = if target < 128 {
171 (target as u8, target)
172 } else if target < 255 {
173 (64 + (target / 2) as u8, (target - target % 2))
174 } else if target < 508 {
175 (32 + (target / 8) as u8, (target - target % 8))
176 } else if target < 1008 {
177 (32 + (target / 16) as u8, (target - target % 16))
178 } else {
179 (u8::MAX, 1008)
180 };
181
182 let this_error = value.abs_diff(result * outdiv);
183 if error > this_error {
184 ckd = this_ckd;
185 bits = these_bits;
186 error = this_error;
187 }
188
189 match error {
190 0 => break,
191 _ => {}
192 }
193 }
194
195 (ckd, bits)
196}
197
198#[cfg(test)]
199mod tests {
200 use super::{compute_dead_time_value, Ckd};
201
202 #[test]
203 fn test_compute_dead_time_value() {
204 struct TestRun {
205 value: u16,
206 ckd: Ckd,
207 bits: u8,
208 }
209
210 let fn_results = [
211 TestRun {
212 value: 1,
213 ckd: Ckd::DIV1,
214 bits: 1,
215 },
216 TestRun {
217 value: 125,
218 ckd: Ckd::DIV1,
219 bits: 125,
220 },
221 TestRun {
222 value: 245,
223 ckd: Ckd::DIV1,
224 bits: 64 + 245 / 2,
225 },
226 TestRun {
227 value: 255,
228 ckd: Ckd::DIV2,
229 bits: 127,
230 },
231 TestRun {
232 value: 400,
233 ckd: Ckd::DIV1,
234 bits: 32 + (400u16 / 8) as u8,
235 },
236 TestRun {
237 value: 600,
238 ckd: Ckd::DIV4,
239 bits: 64 + (600u16 / 8) as u8,
240 },
241 ];
242
243 for test_run in fn_results {
244 let (ckd, bits) = compute_dead_time_value(test_run.value);
245
246 assert_eq!(ckd.to_bits(), test_run.ckd.to_bits());
247 assert_eq!(bits, test_run.bits);
248 }
249 }
250}
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 09b7a3776..6c2d6d827 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -1,3 +1,6 @@
1pub mod complementary_pwm;
2pub mod simple_pwm;
3
1use stm32_metapac::timer::vals; 4use stm32_metapac::timer::vals;
2 5
3use crate::interrupt; 6use crate::interrupt;
@@ -43,15 +46,123 @@ pub(crate) mod sealed {
43 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { 46 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
44 fn regs_advanced() -> crate::pac::timer::TimAdv; 47 fn regs_advanced() -> crate::pac::timer::TimAdv;
45 } 48 }
49
50 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
51 /// Global output enable. Does not do anything on non-advanced timers.
52 fn enable_outputs(&mut self, enable: bool);
53
54 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
55
56 fn enable_channel(&mut self, channel: Channel, enable: bool);
57
58 fn set_compare_value(&mut self, channel: Channel, value: u16);
59
60 fn get_max_compare_value(&self) -> u16;
61 }
62
63 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance {
64 fn set_dead_time_clock_division(&mut self, value: vals::Ckd);
65
66 fn set_dead_time_value(&mut self, value: u8);
67
68 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool);
69 }
70
71 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance {
72 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
73
74 fn enable_channel(&mut self, channel: Channel, enable: bool);
75
76 fn set_compare_value(&mut self, channel: Channel, value: u32);
77
78 fn get_max_compare_value(&self) -> u32;
79 }
80}
81
82#[derive(Clone, Copy)]
83pub enum Channel {
84 Ch1,
85 Ch2,
86 Ch3,
87 Ch4,
46} 88}
47 89
90impl Channel {
91 pub fn raw(&self) -> usize {
92 match self {
93 Channel::Ch1 => 0,
94 Channel::Ch2 => 1,
95 Channel::Ch3 => 2,
96 Channel::Ch4 => 3,
97 }
98 }
99}
100
101#[derive(Clone, Copy)]
102pub enum OutputCompareMode {
103 Frozen,
104 ActiveOnMatch,
105 InactiveOnMatch,
106 Toggle,
107 ForceInactive,
108 ForceActive,
109 PwmMode1,
110 PwmMode2,
111}
112
113impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
114 fn from(mode: OutputCompareMode) -> Self {
115 match mode {
116 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN,
117 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH,
118 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH,
119 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE,
120 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE,
121 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE,
122 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1,
123 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2,
124 }
125 }
126}
127
128pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
129
48pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} 130pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
49 131
50pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} 132pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
51 133
52pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} 134pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
53 135
54pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} 136pub trait CaptureCompare16bitInstance:
137 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
138{
139}
140
141pub trait ComplementaryCaptureCompare16bitInstance:
142 sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
143{
144}
145
146pub trait CaptureCompare32bitInstance:
147 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
148{
149}
150
151pin_trait!(Channel1Pin, CaptureCompare16bitInstance);
152pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance);
153pin_trait!(Channel2Pin, CaptureCompare16bitInstance);
154pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance);
155pin_trait!(Channel3Pin, CaptureCompare16bitInstance);
156pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance);
157pin_trait!(Channel4Pin, CaptureCompare16bitInstance);
158pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance);
159pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance);
160pin_trait!(BreakInputPin, CaptureCompare16bitInstance);
161pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance);
162pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance);
163pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance);
164pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance);
165pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance);
55 166
56#[allow(unused)] 167#[allow(unused)]
57macro_rules! impl_basic_16bit_timer { 168macro_rules! impl_basic_16bit_timer {
@@ -140,33 +251,94 @@ macro_rules! impl_32bit_timer {
140 }; 251 };
141} 252}
142 253
254#[allow(unused)]
255macro_rules! impl_compare_capable_16bit {
256 ($inst:ident) => {
257 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
258 fn enable_outputs(&mut self, _enable: bool) {}
259
260 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
261 use sealed::GeneralPurpose16bitInstance;
262 let r = Self::regs_gp16();
263 let raw_channel: usize = channel.raw();
264 r.ccmr_output(raw_channel / 2)
265 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
266 }
267
268 fn enable_channel(&mut self, channel: Channel, enable: bool) {
269 use sealed::GeneralPurpose16bitInstance;
270 Self::regs_gp16()
271 .ccer()
272 .modify(|w| w.set_cce(channel.raw(), enable));
273 }
274
275 fn set_compare_value(&mut self, channel: Channel, value: u16) {
276 use sealed::GeneralPurpose16bitInstance;
277 Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value));
278 }
279
280 fn get_max_compare_value(&self) -> u16 {
281 use sealed::GeneralPurpose16bitInstance;
282 Self::regs_gp16().arr().read().arr()
283 }
284 }
285 };
286}
287
143foreach_interrupt! { 288foreach_interrupt! {
144 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { 289 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
145 impl_basic_16bit_timer!($inst, $irq); 290 impl_basic_16bit_timer!($inst, $irq);
146 291 impl Basic16bitInstance for crate::peripherals::$inst {}
147 impl Basic16bitInstance for crate::peripherals::$inst {
148 }
149 }; 292 };
150 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { 293 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
151 impl_basic_16bit_timer!($inst, $irq); 294 impl_basic_16bit_timer!($inst, $irq);
152 295 impl_compare_capable_16bit!($inst);
153 impl Basic16bitInstance for crate::peripherals::$inst { 296 impl Basic16bitInstance for crate::peripherals::$inst {}
154 } 297 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
298 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
155 299
156 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 300 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
157 fn regs_gp16() -> crate::pac::timer::TimGp16 { 301 fn regs_gp16() -> crate::pac::timer::TimGp16 {
158 crate::pac::$inst 302 crate::pac::$inst
159 } 303 }
160 } 304 }
161
162 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {
163 }
164 }; 305 };
165 306
166 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 307 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
167 impl_basic_16bit_timer!($inst, $irq); 308 impl_basic_16bit_timer!($inst, $irq);
309 impl_32bit_timer!($inst);
310 impl_compare_capable_16bit!($inst);
311 impl Basic16bitInstance for crate::peripherals::$inst {}
312 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
313 impl CaptureCompare32bitInstance for crate::peripherals::$inst {}
314 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
315 impl GeneralPurpose32bitInstance for crate::peripherals::$inst {}
316
317 impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst {
318 fn set_output_compare_mode(
319 &mut self,
320 channel: Channel,
321 mode: OutputCompareMode,
322 ) {
323 use crate::timer::sealed::GeneralPurpose32bitInstance;
324 let raw_channel = channel.raw();
325 Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
326 }
327
328 fn enable_channel(&mut self, channel: Channel, enable: bool) {
329 use crate::timer::sealed::GeneralPurpose32bitInstance;
330 Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
331 }
168 332
169 impl Basic16bitInstance for crate::peripherals::$inst { 333 fn set_compare_value(&mut self, channel: Channel, value: u32) {
334 use crate::timer::sealed::GeneralPurpose32bitInstance;
335 Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
336 }
337
338 fn get_max_compare_value(&self) -> u32 {
339 use crate::timer::sealed::GeneralPurpose32bitInstance;
340 Self::regs_gp32().arr().read().arr() as u32
341 }
170 } 342 }
171 343
172 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 344 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
@@ -174,21 +346,16 @@ foreach_interrupt! {
174 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } 346 unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) }
175 } 347 }
176 } 348 }
177
178 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {
179 }
180
181 impl_32bit_timer!($inst);
182
183 impl GeneralPurpose32bitInstance for crate::peripherals::$inst {
184 }
185 }; 349 };
186 350
187 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 351 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
188 impl_basic_16bit_timer!($inst, $irq); 352 impl_basic_16bit_timer!($inst, $irq);
189 353
190 impl Basic16bitInstance for crate::peripherals::$inst { 354 impl Basic16bitInstance for crate::peripherals::$inst {}
191 } 355 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {}
356 impl CaptureCompare16bitInstance for crate::peripherals::$inst {}
357 impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {}
358 impl AdvancedControlInstance for crate::peripherals::$inst {}
192 359
193 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { 360 impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst {
194 fn regs_gp16() -> crate::pac::timer::TimGp16 { 361 fn regs_gp16() -> crate::pac::timer::TimGp16 {
@@ -196,16 +363,70 @@ foreach_interrupt! {
196 } 363 }
197 } 364 }
198 365
199 impl GeneralPurpose16bitInstance for crate::peripherals::$inst {
200 }
201
202 impl sealed::AdvancedControlInstance for crate::peripherals::$inst { 366 impl sealed::AdvancedControlInstance for crate::peripherals::$inst {
203 fn regs_advanced() -> crate::pac::timer::TimAdv { 367 fn regs_advanced() -> crate::pac::timer::TimAdv {
204 crate::pac::$inst 368 crate::pac::$inst
205 } 369 }
206 } 370 }
207 371
208 impl AdvancedControlInstance for crate::peripherals::$inst { 372 impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {
373 fn enable_outputs(&mut self, enable: bool) {
374 use crate::timer::sealed::AdvancedControlInstance;
375 let r = Self::regs_advanced();
376 r.bdtr().modify(|w| w.set_moe(enable));
377 }
378
379 fn set_output_compare_mode(
380 &mut self,
381 channel: Channel,
382 mode: OutputCompareMode,
383 ) {
384 use crate::timer::sealed::AdvancedControlInstance;
385 let r = Self::regs_advanced();
386 let raw_channel: usize = channel.raw();
387 r.ccmr_output(raw_channel / 2)
388 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
389 }
390
391 fn enable_channel(&mut self, channel: Channel, enable: bool) {
392 use crate::timer::sealed::AdvancedControlInstance;
393 Self::regs_advanced()
394 .ccer()
395 .modify(|w| w.set_cce(channel.raw(), enable));
396 }
397
398 fn set_compare_value(&mut self, channel: Channel, value: u16) {
399 use crate::timer::sealed::AdvancedControlInstance;
400 Self::regs_advanced()
401 .ccr(channel.raw())
402 .modify(|w| w.set_ccr(value));
403 }
404
405 fn get_max_compare_value(&self) -> u16 {
406 use crate::timer::sealed::AdvancedControlInstance;
407 Self::regs_advanced().arr().read().arr()
408 }
409 }
410
411 impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {
412 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
413 use crate::timer::sealed::AdvancedControlInstance;
414 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
415 }
416
417 fn set_dead_time_value(&mut self, value: u8) {
418 use crate::timer::sealed::AdvancedControlInstance;
419 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
420 }
421
422 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
423 use crate::timer::sealed::AdvancedControlInstance;
424 Self::regs_advanced()
425 .ccer()
426 .modify(|w| w.set_ccne(channel.raw(), enable));
427 }
209 } 428 }
429
430
210 }; 431 };
211} 432}
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
new file mode 100644
index 000000000..514796930
--- /dev/null
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -0,0 +1,107 @@
1use core::marker::PhantomData;
2
3use embassy_hal_internal::{into_ref, PeripheralRef};
4
5use super::*;
6#[allow(unused_imports)]
7use crate::gpio::sealed::{AFType, Pin};
8use crate::gpio::AnyPin;
9use crate::time::Hertz;
10use crate::Peripheral;
11
12pub struct Ch1;
13pub struct Ch2;
14pub struct Ch3;
15pub struct Ch4;
16
17pub struct PwmPin<'d, Perip, Channel> {
18 _pin: PeripheralRef<'d, AnyPin>,
19 phantom: PhantomData<(Perip, Channel)>,
20}
21
22macro_rules! channel_impl {
23 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
24 impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
25 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
26 into_ref!(pin);
27 critical_section::with(|_| {
28 pin.set_low();
29 pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
30 #[cfg(gpio_v2)]
31 pin.set_speed(crate::gpio::Speed::VeryHigh);
32 });
33 PwmPin {
34 _pin: pin.map_into(),
35 phantom: PhantomData,
36 }
37 }
38 }
39 };
40}
41
42channel_impl!(new_ch1, Ch1, Channel1Pin);
43channel_impl!(new_ch2, Ch2, Channel2Pin);
44channel_impl!(new_ch3, Ch3, Channel3Pin);
45channel_impl!(new_ch4, Ch4, Channel4Pin);
46
47pub struct SimplePwm<'d, T> {
48 inner: PeripheralRef<'d, T>,
49}
50
51impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
52 pub fn new(
53 tim: impl Peripheral<P = T> + 'd,
54 _ch1: Option<PwmPin<'d, T, Ch1>>,
55 _ch2: Option<PwmPin<'d, T, Ch2>>,
56 _ch3: Option<PwmPin<'d, T, Ch3>>,
57 _ch4: Option<PwmPin<'d, T, Ch4>>,
58 freq: Hertz,
59 ) -> Self {
60 Self::new_inner(tim, freq)
61 }
62
63 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self {
64 into_ref!(tim);
65
66 T::enable();
67 <T as crate::rcc::sealed::RccPeripheral>::reset();
68
69 let mut this = Self { inner: tim };
70
71 this.inner.set_frequency(freq);
72 this.inner.start();
73
74 this.inner.enable_outputs(true);
75
76 this.inner
77 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
78 this.inner
79 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
80 this.inner
81 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
82 this.inner
83 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
84 this
85 }
86
87 pub fn enable(&mut self, channel: Channel) {
88 self.inner.enable_channel(channel, true);
89 }
90
91 pub fn disable(&mut self, channel: Channel) {
92 self.inner.enable_channel(channel, false);
93 }
94
95 pub fn set_freq(&mut self, freq: Hertz) {
96 self.inner.set_frequency(freq);
97 }
98
99 pub fn get_max_duty(&self) -> u16 {
100 self.inner.get_max_compare_value()
101 }
102
103 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
104 assert!(duty < self.get_max_duty());
105 self.inner.set_compare_value(channel, duty)
106 }
107}