1use core::marker::PhantomData;
13
14use super::PeripheralGuard;
15use crate::{
16 gpio::interconnect::{OutputSignal, PeripheralOutput},
17 mcpwm::{PwmPeripheral, timer::Timer},
18 pac,
19};
20
21#[derive(Copy, Clone)]
23#[allow(clippy::upper_case_acronyms, reason = "peripheral is unstable")]
24pub enum PWMStream {
25 PWMA,
27 PWMB,
29}
30
31#[derive(Copy, Clone)]
34pub struct DeadTimeCfg {
35 cfg_reg: u32,
36}
37
38#[allow(clippy::unusual_byte_groupings)]
39impl DeadTimeCfg {
40 const S0: u32 = 0b01_0000_0000_0000_0000;
46 const S1: u32 = 0b00_1000_0000_0000_0000;
48 const S2: u32 = 0b00_0010_0000_0000_0000;
50 const S3: u32 = 0b00_0100_0000_0000_0000;
52 const S4: u32 = 0b00_0000_1000_0000_0000;
54 const S5: u32 = 0b00_0001_0000_0000_0000;
56 const S6: u32 = 0b00_0000_0010_0000_0000;
58 const S7: u32 = 0b00_0000_0100_0000_0000;
60 const _S8: u32 = 0b00_0000_0001_0000_0000;
62 const CLK_SEL: u32 = 0b10_0000_0000_0000_0000;
64
65 pub const fn new_bypass() -> DeadTimeCfg {
74 DeadTimeCfg {
75 cfg_reg: Self::S0 | Self::S1,
76 }
77 }
78
79 pub const fn new_ahc() -> DeadTimeCfg {
86 DeadTimeCfg { cfg_reg: Self::S3 }
87 }
88 #[must_use]
91 const fn set_flag(mut self, flag: u32, val: bool) -> Self {
92 if val {
93 self.cfg_reg |= flag;
94 } else {
95 self.cfg_reg &= !flag;
96 }
97 self
98 }
99
100 #[must_use]
103 pub const fn invert_output(self, fed: bool, red: bool) -> Self {
104 self.set_flag(Self::S3, fed).set_flag(Self::S2, red)
105 }
106
107 #[must_use]
112 pub const fn set_output_swap(self, stream: PWMStream, swap: bool) -> Self {
113 self.set_flag(
114 match stream {
115 PWMStream::PWMA => Self::S6,
116 PWMStream::PWMB => Self::S7,
117 },
118 swap,
119 )
120 }
121
122 #[must_use]
125 pub const fn set_bypass(self, stream: PWMStream, enable: bool) -> Self {
126 self.set_flag(
127 match stream {
128 PWMStream::PWMA => Self::S1,
129 PWMStream::PWMB => Self::S0,
130 },
131 enable,
132 )
133 }
134
135 #[must_use]
137 pub const fn select_clock(self, pwm_clock: bool) -> Self {
138 self.set_flag(Self::CLK_SEL, pwm_clock)
139 }
140
141 #[must_use]
143 pub const fn select_input(self, fed: PWMStream, red: PWMStream) -> Self {
144 self.set_flag(
145 Self::S5,
146 match fed {
147 PWMStream::PWMA => false,
148 PWMStream::PWMB => true,
149 },
150 )
151 .set_flag(
152 Self::S4,
153 match red {
154 PWMStream::PWMA => false,
155 PWMStream::PWMB => true,
156 },
157 )
158 }
159}
160
161pub struct Operator<'d, const OP: u8, PWM> {
172 phantom: PhantomData<&'d PWM>,
173 _guard: PeripheralGuard,
174}
175
176impl<'d, const OP: u8, PWM: PwmPeripheral> Operator<'d, OP, PWM> {
177 pub(super) fn new() -> Self {
178 let guard = PeripheralGuard::new(PWM::peripheral());
179
180 Operator {
187 phantom: PhantomData,
188 _guard: guard,
189 }
190 }
191
192 pub fn set_timer<const TIM: u8>(&mut self, timer: &Timer<TIM, PWM>) {
197 let _ = timer;
198 let block = unsafe { &*PWM::block() };
201 block.operator_timersel().modify(|_, w| match OP {
202 0 => unsafe { w.operator0_timersel().bits(TIM) },
203 1 => unsafe { w.operator1_timersel().bits(TIM) },
204 2 => unsafe { w.operator2_timersel().bits(TIM) },
205 _ => {
206 unreachable!()
207 }
208 });
209 }
210
211 pub fn with_pin_a(
213 self,
214 pin: impl PeripheralOutput<'d>,
215 config: PwmPinConfig<true>,
216 ) -> PwmPin<'d, PWM, OP, true> {
217 PwmPin::new(pin, config)
218 }
219
220 pub fn with_pin_b(
222 self,
223 pin: impl PeripheralOutput<'d>,
224 config: PwmPinConfig<false>,
225 ) -> PwmPin<'d, PWM, OP, false> {
226 PwmPin::new(pin, config)
227 }
228
229 pub fn with_pins(
231 self,
232 pin_a: impl PeripheralOutput<'d>,
233 config_a: PwmPinConfig<true>,
234 pin_b: impl PeripheralOutput<'d>,
235 config_b: PwmPinConfig<false>,
236 ) -> (PwmPin<'d, PWM, OP, true>, PwmPin<'d, PWM, OP, false>) {
237 (PwmPin::new(pin_a, config_a), PwmPin::new(pin_b, config_b))
238 }
239
240 pub fn with_linked_pins(
245 self,
246 pin_a: impl PeripheralOutput<'d>,
247 config_a: PwmPinConfig<true>,
248 pin_b: impl PeripheralOutput<'d>,
249 config_b: PwmPinConfig<false>,
250 config_dt: DeadTimeCfg,
251 ) -> LinkedPins<'d, PWM, OP> {
252 LinkedPins::new(pin_a, config_a, pin_b, config_b, config_dt)
253 }
254}
255
256pub struct PwmPinConfig<const IS_A: bool> {
259 actions: PwmActions<IS_A>,
260 update_method: PwmUpdateMethod,
261}
262
263impl<const IS_A: bool> PwmPinConfig<IS_A> {
264 pub const UP_ACTIVE_HIGH: Self =
267 Self::new(PwmActions::UP_ACTIVE_HIGH, PwmUpdateMethod::SYNC_ON_ZERO);
268 pub const UP_DOWN_ACTIVE_HIGH: Self = Self::new(
271 PwmActions::UP_DOWN_ACTIVE_HIGH,
272 PwmUpdateMethod::SYNC_ON_ZERO,
273 );
274 pub const EMPTY: Self = Self::new(PwmActions::empty(), PwmUpdateMethod::empty());
277
278 pub const fn new(actions: PwmActions<IS_A>, update_method: PwmUpdateMethod) -> Self {
280 PwmPinConfig {
281 actions,
282 update_method,
283 }
284 }
285}
286
287pub struct PwmPin<'d, PWM, const OP: u8, const IS_A: bool> {
289 pin: OutputSignal<'d>,
290 phantom: PhantomData<PWM>,
291 _guard: PeripheralGuard,
292}
293
294impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> PwmPin<'d, PWM, OP, IS_A> {
295 fn new(pin: impl PeripheralOutput<'d>, config: PwmPinConfig<IS_A>) -> Self {
296 let pin = pin.into();
297
298 let guard = PeripheralGuard::new(PWM::peripheral());
299
300 let mut pin = PwmPin {
301 pin,
302 phantom: PhantomData,
303 _guard: guard,
304 };
305 pin.set_actions(config.actions);
306 pin.set_update_method(config.update_method);
307
308 PWM::output_signal::<OP, IS_A>().connect_to(&pin.pin);
309 pin.pin.set_output_enable(true);
310
311 pin
312 }
313
314 pub fn set_actions(&mut self, value: PwmActions<IS_A>) {
316 let ch = unsafe { Self::ch() };
319 let bits = value.0;
320
321 ch.r#gen((!IS_A) as usize)
324 .write(|w| unsafe { w.bits(bits) });
325 }
326
327 pub fn set_update_method(&mut self, update_method: PwmUpdateMethod) {
329 let ch = unsafe { Self::ch() };
332 let bits = update_method.0;
333
334 #[cfg(esp32s3)]
335 let cfg = ch.cmpr_cfg();
336 #[cfg(any(esp32, esp32c6, esp32h2))]
337 let cfg = ch.gen_stmp_cfg();
338
339 cfg.modify(|_, w| unsafe {
340 if IS_A {
341 w.a_upmethod().bits(bits)
342 } else {
343 w.b_upmethod().bits(bits)
344 }
345 });
346 }
347
348 pub fn set_timestamp(&mut self, value: u16) {
352 let ch = unsafe { Self::ch() };
355
356 #[cfg(esp32s3)]
357 if IS_A {
358 ch.cmpr_value0().write(|w| unsafe { w.a().bits(value) });
359 } else {
360 ch.cmpr_value1().write(|w| unsafe { w.b().bits(value) });
361 }
362
363 #[cfg(any(esp32, esp32c6, esp32h2))]
364 if IS_A {
365 ch.gen_tstmp_a().write(|w| unsafe { w.a().bits(value) });
366 } else {
367 ch.gen_tstmp_b().write(|w| unsafe { w.b().bits(value) });
368 }
369 }
370
371 pub fn timestamp(&self) -> u16 {
375 let ch = unsafe { Self::ch() };
378
379 #[cfg(esp32s3)]
380 if IS_A {
381 ch.cmpr_value0().read().a().bits()
382 } else {
383 ch.cmpr_value1().read().b().bits()
384 }
385
386 #[cfg(any(esp32, esp32c6, esp32h2))]
387 if IS_A {
388 ch.gen_tstmp_a().read().a().bits()
389 } else {
390 ch.gen_tstmp_b().read().b().bits()
391 }
392 }
393
394 pub fn period(&self) -> u16 {
396 let block = unsafe { &*PWM::block() };
399
400 let tim_select = block.operator_timersel().read();
401 let tim = match OP {
402 0 => tim_select.operator0_timersel().bits(),
403 1 => tim_select.operator1_timersel().bits(),
404 2 => tim_select.operator2_timersel().bits(),
405 _ => {
406 unreachable!()
407 }
408 };
409
410 block.timer(tim as usize).cfg0().read().period().bits()
414 }
415
416 unsafe fn ch() -> &'static pac::mcpwm0::CH {
417 let block = unsafe { &*PWM::block() };
418 block.ch(OP as usize)
419 }
420}
421
422impl<PWM: PwmPeripheral, const OP: u8, const IS_A: bool> embedded_hal::pwm::ErrorType
424 for PwmPin<'_, PWM, OP, IS_A>
425{
426 type Error = core::convert::Infallible;
427}
428
429impl<PWM: PwmPeripheral, const OP: u8, const IS_A: bool> embedded_hal::pwm::SetDutyCycle
431 for PwmPin<'_, PWM, OP, IS_A>
432{
433 fn max_duty_cycle(&self) -> u16 {
435 self.period()
436 }
437
438 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), core::convert::Infallible> {
440 self.set_timestamp(duty);
441 Ok(())
442 }
443}
444
445#[doc = crate::before_snippet!()]
454#[cfg_attr(
462 esp32h2,
463 doc = "let clock_cfg = PeripheralClockConfig::with_frequency(Rate::from_mhz(40))?;"
464)]
465#[cfg_attr(
466 not(esp32h2),
467 doc = "let clock_cfg = PeripheralClockConfig::with_frequency(Rate::from_mhz(32))?;"
468)]
469pub struct LinkedPins<'d, PWM, const OP: u8> {
491 pin_a: PwmPin<'d, PWM, OP, true>,
492 pin_b: PwmPin<'d, PWM, OP, false>,
493}
494
495impl<'d, PWM: PwmPeripheral, const OP: u8> LinkedPins<'d, PWM, OP> {
496 fn new(
497 pin_a: impl PeripheralOutput<'d>,
498 config_a: PwmPinConfig<true>,
499 pin_b: impl PeripheralOutput<'d>,
500 config_b: PwmPinConfig<false>,
501 config_dt: DeadTimeCfg,
502 ) -> Self {
503 #[cfg(esp32s3)]
505 let dt_cfg = unsafe { Self::ch() }.db_cfg();
506 #[cfg(not(esp32s3))]
507 let dt_cfg = unsafe { Self::ch() }.dt_cfg();
508 dt_cfg.write(|w| unsafe { w.bits(config_dt.cfg_reg) });
509
510 let pin_a = PwmPin::new(pin_a, config_a);
511 let pin_b = PwmPin::new(pin_b, config_b);
512
513 LinkedPins { pin_a, pin_b }
514 }
515
516 pub fn set_actions_a(&mut self, value: PwmActions<true>) {
518 self.pin_a.set_actions(value)
519 }
520 pub fn set_actions_b(&mut self, value: PwmActions<false>) {
522 self.pin_b.set_actions(value)
523 }
524
525 pub fn set_update_method_a(&mut self, update_method: PwmUpdateMethod) {
527 self.pin_a.set_update_method(update_method)
528 }
529 pub fn set_update_method_b(&mut self, update_method: PwmUpdateMethod) {
531 self.pin_b.set_update_method(update_method)
532 }
533
534 pub fn set_timestamp_a(&mut self, value: u16) {
538 self.pin_a.set_timestamp(value)
539 }
540 pub fn set_timestamp_b(&mut self, value: u16) {
544 self.pin_a.set_timestamp(value)
545 }
546
547 pub fn set_deadtime_cfg(&mut self, config: DeadTimeCfg) {
549 #[cfg(esp32s3)]
550 let dt_cfg = unsafe { Self::ch() }.db_cfg();
551 #[cfg(not(esp32s3))]
552 let dt_cfg = unsafe { Self::ch() }.dt_cfg();
553 dt_cfg.write(|w| unsafe { w.bits(config.cfg_reg) });
554 }
555
556 pub fn set_rising_edge_deadtime(&mut self, dead_time: u16) {
558 #[cfg(esp32s3)]
559 let dt_red = unsafe { Self::ch() }.db_red_cfg();
560 #[cfg(not(esp32s3))]
561 let dt_red = unsafe { Self::ch() }.dt_red_cfg();
562 dt_red.write(|w| unsafe { w.red().bits(dead_time) });
563 }
564 pub fn set_falling_edge_deadtime(&mut self, dead_time: u16) {
566 #[cfg(esp32s3)]
567 let dt_fed = unsafe { Self::ch() }.db_fed_cfg();
568 #[cfg(not(esp32s3))]
569 let dt_fed = unsafe { Self::ch() }.dt_fed_cfg();
570 dt_fed.write(|w| unsafe { w.fed().bits(dead_time) });
571 }
572
573 unsafe fn ch() -> &'static pac::mcpwm0::CH {
574 let block = unsafe { &*PWM::block() };
575 block.ch(OP as usize)
576 }
577}
578
579#[non_exhaustive]
581#[repr(u32)]
582pub enum UpdateAction {
583 SetLow = 1,
585 SetHigh = 2,
587 Toggle = 3,
590}
591
592pub struct PwmActions<const IS_A: bool>(u32);
599
600impl<const IS_A: bool> PwmActions<IS_A> {
601 pub const UP_ACTIVE_HIGH: Self = Self::empty()
606 .on_up_counting_timer_equals_zero(UpdateAction::SetHigh)
607 .on_up_counting_timer_equals_timestamp(UpdateAction::SetLow);
608
609 pub const UP_DOWN_ACTIVE_HIGH: Self = Self::empty()
614 .on_down_counting_timer_equals_timestamp(UpdateAction::SetHigh)
615 .on_up_counting_timer_equals_timestamp(UpdateAction::SetLow);
616
617 pub const fn empty() -> Self {
619 PwmActions(0)
620 }
621
622 pub const fn on_up_counting_timer_equals_zero(self, action: UpdateAction) -> Self {
624 self.with_value_at_offset(action as u32, 0)
625 }
626
627 pub const fn on_up_counting_timer_equals_period(self, action: UpdateAction) -> Self {
629 self.with_value_at_offset(action as u32, 2)
630 }
631
632 pub const fn on_up_counting_timer_equals_timestamp(self, action: UpdateAction) -> Self {
634 match IS_A {
635 true => self.with_value_at_offset(action as u32, 4),
636 false => self.with_value_at_offset(action as u32, 6),
637 }
638 }
639
640 pub const fn on_up_counting_timer_equals_ch_timestamp<const CH_A: bool>(
643 self,
644 action: UpdateAction,
645 ) -> Self {
646 match CH_A {
647 true => self.with_value_at_offset(action as u32, 4),
648 false => self.with_value_at_offset(action as u32, 6),
649 }
650 }
651
652 pub const fn on_down_counting_timer_equals_zero(self, action: UpdateAction) -> Self {
654 self.with_value_at_offset(action as u32, 12)
655 }
656
657 pub const fn on_down_counting_timer_equals_period(self, action: UpdateAction) -> Self {
659 self.with_value_at_offset(action as u32, 14)
660 }
661
662 pub const fn on_down_counting_timer_equals_timestamp(self, action: UpdateAction) -> Self {
664 match IS_A {
665 true => self.with_value_at_offset(action as u32, 16),
666 false => self.with_value_at_offset(action as u32, 18),
667 }
668 }
669
670 pub const fn on_down_counting_timer_equals_ch_timestamp<const CH_A: bool>(
673 self,
674 action: UpdateAction,
675 ) -> Self {
676 match CH_A {
677 true => self.with_value_at_offset(action as u32, 16),
678 false => self.with_value_at_offset(action as u32, 18),
679 }
680 }
681
682 const fn with_value_at_offset(self, value: u32, offset: u32) -> Self {
683 let mask = !(0b11 << offset);
684 let value = (self.0 & mask) | (value << offset);
685 PwmActions(value)
686 }
687}
688
689pub struct PwmUpdateMethod(u8);
693
694impl PwmUpdateMethod {
695 pub const SYNC_IMMEDIATLY: Self = Self::empty();
697 pub const SYNC_ON_ZERO: Self = Self::empty().sync_on_timer_equals_zero();
699 pub const SYNC_ON_PERIOD: Self = Self::empty().sync_on_timer_equals_period();
701
702 pub const fn empty() -> Self {
705 PwmUpdateMethod(0)
706 }
707
708 pub const fn sync_on_timer_equals_zero(mut self) -> Self {
710 self.0 |= 0b0001;
711 self
712 }
713
714 pub const fn sync_on_timer_equals_period(mut self) -> Self {
716 self.0 |= 0b0010;
717 self
718 }
719}