1use core::marker::PhantomData;
4
5pub use stm32_metapac::timer::vals::{Ckd, Ossi, Ossr};
6
7use super::low_level::{CountingMode, OutputPolarity, Timer};
8use super::simple_pwm::PwmPin;
9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin};
10use crate::gpio::{AnyPin, OutputType};
11use crate::time::Hertz;
12use crate::timer::low_level::OutputCompareMode;
13use crate::timer::TimerChannel;
14use crate::Peri;
15
16pub struct ComplementaryPwmPin<'d, T, C> {
20 _pin: Peri<'d, AnyPin>,
21 phantom: PhantomData<(T, C)>,
22}
23
24impl<'d, T: AdvancedInstance4Channel, C: TimerChannel> ComplementaryPwmPin<'d, T, C> {
25 pub fn new(pin: Peri<'d, impl TimerComplementaryPin<T, C>>, output_type: OutputType) -> Self {
27 critical_section::with(|_| {
28 pin.set_low();
29 pin.set_as_af(
30 pin.af_num(),
31 crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh),
32 );
33 });
34 ComplementaryPwmPin {
35 _pin: pin.into(),
36 phantom: PhantomData,
37 }
38 }
39}
40
41pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> {
43 inner: Timer<'d, T>,
44}
45
46#[derive(Copy, Clone, Debug, PartialEq, Eq)]
47pub enum IdlePolarity {
49 OisActive,
51 OisnActive,
53}
54
55impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
56 #[allow(clippy::too_many_arguments)]
58 pub fn new(
59 tim: Peri<'d, T>,
60 _ch1: Option<PwmPin<'d, T, Ch1>>,
61 _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>,
62 _ch2: Option<PwmPin<'d, T, Ch2>>,
63 _ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>,
64 _ch3: Option<PwmPin<'d, T, Ch3>>,
65 _ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>,
66 _ch4: Option<PwmPin<'d, T, Ch4>>,
67 _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>,
68 freq: Hertz,
69 counting_mode: CountingMode,
70 ) -> Self {
71 Self::new_inner(tim, freq, counting_mode)
72 }
73
74 fn new_inner(tim: Peri<'d, T>, freq: Hertz, counting_mode: CountingMode) -> Self {
75 let mut this = Self { inner: Timer::new(tim) };
76
77 this.inner.set_counting_mode(counting_mode);
78 this.set_frequency(freq);
79 this.inner.start();
80
81 this.inner.enable_outputs();
82
83 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
84 .iter()
85 .for_each(|&channel| {
86 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
87 this.inner.set_output_compare_preload(channel, true);
88 });
89 this.inner.set_autoreload_preload(true);
90
91 this
92 }
93
94 pub fn set_output_idle_state(&mut self, channels: &[Channel], polarity: IdlePolarity) {
96 let ois_active = matches!(polarity, IdlePolarity::OisActive);
97 for &channel in channels {
98 self.inner.set_ois(channel, ois_active);
99 self.inner.set_oisn(channel, !ois_active);
100 }
101 }
102
103 pub fn set_off_state_selection_idle(&mut self, val: Ossi) {
105 self.inner.set_ossi(val);
106 }
107
108 pub fn get_off_state_selection_idle(&self) -> Ossi {
110 self.inner.get_ossi()
111 }
112
113 pub fn set_off_state_selection_run(&mut self, val: Ossr) {
115 self.inner.set_ossr(val);
116 }
117
118 pub fn get_off_state_selection_run(&self) -> Ossr {
120 self.inner.get_ossr()
121 }
122
123 pub fn trigger_software_break(&mut self, n: usize) {
125 self.inner.trigger_software_break(n);
126 }
127
128 pub fn set_master_output_enable(&mut self, enable: bool) {
130 self.inner.set_moe(enable);
131 }
132
133 pub fn get_master_output_enable(&self) -> bool {
135 self.inner.get_moe()
136 }
137
138 pub fn enable(&mut self, channel: Channel) {
140 self.inner.enable_channel(channel, true);
141 self.inner.enable_complementary_channel(channel, true);
142 }
143
144 pub fn disable(&mut self, channel: Channel) {
146 self.inner.enable_complementary_channel(channel, false);
147 self.inner.enable_channel(channel, false);
148 }
149
150 pub fn set_frequency(&mut self, freq: Hertz) {
155 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
156 2u8
157 } else {
158 1u8
159 };
160 self.inner.set_frequency_internal(freq * multiplier, 16);
161 }
162
163 pub fn get_max_duty(&self) -> u16 {
167 if self.inner.get_counting_mode().is_center_aligned() {
168 self.inner.get_max_compare_value() as u16
169 } else {
170 self.inner.get_max_compare_value() as u16 + 1
171 }
172 }
173
174 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
178 assert!(duty <= self.get_max_duty());
179 self.inner.set_compare_value(channel, duty as _)
180 }
181
182 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
184 self.inner.set_output_polarity(channel, polarity);
185 self.inner.set_complementary_output_polarity(channel, polarity);
186 }
187
188 pub fn set_dead_time(&mut self, value: u16) {
190 let (ckd, value) = compute_dead_time_value(value);
191
192 self.inner.set_dead_time_clock_division(ckd);
193 self.inner.set_dead_time_value(value);
194 }
195}
196
197impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> {
198 type Channel = Channel;
199 type Time = Hertz;
200 type Duty = u16;
201
202 fn disable(&mut self, channel: Self::Channel) {
203 self.inner.enable_complementary_channel(channel, false);
204 self.inner.enable_channel(channel, false);
205 }
206
207 fn enable(&mut self, channel: Self::Channel) {
208 self.inner.enable_channel(channel, true);
209 self.inner.enable_complementary_channel(channel, true);
210 }
211
212 fn get_period(&self) -> Self::Time {
213 self.inner.get_frequency()
214 }
215
216 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
217 self.inner.get_compare_value(channel) as u16
218 }
219
220 fn get_max_duty(&self) -> Self::Duty {
221 if self.inner.get_counting_mode().is_center_aligned() {
222 self.inner.get_max_compare_value() as u16
223 } else {
224 self.inner.get_max_compare_value() as u16 + 1
225 }
226 }
227
228 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
229 assert!(duty <= self.get_max_duty());
230 self.inner.set_compare_value(channel, duty as u32)
231 }
232
233 fn set_period<P>(&mut self, period: P)
234 where
235 P: Into<Self::Time>,
236 {
237 self.inner.set_frequency(period.into());
238 }
239}
240
241fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
242 let mut error = u16::MAX;
268 let mut ckd = Ckd::DIV1;
269 let mut bits = 0u8;
270
271 for this_ckd in [Ckd::DIV1, Ckd::DIV2, Ckd::DIV4] {
272 let outdiv = match this_ckd {
273 Ckd::DIV1 => 1,
274 Ckd::DIV2 => 2,
275 Ckd::DIV4 => 4,
276 _ => unreachable!(),
277 };
278
279 let target = value / outdiv;
291 let (these_bits, result) = if target < 128 {
292 (target as u8, target)
293 } else if target < 255 {
294 ((64 + (target / 2) as u8) | 128, (target - target % 2))
295 } else if target < 508 {
296 ((32 + (target / 8) as u8) | 192, (target - target % 8))
297 } else if target < 1008 {
298 ((32 + (target / 16) as u8) | 224, (target - target % 16))
299 } else {
300 (u8::MAX, 1008)
301 };
302
303 let this_error = value.abs_diff(result * outdiv);
304 if error > this_error {
305 ckd = this_ckd;
306 bits = these_bits;
307 error = this_error;
308 }
309
310 if error == 0 {
311 break;
312 }
313 }
314
315 (ckd, bits)
316}
317
318#[cfg(test)]
319mod tests {
320 use super::{compute_dead_time_value, Ckd};
321
322 #[test]
323 fn test_compute_dead_time_value() {
324 struct TestRun {
325 value: u16,
326 ckd: Ckd,
327 bits: u8,
328 }
329
330 let fn_results = [
331 TestRun {
332 value: 1,
333 ckd: Ckd::DIV1,
334 bits: 1,
335 },
336 TestRun {
337 value: 125,
338 ckd: Ckd::DIV1,
339 bits: 125,
340 },
341 TestRun {
342 value: 245,
343 ckd: Ckd::DIV1,
344 bits: 64 + 245 / 2,
345 },
346 TestRun {
347 value: 255,
348 ckd: Ckd::DIV2,
349 bits: 127,
350 },
351 TestRun {
352 value: 400,
353 ckd: Ckd::DIV1,
354 bits: 210,
355 },
356 TestRun {
357 value: 600,
358 ckd: Ckd::DIV4,
359 bits: 64 + (600u16 / 8) as u8,
360 },
361 ];
362
363 for test_run in fn_results {
364 let (ckd, bits) = compute_dead_time_value(test_run.value);
365
366 assert_eq!(ckd.to_bits(), test_run.ckd.to_bits());
367 assert_eq!(bits, test_run.bits);
368 }
369 }
370}