Skip to main content

esp_idf_hal/
ledc.rs

1//! LED Control peripheral (which also creates PWM signals for other purposes)
2//!
3//! Interface to the [LED Control (LEDC)
4//! peripheral](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-reference/peripherals/ledc.html)
5//!
6//!
7//! # Examples
8//!
9//! Create a 25 kHz PWM signal with 75 % duty cycle on GPIO 1
10//! ```
11//! use esp_idf_hal::ledc::{config::TimerConfig, Channel, LedcDriver, LedcTimerDriver, Timer};
12//! use esp_idf_hal::peripherals::Peripherals;
13//! use esp_idf_hal::prelude::*;
14//!
15//! let peripherals = Peripherals::take().unwrap();
16//! let timer_driver = LedcTimerDriver::new(peripherals.ledc.timer0, &TimerConfig::default().frequency(25.kHz().into()))?;
17//! let mut driver = LedcDriver::new(peripherals.ledc.channel0, timer_driver, peripherals.pins.gpio1)?;
18//!
19//! let max_duty = driver.get_max_duty();
20//! driver.set_duty(max_duty * 3 / 4)?;
21//! ```
22//!
23//! See the `examples/` folder of this repository for more.
24
25use core::borrow::Borrow;
26use core::marker::PhantomData;
27use core::sync::atomic::{AtomicBool, Ordering};
28
29use esp_idf_sys::*;
30
31use crate::gpio::OutputPin;
32use crate::task::CriticalSection;
33use crate::units::*;
34
35pub use chip::*;
36
37type Duty = u32;
38type HPoint = Duty;
39
40const IDLE_LEVEL: u32 = 0;
41
42static FADE_FUNC_INSTALLED: AtomicBool = AtomicBool::new(false);
43static FADE_FUNC_INSTALLED_CS: CriticalSection = CriticalSection::new();
44
45crate::embedded_hal_error!(
46    PwmError,
47    embedded_hal::pwm::Error,
48    embedded_hal::pwm::ErrorKind
49);
50
51/// Types for configuring the LED Control peripheral
52pub mod config {
53    use super::*;
54
55    pub use chip::Resolution;
56
57    #[derive(Clone, Debug, Eq, PartialEq)]
58    pub struct TimerConfig {
59        pub frequency: Hertz,
60        pub resolution: Resolution,
61    }
62
63    impl TimerConfig {
64        pub const fn new() -> Self {
65            Self {
66                frequency: Hertz(1000),
67                resolution: Resolution::Bits8,
68            }
69        }
70
71        #[must_use]
72        pub fn frequency(mut self, f: Hertz) -> Self {
73            self.frequency = f;
74            self
75        }
76
77        #[must_use]
78        pub fn resolution(mut self, r: Resolution) -> Self {
79            self.resolution = r;
80            self
81        }
82    }
83
84    impl Default for TimerConfig {
85        fn default() -> Self {
86            Self::new()
87        }
88    }
89}
90
91/// LED Control timer driver
92pub struct LedcTimerDriver<'d, S>
93where
94    S: SpeedMode,
95{
96    max_duty: Duty,
97    timer: u8,
98    _speed: PhantomData<S>,
99    _p: PhantomData<&'d mut ()>,
100}
101
102impl<'d, S> LedcTimerDriver<'d, S>
103where
104    S: SpeedMode,
105{
106    pub fn new<T: LedcTimer<SpeedMode = S> + 'd>(
107        _timer: T,
108        config: &config::TimerConfig,
109    ) -> Result<Self, EspError> {
110        let timer_config = ledc_timer_config_t {
111            speed_mode: T::SpeedMode::SPEED_MODE,
112            timer_num: T::timer() as _,
113            #[cfg(esp_idf_version_major = "4")]
114            __bindgen_anon_1: ledc_timer_config_t__bindgen_ty_1 {
115                duty_resolution: config.resolution.timer_bits(),
116            },
117            #[cfg(not(esp_idf_version_major = "4"))]
118            duty_resolution: config.resolution.timer_bits(),
119            freq_hz: config.frequency.into(),
120            #[cfg(not(esp_idf_version_at_least_5_1_0))]
121            clk_cfg: ledc_clk_cfg_t_LEDC_AUTO_CLK,
122            #[cfg(esp_idf_version_at_least_5_1_0)]
123            clk_cfg: soc_periph_ledc_clk_src_legacy_t_LEDC_AUTO_CLK,
124            #[cfg(not(any(
125                esp_idf_version_major = "4",
126                all(esp_idf_version_major = "5", esp_idf_version_minor = "0"),
127                all(esp_idf_version_major = "5", esp_idf_version_minor = "1")
128            )))]
129            deconfigure: false,
130        };
131
132        // SAFETY: We own the instance and therefor are safe to configure it.
133        esp!(unsafe { ledc_timer_config(&timer_config) })?;
134
135        Ok(Self {
136            max_duty: config.resolution.max_duty(),
137            timer: T::timer() as _,
138            _speed: PhantomData,
139            _p: PhantomData,
140        })
141    }
142
143    /// Pauses the timer. Operation can be resumed with [`resume_timer()`].
144    pub fn pause(&mut self) -> Result<(), EspError> {
145        esp!(unsafe { ledc_timer_pause(S::SPEED_MODE, self.timer()) })?;
146        Ok(())
147    }
148
149    /// Resumes the operation of the previously paused timer
150    pub fn resume(&mut self) -> Result<(), EspError> {
151        esp!(unsafe { ledc_timer_resume(S::SPEED_MODE, self.timer()) })?;
152        Ok(())
153    }
154
155    /// Set the frequency of the timer.
156    pub fn set_frequency(&mut self, frequency: Hertz) -> Result<(), EspError> {
157        esp!(unsafe { ledc_set_freq(S::SPEED_MODE, self.timer(), frequency.into()) })?;
158        Ok(())
159    }
160
161    fn reset(&mut self) -> Result<(), EspError> {
162        esp!(unsafe { ledc_timer_rst(S::SPEED_MODE, self.timer()) })?;
163        Ok(())
164    }
165
166    pub fn timer(&self) -> ledc_timer_t {
167        self.timer as _
168    }
169}
170
171impl<S> Drop for LedcTimerDriver<'_, S>
172where
173    S: SpeedMode,
174{
175    fn drop(&mut self) {
176        self.reset().unwrap();
177    }
178}
179
180unsafe impl<S> Send for LedcTimerDriver<'_, S> where S: SpeedMode {}
181
182/// LED Control driver
183pub struct LedcDriver<'d> {
184    channel: u8,
185    timer: u8,
186    duty: Duty,
187    hpoint: HPoint,
188    speed_mode: ledc_mode_t,
189    max_duty: Duty,
190    _p: PhantomData<&'d mut ()>,
191}
192
193// TODO: Stop channel when the instance gets dropped. It seems that we can't
194// have both at the same time: a method for releasing its hardware resources
195// and implementing Drop.
196impl<'d> LedcDriver<'d> {
197    /// Creates a new LED Control driver
198    pub fn new<C, B>(
199        _channel: C,
200        timer_driver: B,
201        pin: impl OutputPin + 'd,
202    ) -> Result<Self, EspError>
203    where
204        C: LedcChannel + 'd,
205        B: Borrow<LedcTimerDriver<'d, C::SpeedMode>>,
206    {
207        if !FADE_FUNC_INSTALLED.load(Ordering::SeqCst) {
208            let _guard = FADE_FUNC_INSTALLED_CS.enter();
209
210            if !FADE_FUNC_INSTALLED.load(Ordering::SeqCst) {
211                // It looks like ledc_channel_config requires the face function to
212                // be installed. I don't see why this is nescessary yet but hey,
213                // let the Wookie win for now.
214                //
215                // TODO: Check whether it's worth to track its install status and
216                // remove it if no longer needed.
217                esp!(unsafe { ledc_fade_func_install(0) })?;
218
219                FADE_FUNC_INSTALLED.store(true, Ordering::SeqCst);
220            }
221        }
222
223        let mut driver = LedcDriver {
224            duty: 0,
225            hpoint: 0,
226            speed_mode: C::SpeedMode::SPEED_MODE,
227            max_duty: timer_driver.borrow().max_duty,
228            timer: timer_driver.borrow().timer() as _,
229            channel: C::channel() as _,
230            _p: PhantomData,
231        };
232
233        driver.config_with_pin(pin)?;
234
235        Ok(driver)
236    }
237
238    /// Applies LEDC configuration with a specific pin
239    /// Can be used to reconfigure the LEDC driver with a different pin
240    pub fn config_with_pin(&mut self, pin: impl OutputPin + 'd) -> Result<(), EspError> {
241        let channel_config = ledc_channel_config_t {
242            speed_mode: self.speed_mode,
243            channel: self.channel as u32,
244            timer_sel: self.timer as u32,
245            intr_type: ledc_intr_type_t_LEDC_INTR_DISABLE,
246            gpio_num: pin.pin() as _,
247            duty: self.duty,
248            hpoint: self.hpoint as _,
249            ..Default::default()
250        };
251
252        // SAFETY: As long as we have borrowed the timer, we are safe to use
253        // it.
254        esp!(unsafe { ledc_channel_config(&channel_config) })?;
255        Ok(())
256    }
257
258    pub fn get_duty(&self) -> Duty {
259        self.duty
260    }
261
262    pub fn get_hpoint(&self) -> HPoint {
263        self.hpoint
264    }
265
266    pub fn get_max_duty(&self) -> Duty {
267        self.max_duty
268    }
269
270    pub fn disable(&mut self) -> Result<(), EspError> {
271        self.update_duty(0, 0)?;
272        Ok(())
273    }
274
275    pub fn enable(&mut self) -> Result<(), EspError> {
276        self.update_duty(self.duty, self.hpoint)?;
277        Ok(())
278    }
279
280    pub fn set_duty(&mut self, duty: Duty) -> Result<(), EspError> {
281        self.set_duty_with_hpoint(duty, self.hpoint)
282    }
283
284    pub fn set_hpoint(&mut self, hpoint: HPoint) -> Result<(), EspError> {
285        self.set_duty_with_hpoint(self.duty, hpoint)
286    }
287
288    pub fn set_duty_with_hpoint(&mut self, duty: Duty, hpoint: HPoint) -> Result<(), EspError> {
289        // Clamp the actual duty cycle to the current maximum as done by other
290        // Pwm/PwmPin implementations.
291        let max_duty = self.get_max_duty();
292        let clamped_duty = duty.min(max_duty);
293        let clamped_hpoint = hpoint.min(max_duty);
294        self.duty = clamped_duty;
295        self.hpoint = clamped_hpoint;
296        self.update_duty(clamped_duty, clamped_hpoint)?;
297        Ok(())
298    }
299
300    fn stop(&mut self) -> Result<(), EspError> {
301        esp!(unsafe { ledc_stop(self.speed_mode, self.channel(), IDLE_LEVEL,) })?;
302        Ok(())
303    }
304
305    fn update_duty(&mut self, duty: Duty, hpoint: HPoint) -> Result<(), EspError> {
306        esp!(unsafe { ledc_set_duty_and_update(self.speed_mode, self.channel(), duty, hpoint) })?;
307        Ok(())
308    }
309
310    pub fn channel(&self) -> ledc_channel_t {
311        self.channel as _
312    }
313
314    pub fn timer(&self) -> ledc_timer_t {
315        self.timer as _
316    }
317
318    /// Fade the LED to a target duty cycle over a specified time
319    pub fn fade_with_time(
320        &mut self,
321        target_duty: u32,
322        fade_time_ms: i32,
323        wait: bool,
324    ) -> Result<(), EspError> {
325        let max_duty = self.get_max_duty();
326        if target_duty > max_duty {
327            return Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>());
328        }
329
330        let fade_mode = if wait {
331            ledc_fade_mode_t_LEDC_FADE_WAIT_DONE
332        } else {
333            ledc_fade_mode_t_LEDC_FADE_NO_WAIT
334        };
335
336        unsafe {
337            esp!(ledc_set_fade_with_time(
338                self.speed_mode,
339                self.channel(),
340                target_duty,
341                fade_time_ms
342            ))?;
343            esp!(ledc_fade_start(self.speed_mode, self.channel(), fade_mode))?;
344        }
345        Ok(())
346    }
347
348    /// Fade the LED to a target duty cycle using steps
349    pub fn fade_with_step(
350        &mut self,
351        target_duty: u32,
352        step_size: u32,
353        step_time_ms: u32,
354        wait: bool,
355    ) -> Result<(), EspError> {
356        let max_duty = self.get_max_duty();
357        if target_duty > max_duty {
358            return Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>());
359        }
360
361        let fade_mode = if wait {
362            ledc_fade_mode_t_LEDC_FADE_WAIT_DONE
363        } else {
364            ledc_fade_mode_t_LEDC_FADE_NO_WAIT
365        };
366
367        unsafe {
368            esp!(ledc_set_fade_with_step(
369                self.speed_mode,
370                self.channel(),
371                target_duty,
372                step_size,
373                step_time_ms,
374            ))?;
375
376            esp!(ledc_fade_start(self.speed_mode, self.channel(), fade_mode))?;
377        }
378        Ok(())
379    }
380
381    #[cfg(not(any(esp32, esp_idf_version_major = "4")))]
382    /// Stop LED fading before target duty cycle is reached
383    pub fn fade_stop(&mut self) -> Result<(), EspError> {
384        unsafe {
385            esp!(ledc_fade_stop(self.speed_mode, self.channel()))?;
386        }
387        Ok(())
388    }
389}
390
391impl Drop for LedcDriver<'_> {
392    fn drop(&mut self) {
393        self.stop().unwrap();
394    }
395}
396
397unsafe impl Send for LedcDriver<'_> {}
398
399impl embedded_hal::pwm::ErrorType for LedcDriver<'_> {
400    type Error = PwmError;
401}
402
403fn to_pwm_err(err: EspError) -> PwmError {
404    PwmError::other(err)
405}
406
407impl embedded_hal::pwm::SetDutyCycle for LedcDriver<'_> {
408    fn max_duty_cycle(&self) -> u16 {
409        let duty = self.get_max_duty();
410        let duty_cap: u16 = if duty > u16::MAX as u32 {
411            u16::MAX
412        } else {
413            duty as u16
414        };
415        duty_cap
416    }
417
418    fn set_duty_cycle(&mut self, duty: u16) -> Result<(), PwmError> {
419        self.set_duty(duty as u32).map_err(to_pwm_err)
420    }
421
422    fn set_duty_cycle_fully_on(&mut self) -> Result<(), PwmError> {
423        self.set_duty(self.get_max_duty()).map_err(to_pwm_err)
424    }
425
426    fn set_duty_cycle_fully_off(&mut self) -> Result<(), PwmError> {
427        self.set_duty(0).map_err(to_pwm_err)
428    }
429
430    fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), PwmError> {
431        let duty = num as u32 * self.max_duty_cycle() as u32 / denom as u32;
432        self.set_duty_cycle(duty as u16)
433    }
434
435    fn set_duty_cycle_percent(&mut self, percent: u8) -> Result<(), PwmError> {
436        self.set_duty_cycle_fraction(percent as u16, 100)
437    }
438}
439
440impl embedded_hal_0_2::PwmPin for LedcDriver<'_> {
441    type Duty = Duty;
442
443    fn disable(&mut self) {
444        if let Err(e) = self.disable() {
445            panic!("disabling PWM failed: {e}");
446        }
447    }
448
449    fn enable(&mut self) {
450        if let Err(e) = self.enable() {
451            panic!("enabling PWM failed: {e}");
452        }
453    }
454
455    fn get_duty(&self) -> Self::Duty {
456        self.get_duty()
457    }
458
459    fn get_max_duty(&self) -> Self::Duty {
460        self.get_max_duty()
461    }
462
463    fn set_duty(&mut self, duty: Duty) {
464        if let Err(e) = self.set_duty(duty) {
465            panic!("updating duty failed: {e}");
466        }
467    }
468}
469
470mod chip {
471    use esp_idf_sys::*;
472
473    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
474    pub enum Resolution {
475        Bits1,
476        Bits2,
477        Bits3,
478        Bits4,
479        Bits5,
480        Bits6,
481        Bits7,
482        Bits8,
483        Bits9,
484        Bits10,
485        Bits11,
486        Bits12,
487        Bits13,
488        Bits14,
489        #[cfg(esp32)]
490        Bits15,
491        #[cfg(esp32)]
492        Bits16,
493        #[cfg(esp32)]
494        Bits17,
495        #[cfg(esp32)]
496        Bits18,
497        #[cfg(esp32)]
498        Bits19,
499        #[cfg(esp32)]
500        Bits20,
501    }
502
503    impl Resolution {
504        pub const fn bits(&self) -> usize {
505            match self {
506                Resolution::Bits1 => 1,
507                Resolution::Bits2 => 2,
508                Resolution::Bits3 => 3,
509                Resolution::Bits4 => 4,
510                Resolution::Bits5 => 5,
511                Resolution::Bits6 => 6,
512                Resolution::Bits7 => 7,
513                Resolution::Bits8 => 8,
514                Resolution::Bits9 => 9,
515                Resolution::Bits10 => 10,
516                Resolution::Bits11 => 11,
517                Resolution::Bits12 => 12,
518                Resolution::Bits13 => 13,
519                Resolution::Bits14 => 14,
520                #[cfg(esp32)]
521                Resolution::Bits15 => 15,
522                #[cfg(esp32)]
523                Resolution::Bits16 => 16,
524                #[cfg(esp32)]
525                Resolution::Bits17 => 17,
526                #[cfg(esp32)]
527                Resolution::Bits18 => 18,
528                #[cfg(esp32)]
529                Resolution::Bits19 => 19,
530                #[cfg(esp32)]
531                Resolution::Bits20 => 20,
532            }
533        }
534
535        pub const fn max_duty(&self) -> u32 {
536            // when using the maximum resultion, the duty cycle must not exceed 2^N - 1 to avoid timer overflow
537            if cfg!(esp32) && self.bits() == 20 || cfg!(not(esp32)) && self.bits() == 14 {
538                (1 << self.bits()) - 1
539            } else {
540                1 << self.bits()
541            }
542        }
543
544        pub(crate) const fn timer_bits(&self) -> ledc_timer_bit_t {
545            match self {
546                Resolution::Bits1 => ledc_timer_bit_t_LEDC_TIMER_1_BIT,
547                Resolution::Bits2 => ledc_timer_bit_t_LEDC_TIMER_2_BIT,
548                Resolution::Bits3 => ledc_timer_bit_t_LEDC_TIMER_3_BIT,
549                Resolution::Bits4 => ledc_timer_bit_t_LEDC_TIMER_4_BIT,
550                Resolution::Bits5 => ledc_timer_bit_t_LEDC_TIMER_5_BIT,
551                Resolution::Bits6 => ledc_timer_bit_t_LEDC_TIMER_6_BIT,
552                Resolution::Bits7 => ledc_timer_bit_t_LEDC_TIMER_7_BIT,
553                Resolution::Bits8 => ledc_timer_bit_t_LEDC_TIMER_8_BIT,
554                Resolution::Bits9 => ledc_timer_bit_t_LEDC_TIMER_9_BIT,
555                Resolution::Bits10 => ledc_timer_bit_t_LEDC_TIMER_10_BIT,
556                Resolution::Bits11 => ledc_timer_bit_t_LEDC_TIMER_11_BIT,
557                Resolution::Bits12 => ledc_timer_bit_t_LEDC_TIMER_12_BIT,
558                Resolution::Bits13 => ledc_timer_bit_t_LEDC_TIMER_13_BIT,
559                Resolution::Bits14 => ledc_timer_bit_t_LEDC_TIMER_14_BIT,
560                #[cfg(esp32)]
561                Resolution::Bits15 => ledc_timer_bit_t_LEDC_TIMER_15_BIT,
562                #[cfg(esp32)]
563                Resolution::Bits16 => ledc_timer_bit_t_LEDC_TIMER_16_BIT,
564                #[cfg(esp32)]
565                Resolution::Bits17 => ledc_timer_bit_t_LEDC_TIMER_17_BIT,
566                #[cfg(esp32)]
567                Resolution::Bits18 => ledc_timer_bit_t_LEDC_TIMER_18_BIT,
568                #[cfg(esp32)]
569                Resolution::Bits19 => ledc_timer_bit_t_LEDC_TIMER_19_BIT,
570                #[cfg(esp32)]
571                Resolution::Bits20 => ledc_timer_bit_t_LEDC_TIMER_20_BIT,
572            }
573        }
574    }
575
576    /// Speed mode for the LED Control peripheral
577    /// The ESP32 supports two speed modes: low and high speed
578    /// All others support only low speed mode.
579    pub trait SpeedMode: Send + Sync + 'static {
580        const SPEED_MODE: ledc_mode_t;
581        const HIGH_SPEED: bool;
582    }
583
584    /// Low speed mode for the LED Control peripheral
585    pub struct LowSpeed;
586
587    impl SpeedMode for LowSpeed {
588        const SPEED_MODE: ledc_mode_t = ledc_mode_t_LEDC_LOW_SPEED_MODE;
589        const HIGH_SPEED: bool = false;
590    }
591
592    #[cfg(esp32)]
593    /// High speed mode for the LED Control peripheral (ESP32 only)
594    pub struct HighSpeed;
595
596    #[cfg(esp32)]
597    impl SpeedMode for HighSpeed {
598        const SPEED_MODE: ledc_mode_t = ledc_mode_t_LEDC_HIGH_SPEED_MODE;
599        const HIGH_SPEED: bool = true;
600    }
601
602    /// LED Control peripheral timer
603    pub trait LedcTimer {
604        type SpeedMode: SpeedMode;
605
606        fn timer() -> ledc_timer_t;
607    }
608
609    /// LED Control peripheral output channel
610    pub trait LedcChannel {
611        type SpeedMode: SpeedMode;
612
613        fn channel() -> ledc_channel_t;
614    }
615
616    macro_rules! impl_timer {
617        ($typ:ty; $instance:ident: $timer:expr) => {
618            crate::impl_peripheral!($instance);
619
620            impl LedcTimer for $instance<'_> {
621                type SpeedMode = $typ;
622
623                fn timer() -> ledc_timer_t {
624                    $timer
625                }
626            }
627        };
628    }
629
630    impl_timer!(LowSpeed; TIMER0: ledc_timer_t_LEDC_TIMER_0);
631    impl_timer!(LowSpeed; TIMER1: ledc_timer_t_LEDC_TIMER_1);
632    impl_timer!(LowSpeed; TIMER2: ledc_timer_t_LEDC_TIMER_2);
633    impl_timer!(LowSpeed; TIMER3: ledc_timer_t_LEDC_TIMER_3);
634
635    #[cfg(esp32)]
636    impl_timer!(HighSpeed; HTIMER0: ledc_timer_t_LEDC_TIMER_0);
637    #[cfg(esp32)]
638    impl_timer!(HighSpeed; HTIMER1: ledc_timer_t_LEDC_TIMER_1);
639    #[cfg(esp32)]
640    impl_timer!(HighSpeed; HTIMER2: ledc_timer_t_LEDC_TIMER_2);
641    #[cfg(esp32)]
642    impl_timer!(HighSpeed; HTIMER3: ledc_timer_t_LEDC_TIMER_3);
643
644    macro_rules! impl_channel {
645        ($typ:ty; $instance:ident: $channel:expr) => {
646            crate::impl_peripheral!($instance);
647
648            impl LedcChannel for $instance<'_> {
649                type SpeedMode = $typ;
650
651                fn channel() -> ledc_channel_t {
652                    $channel
653                }
654            }
655        };
656    }
657
658    impl_channel!(LowSpeed; CHANNEL0: ledc_channel_t_LEDC_CHANNEL_0);
659    impl_channel!(LowSpeed; CHANNEL1: ledc_channel_t_LEDC_CHANNEL_1);
660    impl_channel!(LowSpeed; CHANNEL2: ledc_channel_t_LEDC_CHANNEL_2);
661    impl_channel!(LowSpeed; CHANNEL3: ledc_channel_t_LEDC_CHANNEL_3);
662    impl_channel!(LowSpeed; CHANNEL4: ledc_channel_t_LEDC_CHANNEL_4);
663    impl_channel!(LowSpeed; CHANNEL5: ledc_channel_t_LEDC_CHANNEL_5);
664    #[cfg(any(esp32, esp32s2, esp32s3, esp8684))]
665    impl_channel!(LowSpeed; CHANNEL6: ledc_channel_t_LEDC_CHANNEL_6);
666    #[cfg(any(esp32, esp32s2, esp32s3, esp8684))]
667    impl_channel!(LowSpeed; CHANNEL7: ledc_channel_t_LEDC_CHANNEL_7);
668
669    #[cfg(esp32)]
670    impl_channel!(HighSpeed; HCHANNEL0: ledc_channel_t_LEDC_CHANNEL_0);
671    #[cfg(esp32)]
672    impl_channel!(HighSpeed; HCHANNEL1: ledc_channel_t_LEDC_CHANNEL_1);
673    #[cfg(esp32)]
674    impl_channel!(HighSpeed; HCHANNEL2: ledc_channel_t_LEDC_CHANNEL_2);
675    #[cfg(esp32)]
676    impl_channel!(HighSpeed; HCHANNEL3: ledc_channel_t_LEDC_CHANNEL_3);
677    #[cfg(esp32)]
678    impl_channel!(HighSpeed; HCHANNEL4: ledc_channel_t_LEDC_CHANNEL_4);
679    #[cfg(esp32)]
680    impl_channel!(HighSpeed; HCHANNEL5: ledc_channel_t_LEDC_CHANNEL_5);
681    #[cfg(esp32)]
682    impl_channel!(HighSpeed; HCHANNEL6: ledc_channel_t_LEDC_CHANNEL_6);
683    #[cfg(esp32)]
684    impl_channel!(HighSpeed; HCHANNEL7: ledc_channel_t_LEDC_CHANNEL_7);
685
686    /// The LED Control device peripheral
687    pub struct LEDC {
688        pub timer0: TIMER0<'static>,
689        pub timer1: TIMER1<'static>,
690        pub timer2: TIMER2<'static>,
691        pub timer3: TIMER3<'static>,
692        pub channel0: CHANNEL0<'static>,
693        pub channel1: CHANNEL1<'static>,
694        pub channel2: CHANNEL2<'static>,
695        pub channel3: CHANNEL3<'static>,
696        pub channel4: CHANNEL4<'static>,
697        pub channel5: CHANNEL5<'static>,
698        #[cfg(any(esp32, esp32s2, esp32s3, esp8684))]
699        pub channel6: CHANNEL6<'static>,
700        #[cfg(any(esp32, esp32s2, esp32s3, esp8684))]
701        pub channel7: CHANNEL7<'static>,
702    }
703
704    impl LEDC {
705        /// Creates a new instance of the LEDC peripheral. Typically one wants
706        /// to use the instance [`ledc`](crate::peripherals::Peripherals::ledc) from
707        /// the device peripherals obtained via
708        /// [`peripherals::Peripherals::take()`](crate::peripherals::Peripherals::take()).
709        ///
710        /// # Safety
711        ///
712        /// It is safe to instantiate the LEDC peripheral exactly one time.
713        /// Care has to be taken that this has not already been done elsewhere.
714        pub(crate) unsafe fn new() -> Self {
715            Self {
716                timer0: TIMER0::steal(),
717                timer1: TIMER1::steal(),
718                timer2: TIMER2::steal(),
719                timer3: TIMER3::steal(),
720                channel0: CHANNEL0::steal(),
721                channel1: CHANNEL1::steal(),
722                channel2: CHANNEL2::steal(),
723                channel3: CHANNEL3::steal(),
724                channel4: CHANNEL4::steal(),
725                channel5: CHANNEL5::steal(),
726                #[cfg(any(esp32, esp32s2, esp32s3, esp8684))]
727                channel6: CHANNEL6::steal(),
728                #[cfg(any(esp32, esp32s2, esp32s3, esp8684))]
729                channel7: CHANNEL7::steal(),
730            }
731        }
732    }
733
734    /// The LED Control device peripheral (high speed channels, ESP32 only)
735    #[cfg(esp32)]
736    pub struct HLEDC {
737        pub timer0: HTIMER0<'static>,
738        pub timer1: HTIMER1<'static>,
739        pub timer2: HTIMER2<'static>,
740        pub timer3: HTIMER3<'static>,
741        pub channel0: HCHANNEL0<'static>,
742        pub channel1: HCHANNEL1<'static>,
743        pub channel2: HCHANNEL2<'static>,
744        pub channel3: HCHANNEL3<'static>,
745        pub channel4: HCHANNEL4<'static>,
746        pub channel5: HCHANNEL5<'static>,
747        pub channel6: HCHANNEL6<'static>,
748        pub channel7: HCHANNEL7<'static>,
749    }
750
751    #[cfg(esp32)]
752    impl HLEDC {
753        /// Creates a new instance of the HLEDC peripheral. Typically one wants
754        /// to use the instance [`ledc`](crate::peripherals::Peripherals::fledc) from
755        /// the device peripherals obtained via
756        /// [`peripherals::Peripherals::take()`](crate::peripherals::Peripherals::take()).
757        ///
758        /// # Safety
759        ///
760        /// It is safe to instantiate the HLEDC peripheral exactly one time.
761        /// Care has to be taken that this has not already been done elsewhere.
762        pub(crate) unsafe fn new() -> Self {
763            Self {
764                timer0: HTIMER0::steal(),
765                timer1: HTIMER1::steal(),
766                timer2: HTIMER2::steal(),
767                timer3: HTIMER3::steal(),
768                channel0: HCHANNEL0::steal(),
769                channel1: HCHANNEL1::steal(),
770                channel2: HCHANNEL2::steal(),
771                channel3: HCHANNEL3::steal(),
772                channel4: HCHANNEL4::steal(),
773                channel5: HCHANNEL5::steal(),
774                channel6: HCHANNEL6::steal(),
775                channel7: HCHANNEL7::steal(),
776            }
777        }
778    }
779}