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