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