1use core::marker::PhantomData;
8
9use crate::pac::timer::vals::Ckd;
10use embassy_hal_internal::{into_ref, PeripheralRef};
11
12use super::low_level::{CountingMode, OutputPolarity, Timer};
13use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin};
14use super::{
15 AdvancedInstance4Channel, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin,
16 Channel3ComplementaryPin, Channel4ComplementaryPin,
17};
18use crate::gpio::{AnyPin, OutputType};
19use crate::time::Hertz;
20use crate::timer::low_level::OutputCompareMode;
21use crate::Peripheral;
22
23pub struct ComplementaryPwmPin<'d, T, C> {
27 _pin: PeripheralRef<'d, AnyPin>,
28 phantom: PhantomData<(T, C)>,
29}
30
31macro_rules! complementary_channel_impl {
32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
33 impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> {
34 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
35 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
36 into_ref!(pin);
37 critical_section::with(|_| {
38 pin.set_low();
39 pin.set_as_af(
40 pin.af_num(),
41 crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh),
42 );
43 });
44 ComplementaryPwmPin {
45 _pin: pin.map_into(),
46 phantom: PhantomData,
47 }
48 }
49 }
50 };
51}
52
53complementary_channel_impl!(new_ch1, Ch1, Channel1ComplementaryPin);
54complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin);
55complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
56complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
57
58pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> {
60 inner: Timer<'d, T>,
61}
62
63impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
64 #[allow(clippy::too_many_arguments)]
66 pub fn new(
67 tim: impl Peripheral<P = T> + 'd,
68 _ch1: Option<PwmPin<'d, T, Ch1>>,
69 _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>,
70 _ch2: Option<PwmPin<'d, T, Ch2>>,
71 _ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>,
72 _ch3: Option<PwmPin<'d, T, Ch3>>,
73 _ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>,
74 _ch4: Option<PwmPin<'d, T, Ch4>>,
75 _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>,
76 freq: Hertz,
77 counting_mode: CountingMode,
78 ) -> Self {
79 Self::new_inner(tim, freq, counting_mode)
80 }
81
82 fn new_inner(
83 tim: impl Peripheral<P = T> + 'd,
84 freq: Hertz,
85 counting_mode: CountingMode,
86 ) -> Self {
87 let mut this = Self {
88 inner: Timer::new(tim),
89 };
90
91 this.inner.set_counting_mode(counting_mode);
92 this.set_frequency(freq);
93 this.inner.start();
94
95 this.inner.enable_outputs();
96
97 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
98 .iter()
99 .for_each(|&channel| {
100 this.inner
101 .set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
102 this.inner.set_output_compare_preload(channel, true);
103 });
104
105 this
106 }
107
108 pub fn enable(&mut self, channel: Channel) {
110 self.inner.enable_channel(channel, true);
111 self.inner.enable_complementary_channel(channel, true);
112 }
113
114 pub fn disable(&mut self, channel: Channel) {
116 self.inner.enable_complementary_channel(channel, false);
117 self.inner.enable_channel(channel, false);
118 }
119
120 pub fn set_frequency(&mut self, freq: Hertz) {
125 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
126 2u8
127 } else {
128 1u8
129 };
130 self.inner.set_frequency(freq * multiplier);
131 }
132
133 pub fn get_max_duty(&self) -> u16 {
137 self.inner.get_max_compare_value() as u16 + 1
138 }
139
140 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
144 assert!(duty <= self.get_max_duty());
145 self.inner.set_compare_value(channel, duty as _)
146 }
147
148 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
150 self.inner.set_output_polarity(channel, polarity);
151 self.inner
152 .set_complementary_output_polarity(channel, polarity);
153 }
154
155 pub fn set_dead_time(&mut self, value: u16) {
157 let (ckd, value) = compute_dead_time_value(value);
158
159 self.inner.set_dead_time_clock_division(ckd);
160 self.inner.set_dead_time_value(value);
161 }
162}
163
164impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> {
165 type Channel = Channel;
166 type Time = Hertz;
167 type Duty = u16;
168
169 fn disable(&mut self, channel: Self::Channel) {
170 self.inner.enable_complementary_channel(channel, false);
171 self.inner.enable_channel(channel, false);
172 }
173
174 fn enable(&mut self, channel: Self::Channel) {
175 self.inner.enable_channel(channel, true);
176 self.inner.enable_complementary_channel(channel, true);
177 }
178
179 fn get_period(&self) -> Self::Time {
180 self.inner.get_frequency()
181 }
182
183 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
184 self.inner.get_compare_value(channel) as u16
185 }
186
187 fn get_max_duty(&self) -> Self::Duty {
188 self.inner.get_max_compare_value() as u16 + 1
189 }
190
191 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
192 assert!(duty <= self.get_max_duty());
193 self.inner.set_compare_value(channel, duty as u32)
194 }
195
196 fn set_period<P>(&mut self, period: P)
197 where
198 P: Into<Self::Time>,
199 {
200 self.inner.set_frequency(period.into());
201 }
202}
203
204fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
205 let mut error = u16::MAX;
231 let mut ckd = Ckd::DIV1;
232 let mut bits = 0u8;
233
234 for this_ckd in [Ckd::DIV1, Ckd::DIV2, Ckd::DIV4] {
235 let outdiv = match this_ckd {
236 Ckd::DIV1 => 1,
237 Ckd::DIV2 => 2,
238 Ckd::DIV4 => 4,
239 _ => unreachable!(),
240 };
241
242 let target = value / outdiv;
254 let (these_bits, result) = if target < 128 {
255 (target as u8, target)
256 } else if target < 255 {
257 (64 + (target / 2) as u8, (target - target % 2))
258 } else if target < 508 {
259 (32 + (target / 8) as u8, (target - target % 8))
260 } else if target < 1008 {
261 (32 + (target / 16) as u8, (target - target % 16))
262 } else {
263 (u8::MAX, 1008)
264 };
265
266 let this_error = value.abs_diff(result * outdiv);
267 if error > this_error {
268 ckd = this_ckd;
269 bits = these_bits;
270 error = this_error;
271 }
272
273 if error == 0 {
274 break;
275 }
276 }
277
278 (ckd, bits)
279}
280
281#[cfg(test)]
282mod tests {
283 use super::{compute_dead_time_value, Ckd};
284
285 #[test]
286 fn test_compute_dead_time_value() {
287 struct TestRun {
288 value: u16,
289 ckd: Ckd,
290 bits: u8,
291 }
292
293 let fn_results = [
294 TestRun {
295 value: 1,
296 ckd: Ckd::DIV1,
297 bits: 1,
298 },
299 TestRun {
300 value: 125,
301 ckd: Ckd::DIV1,
302 bits: 125,
303 },
304 TestRun {
305 value: 245,
306 ckd: Ckd::DIV1,
307 bits: 64 + 245 / 2,
308 },
309 TestRun {
310 value: 255,
311 ckd: Ckd::DIV2,
312 bits: 127,
313 },
314 TestRun {
315 value: 400,
316 ckd: Ckd::DIV1,
317 bits: 32 + (400u16 / 8) as u8,
318 },
319 TestRun {
320 value: 600,
321 ckd: Ckd::DIV4,
322 bits: 64 + (600u16 / 8) as u8,
323 },
324 ];
325
326 for test_run in fn_results {
327 let (ckd, bits) = compute_dead_time_value(test_run.value);
328
329 assert_eq!(ckd.to_bits(), test_run.ckd.to_bits());
330 assert_eq!(bits, test_run.bits);
331 }
332 }
333}