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