Skip to main content

esp_hal/ledc/
timer.rs

1//! # LEDC timer
2//!
3//! ## Overview
4//! The LEDC Timer provides a high-level interface to configure and control
5//! individual timers of the `LEDC` peripheral.
6//!
7//! ## Configuration
8//! The module allows precise and flexible control over timer configurations,
9//! duty cycles and frequencies, making it ideal for Pulse-Width Modulation
10//! (PWM) applications and LED lighting control.
11//!
12//! LEDC uses APB as clock source.
13
14#[cfg(esp32)]
15use super::HighSpeed;
16use super::{LowSpeed, Speed};
17use crate::{clock::Clocks, pac, time::Rate};
18
19const LEDC_TIMER_DIV_NUM_MAX: u64 = 0x3FFFF;
20
21/// Timer errors
22#[derive(Debug, Clone, Copy, PartialEq)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub enum Error {
25    /// Invalid Divisor
26    Divisor,
27    /// Frequency unset
28    FrequencyUnset,
29}
30
31#[cfg(esp32)]
32/// Clock source for HS Timers
33#[derive(PartialEq, Eq, Copy, Clone, Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub enum HSClockSource {
36    /// APB clock.
37    APBClk,
38    // TODO RefTick,
39}
40
41/// Clock source for LS Timers
42#[derive(PartialEq, Eq, Copy, Clone, Debug)]
43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
44pub enum LSClockSource {
45    /// APB clock.
46    APBClk,
47    // TODO SLOWClk
48}
49
50/// Timer number
51#[derive(PartialEq, Eq, Copy, Clone, Debug)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub enum Number {
54    /// Timer 0.
55    Timer0 = 0,
56    /// Timer 1.
57    Timer1 = 1,
58    /// Timer 2.
59    Timer2 = 2,
60    /// Timer 3.
61    Timer3 = 3,
62}
63
64/// Timer configuration
65pub mod config {
66    use crate::time::Rate;
67
68    /// Number of bits reserved for duty cycle adjustment
69    #[derive(PartialEq, Eq, Copy, Clone, Debug)]
70    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
71    #[allow(clippy::enum_variant_names)] // FIXME: resolve before stabilizing this driver
72    pub enum Duty {
73        /// 1-bit resolution for duty cycle adjustment.
74        Duty1Bit = 1,
75        /// 2-bit resolution for duty cycle adjustment.
76        Duty2Bit,
77        /// 3-bit resolution for duty cycle adjustment.
78        Duty3Bit,
79        /// 4-bit resolution for duty cycle adjustment.
80        Duty4Bit,
81        /// 5-bit resolution for duty cycle adjustment.
82        Duty5Bit,
83        /// 6-bit resolution for duty cycle adjustment.
84        Duty6Bit,
85        /// 7-bit resolution for duty cycle adjustment.
86        Duty7Bit,
87        /// 8-bit resolution for duty cycle adjustment.
88        Duty8Bit,
89        /// 9-bit resolution for duty cycle adjustment.
90        Duty9Bit,
91        /// 10-bit resolution for duty cycle adjustment.
92        Duty10Bit,
93        /// 11-bit resolution for duty cycle adjustment.
94        Duty11Bit,
95        /// 12-bit resolution for duty cycle adjustment.
96        Duty12Bit,
97        /// 13-bit resolution for duty cycle adjustment.
98        Duty13Bit,
99        /// 14-bit resolution for duty cycle adjustment.
100        Duty14Bit,
101        #[cfg(esp32)]
102        /// 15-bit resolution for duty cycle adjustment.
103        Duty15Bit,
104        #[cfg(esp32)]
105        /// 16-bit resolution for duty cycle adjustment.
106        Duty16Bit,
107        #[cfg(esp32)]
108        /// 17-bit resolution for duty cycle adjustment.
109        Duty17Bit,
110        #[cfg(esp32)]
111        /// 18-bit resolution for duty cycle adjustment.
112        Duty18Bit,
113        #[cfg(esp32)]
114        /// 19-bit resolution for duty cycle adjustment.
115        Duty19Bit,
116        #[cfg(esp32)]
117        /// 20-bit resolution for duty cycle adjustment.
118        Duty20Bit,
119    }
120
121    impl TryFrom<u32> for Duty {
122        type Error = ();
123
124        fn try_from(value: u32) -> Result<Self, Self::Error> {
125            Ok(match value {
126                1 => Self::Duty1Bit,
127                2 => Self::Duty2Bit,
128                3 => Self::Duty3Bit,
129                4 => Self::Duty4Bit,
130                5 => Self::Duty5Bit,
131                6 => Self::Duty6Bit,
132                7 => Self::Duty7Bit,
133                8 => Self::Duty8Bit,
134                9 => Self::Duty9Bit,
135                10 => Self::Duty10Bit,
136                11 => Self::Duty11Bit,
137                12 => Self::Duty12Bit,
138                13 => Self::Duty13Bit,
139                14 => Self::Duty14Bit,
140                #[cfg(esp32)]
141                15 => Self::Duty15Bit,
142                #[cfg(esp32)]
143                16 => Self::Duty16Bit,
144                #[cfg(esp32)]
145                17 => Self::Duty17Bit,
146                #[cfg(esp32)]
147                18 => Self::Duty18Bit,
148                #[cfg(esp32)]
149                19 => Self::Duty19Bit,
150                #[cfg(esp32)]
151                20 => Self::Duty20Bit,
152                _ => Err(())?,
153            })
154        }
155    }
156
157    /// Timer configuration
158    #[derive(Copy, Clone)]
159    pub struct Config<CS> {
160        /// The duty cycle resolution.
161        pub duty: Duty,
162        /// The clock source for the timer.
163        pub clock_source: CS,
164        /// The frequency of the PWM signal in Hertz.
165        pub frequency: Rate,
166    }
167}
168
169/// Trait defining the type of timer source
170pub trait TimerSpeed: Speed {
171    /// The type of clock source used by the timer in this speed mode.
172    type ClockSourceType;
173}
174
175/// Timer source type for LowSpeed timers
176impl TimerSpeed for LowSpeed {
177    /// The clock source type for low-speed timers.
178    type ClockSourceType = LSClockSource;
179}
180
181#[cfg(esp32)]
182/// Timer source type for HighSpeed timers
183impl TimerSpeed for HighSpeed {
184    /// The clock source type for high-speed timers.
185    type ClockSourceType = HSClockSource;
186}
187
188/// Interface for Timers
189pub trait TimerIFace<S: TimerSpeed> {
190    /// Return the frequency of the timer
191    fn freq(&self) -> Option<Rate>;
192
193    /// Configure the timer
194    fn configure(&mut self, config: config::Config<S::ClockSourceType>) -> Result<(), Error>;
195
196    /// Check if the timer has been configured
197    fn is_configured(&self) -> bool;
198
199    /// Return the duty resolution of the timer
200    fn duty(&self) -> Option<config::Duty>;
201
202    /// Return the timer number
203    fn number(&self) -> Number;
204
205    /// Return the timer frequency, or 0 if not configured
206    fn frequency(&self) -> u32;
207}
208
209/// Interface for HW configuration of timer
210pub trait TimerHW<S: TimerSpeed> {
211    /// Get the current source timer frequency from the HW
212    fn freq_hw(&self) -> Option<Rate>;
213
214    /// Configure the HW for the timer
215    fn configure_hw(&self, divisor: u32);
216
217    /// Update the timer in HW
218    fn update_hw(&self);
219}
220
221/// Timer struct
222pub struct Timer<'a, S: TimerSpeed> {
223    ledc: &'a pac::ledc::RegisterBlock,
224    number: Number,
225    duty: Option<config::Duty>,
226    frequency: u32,
227    configured: bool,
228    #[cfg(soc_has_clock_node_ref_tick)]
229    use_ref_tick: bool,
230    clock_source: Option<S::ClockSourceType>,
231}
232
233impl<'a, S: TimerSpeed> TimerIFace<S> for Timer<'a, S>
234where
235    Timer<'a, S>: TimerHW<S>,
236{
237    /// Return the frequency of the timer
238    fn freq(&self) -> Option<Rate> {
239        self.freq_hw()
240    }
241
242    /// Configure the timer
243    fn configure(&mut self, config: config::Config<S::ClockSourceType>) -> Result<(), Error> {
244        self.duty = Some(config.duty);
245        self.clock_source = Some(config.clock_source);
246
247        let src_freq: u32 = self.freq().ok_or(Error::FrequencyUnset)?.as_hz();
248        let precision = 1 << config.duty as u32;
249        let frequency: u32 = config.frequency.as_hz();
250        self.frequency = frequency;
251
252        #[cfg_attr(not(soc_has_clock_node_ref_tick), expect(unused_mut))]
253        let mut divisor = ((src_freq as u64) << 8) / frequency as u64 / precision as u64;
254
255        #[cfg(soc_has_clock_node_ref_tick)]
256        if divisor > LEDC_TIMER_DIV_NUM_MAX {
257            // APB_CLK results in divisor which too high. Try using REF_TICK as clock
258            // source.
259            self.use_ref_tick = true;
260            divisor = (1_000_000u64 << 8) / frequency as u64 / precision as u64;
261        }
262
263        if !(256..LEDC_TIMER_DIV_NUM_MAX).contains(&divisor) {
264            return Err(Error::Divisor);
265        }
266
267        self.configure_hw(divisor as u32);
268        self.update_hw();
269
270        self.configured = true;
271
272        Ok(())
273    }
274
275    /// Check if the timer has been configured
276    fn is_configured(&self) -> bool {
277        self.configured
278    }
279
280    /// Return the duty resolution of the timer
281    fn duty(&self) -> Option<config::Duty> {
282        self.duty
283    }
284
285    /// Return the timer number
286    fn number(&self) -> Number {
287        self.number
288    }
289
290    /// Return the timer frequency
291    fn frequency(&self) -> u32 {
292        self.frequency
293    }
294}
295
296impl<'a, S: TimerSpeed> Timer<'a, S> {
297    /// Create a new instance of a timer
298    pub fn new(ledc: &'a pac::ledc::RegisterBlock, number: Number) -> Self {
299        Timer {
300            ledc,
301            number,
302            duty: None,
303            frequency: 0u32,
304            configured: false,
305            #[cfg(soc_has_clock_node_ref_tick)]
306            use_ref_tick: false,
307            clock_source: None,
308        }
309    }
310}
311
312/// Timer HW implementation for LowSpeed timers
313impl TimerHW<LowSpeed> for Timer<'_, LowSpeed> {
314    /// Get the current source timer frequency from the HW
315    fn freq_hw(&self) -> Option<Rate> {
316        self.clock_source.map(|source| match source {
317            LSClockSource::APBClk => {
318                let clocks = Clocks::get();
319                clocks.apb_clock
320            }
321        })
322    }
323
324    #[cfg(esp32)]
325    /// Configure the HW for the timer
326    fn configure_hw(&self, divisor: u32) {
327        let duty = unwrap!(self.duty) as u8;
328        let use_apb = !self.use_ref_tick;
329
330        self.ledc
331            .lstimer(self.number as usize)
332            .conf()
333            .modify(|_, w| unsafe {
334                w.tick_sel().bit(use_apb);
335                w.rst().clear_bit();
336                w.pause().clear_bit();
337                w.div_num().bits(divisor);
338                w.duty_res().bits(duty)
339            });
340    }
341
342    #[cfg(not(esp32))]
343    /// Configure the HW for the timer
344    fn configure_hw(&self, divisor: u32) {
345        let duty = unwrap!(self.duty) as u8;
346
347        self.ledc
348            .timer(self.number as usize)
349            .conf()
350            .modify(|_, w| unsafe {
351                #[cfg(soc_has_clock_node_ref_tick)]
352                w.tick_sel().bit(self.use_ref_tick);
353                w.rst().clear_bit();
354                w.pause().clear_bit();
355                w.clk_div().bits(divisor);
356                w.duty_res().bits(duty)
357            });
358    }
359
360    /// Update the timer in HW
361    fn update_hw(&self) {
362        cfg_if::cfg_if! {
363            if #[cfg(esp32)] {
364                let tmr = self.ledc.lstimer(self.number as usize);
365            } else {
366                let tmr = self.ledc.timer(self.number as usize);
367            }
368        }
369
370        tmr.conf().modify(|_, w| w.para_up().set_bit());
371    }
372}
373
374#[cfg(esp32)]
375/// Timer HW implementation for HighSpeed timers
376impl TimerHW<HighSpeed> for Timer<'_, HighSpeed> {
377    /// Get the current source timer frequency from the HW
378    fn freq_hw(&self) -> Option<Rate> {
379        self.clock_source.map(|source| match source {
380            HSClockSource::APBClk => {
381                let clocks = Clocks::get();
382                clocks.apb_clock
383            }
384        })
385    }
386
387    /// Configure the HW for the timer
388    fn configure_hw(&self, divisor: u32) {
389        let duty = unwrap!(self.duty) as u8;
390        let sel_hstimer = self.clock_source == Some(HSClockSource::APBClk);
391
392        self.ledc
393            .hstimer(self.number as usize)
394            .conf()
395            .modify(|_, w| unsafe {
396                w.tick_sel().bit(sel_hstimer);
397                w.rst().clear_bit();
398                w.pause().clear_bit();
399                w.div_num().bits(divisor);
400                w.duty_res().bits(duty)
401            });
402    }
403
404    /// Update the timer in HW
405    fn update_hw(&self) {
406        // Nothing to do for HS timers
407    }
408}