1use super::timer::{TimerIFace, TimerSpeed};
13use crate::{
14 gpio::{
15 interconnect::{OutputConnection, PeripheralOutput},
16 OutputSignal,
17 },
18 pac::ledc::RegisterBlock,
19 peripheral::{Peripheral, PeripheralRef},
20 peripherals::LEDC,
21};
22
23#[derive(Debug, Clone, Copy, PartialEq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum FadeError {
27 StartDuty,
29 EndDuty,
31 DutyRange,
33 Duration,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum Error {
41 Duty,
43 Timer,
45 Channel,
47 Fade(FadeError),
49}
50
51#[derive(PartialEq, Eq, Copy, Clone, Debug)]
53#[cfg_attr(feature = "defmt", derive(defmt::Format))]
54pub enum Number {
55 Channel0 = 0,
57 Channel1 = 1,
59 Channel2 = 2,
61 Channel3 = 3,
63 Channel4 = 4,
65 Channel5 = 5,
67 #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
68 Channel6 = 6,
70 #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
71 Channel7 = 7,
73}
74
75pub mod config {
77 use crate::ledc::timer::{TimerIFace, TimerSpeed};
78
79 #[derive(Debug, Clone, Copy, PartialEq)]
80 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
81 pub enum PinConfig {
83 PushPull,
85 OpenDrain,
87 }
88
89 #[derive(Copy, Clone)]
91 pub struct Config<'a, S: TimerSpeed> {
92 pub timer: &'a dyn TimerIFace<S>,
94 pub duty_pct: u8,
96 pub pin_config: PinConfig,
98 }
99}
100
101pub trait ChannelIFace<'a, S: TimerSpeed + 'a>
103where
104 Channel<'a, S>: ChannelHW,
105{
106 fn configure(&mut self, config: config::Config<'a, S>) -> Result<(), Error>;
108
109 fn set_duty(&self, duty_pct: u8) -> Result<(), Error>;
111
112 fn start_duty_fade(
114 &self,
115 start_duty_pct: u8,
116 end_duty_pct: u8,
117 duration_ms: u16,
118 ) -> Result<(), Error>;
119
120 fn is_duty_fade_running(&self) -> bool;
122}
123
124pub trait ChannelHW {
126 fn configure_hw(&mut self) -> Result<(), Error>;
129 fn configure_hw_with_pin_config(&mut self, cfg: config::PinConfig) -> Result<(), Error>;
132
133 fn set_duty_hw(&self, duty: u32);
135
136 fn start_duty_fade_hw(
138 &self,
139 start_duty: u32,
140 duty_inc: bool,
141 duty_steps: u16,
142 cycles_per_step: u16,
143 duty_per_cycle: u16,
144 );
145
146 fn is_duty_fade_running_hw(&self) -> bool;
148}
149
150pub struct Channel<'a, S: TimerSpeed> {
152 ledc: &'a RegisterBlock,
153 timer: Option<&'a dyn TimerIFace<S>>,
154 number: Number,
155 output_pin: PeripheralRef<'a, OutputConnection>,
156}
157
158impl<'a, S: TimerSpeed> Channel<'a, S> {
159 pub fn new(
161 number: Number,
162 output_pin: impl Peripheral<P = impl PeripheralOutput> + 'a,
163 ) -> Self {
164 crate::into_mapped_ref!(output_pin);
165 let ledc = LEDC::regs();
166 Channel {
167 ledc,
168 timer: None,
169 number,
170 output_pin,
171 }
172 }
173}
174
175impl<'a, S: TimerSpeed> ChannelIFace<'a, S> for Channel<'a, S>
176where
177 Channel<'a, S>: ChannelHW,
178{
179 fn configure(&mut self, config: config::Config<'a, S>) -> Result<(), Error> {
181 self.timer = Some(config.timer);
182
183 self.set_duty(config.duty_pct)?;
184 self.configure_hw_with_pin_config(config.pin_config)?;
185
186 Ok(())
187 }
188
189 fn set_duty(&self, duty_pct: u8) -> Result<(), Error> {
191 let duty_exp;
192 if let Some(timer) = self.timer {
193 if let Some(timer_duty) = timer.duty() {
194 duty_exp = timer_duty as u32;
195 } else {
196 return Err(Error::Timer);
197 }
198 } else {
199 return Err(Error::Channel);
200 }
201
202 let duty_range = 2u32.pow(duty_exp);
203 let duty_value = (duty_range * duty_pct as u32) / 100;
204
205 if duty_pct > 100u8 {
206 return Err(Error::Duty);
208 }
209
210 self.set_duty_hw(duty_value);
211
212 Ok(())
213 }
214
215 fn start_duty_fade(
228 &self,
229 start_duty_pct: u8,
230 end_duty_pct: u8,
231 duration_ms: u16,
232 ) -> Result<(), Error> {
233 let duty_exp;
234 let frequency;
235 if start_duty_pct > 100u8 {
236 return Err(Error::Fade(FadeError::StartDuty));
237 }
238 if end_duty_pct > 100u8 {
239 return Err(Error::Fade(FadeError::EndDuty));
240 }
241 if let Some(timer) = self.timer {
242 if let Some(timer_duty) = timer.duty() {
243 if timer.frequency() > 0 {
244 duty_exp = timer_duty as u32;
245 frequency = timer.frequency();
246 } else {
247 return Err(Error::Timer);
248 }
249 } else {
250 return Err(Error::Timer);
251 }
252 } else {
253 return Err(Error::Channel);
254 }
255
256 let duty_range = (1u32 << duty_exp) - 1;
257 let start_duty_value = (duty_range * start_duty_pct as u32) / 100;
258 let end_duty_value = (duty_range * end_duty_pct as u32) / 100;
259
260 let pwm_cycles = (duration_ms as u32) * frequency / 1000;
263
264 let abs_duty_diff = end_duty_value.abs_diff(start_duty_value);
265 let duty_steps: u32 = u16::try_from(abs_duty_diff).unwrap_or(65535).into();
266 let cycles_per_step: u16 = (pwm_cycles / duty_steps)
271 .try_into()
272 .map_err(|_| Error::Fade(FadeError::Duration))
273 .and_then(|res| {
274 if res > 1023 {
275 Err(Error::Fade(FadeError::Duration))
276 } else {
277 Ok(res)
278 }
279 })?;
280 let duty_per_cycle: u16 = (abs_duty_diff / duty_steps)
285 .try_into()
286 .map_err(|_| Error::Fade(FadeError::DutyRange))?;
287
288 self.start_duty_fade_hw(
289 start_duty_value,
290 end_duty_value > start_duty_value,
291 duty_steps.try_into().unwrap(),
292 cycles_per_step,
293 duty_per_cycle,
294 );
295
296 Ok(())
297 }
298
299 fn is_duty_fade_running(&self) -> bool {
300 self.is_duty_fade_running_hw()
301 }
302}
303
304mod ehal1 {
305 use embedded_hal::pwm::{self, ErrorKind, ErrorType, SetDutyCycle};
306
307 use super::{Channel, ChannelHW, Error};
308 use crate::ledc::timer::TimerSpeed;
309
310 impl pwm::Error for Error {
311 fn kind(&self) -> pwm::ErrorKind {
312 ErrorKind::Other
313 }
314 }
315
316 impl<S: TimerSpeed> ErrorType for Channel<'_, S> {
317 type Error = Error;
318 }
319
320 impl<'a, S: TimerSpeed> SetDutyCycle for Channel<'a, S>
321 where
322 Channel<'a, S>: ChannelHW,
323 {
324 fn max_duty_cycle(&self) -> u16 {
325 let duty_exp;
326
327 if let Some(timer_duty) = self.timer.and_then(|timer| timer.duty()) {
328 duty_exp = timer_duty as u32;
329 } else {
330 return 0;
331 }
332
333 let duty_range = 2u32.pow(duty_exp);
334
335 duty_range as u16
336 }
337
338 fn set_duty_cycle(&mut self, mut duty: u16) -> Result<(), Self::Error> {
339 let max = self.max_duty_cycle();
340 duty = if duty > max { max } else { duty };
341 self.set_duty_hw(duty.into());
342 Ok(())
343 }
344 }
345}
346
347impl<S: crate::ledc::timer::TimerSpeed> Channel<'_, S> {
348 #[cfg(esp32)]
349 fn set_channel(&mut self, timer_number: u8) {
350 if S::IS_HS {
351 let ch = self.ledc.hsch(self.number as usize);
352 ch.hpoint().write(|w| unsafe { w.hpoint().bits(0x0) });
353 ch.conf0()
354 .modify(|_, w| unsafe { w.sig_out_en().set_bit().timer_sel().bits(timer_number) });
355 } else {
356 let ch = self.ledc.lsch(self.number as usize);
357 ch.hpoint().write(|w| unsafe { w.hpoint().bits(0x0) });
358 ch.conf0()
359 .modify(|_, w| unsafe { w.sig_out_en().set_bit().timer_sel().bits(timer_number) });
360 }
361 self.start_duty_without_fading();
362 }
363 #[cfg(not(esp32))]
364 fn set_channel(&mut self, timer_number: u8) {
365 {
366 let ch = self.ledc.ch(self.number as usize);
367 ch.hpoint().write(|w| unsafe { w.hpoint().bits(0x0) });
368 ch.conf0().modify(|_, w| {
369 w.sig_out_en().set_bit();
370 unsafe { w.timer_sel().bits(timer_number) }
371 });
372 }
373
374 #[cfg(any(esp32h2, esp32c6))]
376 self.ledc
377 .ch_gamma_wr_addr(self.number as usize)
378 .write(|w| unsafe { w.bits(0) });
379
380 self.start_duty_without_fading();
381 }
382
383 #[cfg(esp32)]
384 fn start_duty_without_fading(&self) {
385 if S::IS_HS {
386 self.ledc
387 .hsch(self.number as usize)
388 .conf1()
389 .write(|w| unsafe {
390 w.duty_start().set_bit();
391 w.duty_inc().set_bit();
392 w.duty_num().bits(0x1);
393 w.duty_cycle().bits(0x1);
394 w.duty_scale().bits(0x0)
395 });
396 } else {
397 self.ledc
398 .lsch(self.number as usize)
399 .conf1()
400 .write(|w| unsafe {
401 w.duty_start().set_bit();
402 w.duty_inc().set_bit();
403 w.duty_num().bits(0x1);
404 w.duty_cycle().bits(0x1);
405 w.duty_scale().bits(0x0)
406 });
407 }
408 }
409 #[cfg(any(esp32c6, esp32h2))]
410 fn start_duty_without_fading(&self) {
411 let cnum = self.number as usize;
412 self.ledc
413 .ch(cnum)
414 .conf1()
415 .write(|w| w.duty_start().set_bit());
416 self.ledc.ch_gamma_wr(cnum).write(|w| {
417 w.ch_gamma_duty_inc().set_bit();
418 unsafe {
419 w.ch_gamma_duty_num().bits(0x1);
420 w.ch_gamma_duty_cycle().bits(0x1);
421 w.ch_gamma_scale().bits(0x0)
422 }
423 });
424 }
425 #[cfg(not(any(esp32, esp32c6, esp32h2)))]
426 fn start_duty_without_fading(&self) {
427 self.ledc.ch(self.number as usize).conf1().write(|w| {
428 w.duty_start().set_bit();
429 w.duty_inc().set_bit();
430 unsafe {
431 w.duty_num().bits(0x1);
432 w.duty_cycle().bits(0x1);
433 w.duty_scale().bits(0x0)
434 }
435 });
436 }
437
438 #[cfg(esp32)]
439 fn start_duty_fade_inner(
440 &self,
441 duty_inc: bool,
442 duty_steps: u16,
443 cycles_per_step: u16,
444 duty_per_cycle: u16,
445 ) {
446 if S::IS_HS {
447 self.ledc
448 .hsch(self.number as usize)
449 .conf1()
450 .write(|w| unsafe {
451 w.duty_start()
452 .set_bit()
453 .duty_inc()
454 .variant(duty_inc)
455 .duty_num() .bits(duty_steps)
457 .duty_cycle() .bits(cycles_per_step)
459 .duty_scale()
460 .bits(duty_per_cycle)
461 });
462 } else {
463 self.ledc
464 .lsch(self.number as usize)
465 .conf1()
466 .write(|w| unsafe {
467 w.duty_start()
468 .set_bit()
469 .duty_inc()
470 .variant(duty_inc)
471 .duty_num() .bits(duty_steps)
473 .duty_cycle() .bits(cycles_per_step)
475 .duty_scale()
476 .bits(duty_per_cycle)
477 });
478 }
479 }
480
481 #[cfg(any(esp32c6, esp32h2))]
482 fn start_duty_fade_inner(
483 &self,
484 duty_inc: bool,
485 duty_steps: u16,
486 cycles_per_step: u16,
487 duty_per_cycle: u16,
488 ) {
489 let cnum = self.number as usize;
490 self.ledc
491 .ch(cnum)
492 .conf1()
493 .write(|w| w.duty_start().set_bit());
494 self.ledc.ch_gamma_wr(cnum).write(|w| unsafe {
495 w.ch_gamma_duty_inc()
496 .variant(duty_inc)
497 .ch_gamma_duty_num() .bits(duty_steps)
499 .ch_gamma_duty_cycle() .bits(cycles_per_step)
501 .ch_gamma_scale()
502 .bits(duty_per_cycle)
503 });
504 self.ledc
505 .ch_gamma_wr_addr(cnum)
506 .write(|w| unsafe { w.ch_gamma_wr_addr().bits(0) });
507 self.ledc
508 .ch_gamma_conf(cnum)
509 .write(|w| unsafe { w.ch_gamma_entry_num().bits(0x1) });
510 }
511
512 #[cfg(not(any(esp32, esp32c6, esp32h2)))]
513 fn start_duty_fade_inner(
514 &self,
515 duty_inc: bool,
516 duty_steps: u16,
517 cycles_per_step: u16,
518 duty_per_cycle: u16,
519 ) {
520 self.ledc
521 .ch(self.number as usize)
522 .conf1()
523 .write(|w| unsafe {
524 w.duty_start().set_bit();
525 w.duty_inc().variant(duty_inc);
526 w.duty_num().bits(duty_steps);
528 w.duty_cycle().bits(cycles_per_step);
530 w.duty_scale().bits(duty_per_cycle)
531 });
532 }
533
534 #[cfg(esp32)]
535 fn update_channel(&self) {
536 if !S::IS_HS {
537 self.ledc
538 .lsch(self.number as usize)
539 .conf0()
540 .modify(|_, w| w.para_up().set_bit());
541 }
542 }
543 #[cfg(not(esp32))]
544 fn update_channel(&self) {
545 self.ledc
546 .ch(self.number as usize)
547 .conf0()
548 .modify(|_, w| w.para_up().set_bit());
549 }
550}
551
552impl<S> ChannelHW for Channel<'_, S>
553where
554 S: crate::ledc::timer::TimerSpeed,
555{
556 fn configure_hw(&mut self) -> Result<(), Error> {
558 self.configure_hw_with_pin_config(config::PinConfig::PushPull)
559 }
560 fn configure_hw_with_pin_config(&mut self, cfg: config::PinConfig) -> Result<(), Error> {
561 if let Some(timer) = self.timer {
562 if !timer.is_configured() {
563 return Err(Error::Timer);
564 }
565
566 match cfg {
567 config::PinConfig::PushPull => self.output_pin.set_to_push_pull_output(),
568 config::PinConfig::OpenDrain => self.output_pin.set_to_open_drain_output(),
569 };
570
571 let timer_number = timer.number() as u8;
572
573 self.set_channel(timer_number);
574 self.update_channel();
575
576 #[cfg(esp32)]
577 let signal = if S::IS_HS {
578 #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
579 match self.number {
580 Number::Channel0 => OutputSignal::LEDC_HS_SIG0,
581 Number::Channel1 => OutputSignal::LEDC_HS_SIG1,
582 Number::Channel2 => OutputSignal::LEDC_HS_SIG2,
583 Number::Channel3 => OutputSignal::LEDC_HS_SIG3,
584 Number::Channel4 => OutputSignal::LEDC_HS_SIG4,
585 Number::Channel5 => OutputSignal::LEDC_HS_SIG5,
586 Number::Channel6 => OutputSignal::LEDC_HS_SIG6,
587 Number::Channel7 => OutputSignal::LEDC_HS_SIG7,
588 }
589 } else {
590 match self.number {
591 Number::Channel0 => OutputSignal::LEDC_LS_SIG0,
592 Number::Channel1 => OutputSignal::LEDC_LS_SIG1,
593 Number::Channel2 => OutputSignal::LEDC_LS_SIG2,
594 Number::Channel3 => OutputSignal::LEDC_LS_SIG3,
595 Number::Channel4 => OutputSignal::LEDC_LS_SIG4,
596 Number::Channel5 => OutputSignal::LEDC_LS_SIG5,
597 #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
598 Number::Channel6 => OutputSignal::LEDC_LS_SIG6,
599 #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
600 Number::Channel7 => OutputSignal::LEDC_LS_SIG7,
601 }
602 };
603 #[cfg(not(esp32))]
604 let signal = match self.number {
605 Number::Channel0 => OutputSignal::LEDC_LS_SIG0,
606 Number::Channel1 => OutputSignal::LEDC_LS_SIG1,
607 Number::Channel2 => OutputSignal::LEDC_LS_SIG2,
608 Number::Channel3 => OutputSignal::LEDC_LS_SIG3,
609 Number::Channel4 => OutputSignal::LEDC_LS_SIG4,
610 Number::Channel5 => OutputSignal::LEDC_LS_SIG5,
611 #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
612 Number::Channel6 => OutputSignal::LEDC_LS_SIG6,
613 #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
614 Number::Channel7 => OutputSignal::LEDC_LS_SIG7,
615 };
616
617 signal.connect_to(&mut self.output_pin);
618 } else {
619 return Err(Error::Timer);
620 }
621
622 Ok(())
623 }
624
625 #[cfg(esp32)]
627 fn set_duty_hw(&self, duty: u32) {
628 if S::IS_HS {
629 self.ledc
630 .hsch(self.number as usize)
631 .duty()
632 .write(|w| unsafe { w.duty().bits(duty << 4) });
633 } else {
634 self.ledc
635 .lsch(self.number as usize)
636 .duty()
637 .write(|w| unsafe { w.duty().bits(duty << 4) });
638 }
639 self.start_duty_without_fading();
640 self.update_channel();
641 }
642
643 #[cfg(not(esp32))]
645 fn set_duty_hw(&self, duty: u32) {
646 self.ledc
647 .ch(self.number as usize)
648 .duty()
649 .write(|w| unsafe { w.duty().bits(duty << 4) });
650 self.start_duty_without_fading();
651 self.update_channel();
652 }
653
654 #[cfg(esp32)]
656 fn start_duty_fade_hw(
657 &self,
658 start_duty: u32,
659 duty_inc: bool,
660 duty_steps: u16,
661 cycles_per_step: u16,
662 duty_per_cycle: u16,
663 ) {
664 if S::IS_HS {
665 self.ledc
666 .hsch(self.number as usize)
667 .duty()
668 .write(|w| unsafe { w.duty().bits(start_duty << 4) });
669 self.ledc
670 .int_clr()
671 .write(|w| w.duty_chng_end_hsch(self.number as u8).clear_bit_by_one());
672 } else {
673 self.ledc
674 .lsch(self.number as usize)
675 .duty()
676 .write(|w| unsafe { w.duty().bits(start_duty << 4) });
677 self.ledc
678 .int_clr()
679 .write(|w| w.duty_chng_end_lsch(self.number as u8).clear_bit_by_one());
680 }
681 self.start_duty_fade_inner(duty_inc, duty_steps, cycles_per_step, duty_per_cycle);
682 self.update_channel();
683 }
684
685 #[cfg(not(esp32))]
687 fn start_duty_fade_hw(
688 &self,
689 start_duty: u32,
690 duty_inc: bool,
691 duty_steps: u16,
692 cycles_per_step: u16,
693 duty_per_cycle: u16,
694 ) {
695 self.ledc
696 .ch(self.number as usize)
697 .duty()
698 .write(|w| unsafe { w.duty().bits(start_duty << 4) });
699 self.ledc
700 .int_clr()
701 .write(|w| w.duty_chng_end_ch(self.number as u8).clear_bit_by_one());
702 self.start_duty_fade_inner(duty_inc, duty_steps, cycles_per_step, duty_per_cycle);
703 self.update_channel();
704 }
705
706 #[cfg(esp32)]
707 fn is_duty_fade_running_hw(&self) -> bool {
708 let reg = self.ledc.int_raw().read();
709 if S::IS_HS {
710 reg.duty_chng_end_hsch(self.number as u8).bit_is_clear()
711 } else {
712 reg.duty_chng_end_lsch(self.number as u8).bit_is_clear()
713 }
714 }
715
716 #[cfg(not(esp32))]
717 fn is_duty_fade_running_hw(&self) -> bool {
718 self.ledc
719 .int_raw()
720 .read()
721 .duty_chng_end_ch(self.number as u8)
722 .bit_is_clear()
723 }
724}