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}