1#[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#[derive(Debug, Clone, Copy, PartialEq)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub enum Error {
25    Divisor,
27    FrequencyUnset,
29}
30
31#[cfg(esp32)]
32#[derive(PartialEq, Eq, Copy, Clone, Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub enum HSClockSource {
36    APBClk,
38    }
40
41#[derive(PartialEq, Eq, Copy, Clone, Debug)]
43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
44pub enum LSClockSource {
45    APBClk,
47    }
49
50#[derive(PartialEq, Eq, Copy, Clone, Debug)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub enum Number {
54    Timer0 = 0,
56    Timer1 = 1,
58    Timer2 = 2,
60    Timer3 = 3,
62}
63
64pub mod config {
66    use crate::time::Rate;
67
68    #[derive(PartialEq, Eq, Copy, Clone, Debug)]
70    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
71    #[allow(clippy::enum_variant_names)] pub enum Duty {
73        Duty1Bit = 1,
75        Duty2Bit,
77        Duty3Bit,
79        Duty4Bit,
81        Duty5Bit,
83        Duty6Bit,
85        Duty7Bit,
87        Duty8Bit,
89        Duty9Bit,
91        Duty10Bit,
93        Duty11Bit,
95        Duty12Bit,
97        Duty13Bit,
99        Duty14Bit,
101        #[cfg(esp32)]
102        Duty15Bit,
104        #[cfg(esp32)]
105        Duty16Bit,
107        #[cfg(esp32)]
108        Duty17Bit,
110        #[cfg(esp32)]
111        Duty18Bit,
113        #[cfg(esp32)]
114        Duty19Bit,
116        #[cfg(esp32)]
117        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    #[derive(Copy, Clone)]
159    pub struct Config<CS> {
160        pub duty: Duty,
162        pub clock_source: CS,
164        pub frequency: Rate,
166    }
167}
168
169pub trait TimerSpeed: Speed {
171    type ClockSourceType;
173}
174
175impl TimerSpeed for LowSpeed {
177    type ClockSourceType = LSClockSource;
179}
180
181#[cfg(esp32)]
182impl TimerSpeed for HighSpeed {
184    type ClockSourceType = HSClockSource;
186}
187
188pub trait TimerIFace<S: TimerSpeed> {
190    fn freq(&self) -> Option<Rate>;
192
193    fn configure(&mut self, config: config::Config<S::ClockSourceType>) -> Result<(), Error>;
195
196    fn is_configured(&self) -> bool;
198
199    fn duty(&self) -> Option<config::Duty>;
201
202    fn number(&self) -> Number;
204
205    fn frequency(&self) -> u32;
207}
208
209pub trait TimerHW<S: TimerSpeed> {
211    fn freq_hw(&self) -> Option<Rate>;
213
214    fn configure_hw(&self, divisor: u32);
216
217    fn update_hw(&self);
219}
220
221pub 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    use_ref_tick: bool,
229    clock_source: Option<S::ClockSourceType>,
230}
231
232impl<'a, S: TimerSpeed> TimerIFace<S> for Timer<'a, S>
233where
234    Timer<'a, S>: TimerHW<S>,
235{
236    fn freq(&self) -> Option<Rate> {
238        self.freq_hw()
239    }
240
241    fn configure(&mut self, config: config::Config<S::ClockSourceType>) -> Result<(), Error> {
243        self.duty = Some(config.duty);
244        self.clock_source = Some(config.clock_source);
245
246        let src_freq: u32 = self.freq().ok_or(Error::FrequencyUnset)?.as_hz();
247        let precision = 1 << config.duty as u32;
248        let frequency: u32 = config.frequency.as_hz();
249        self.frequency = frequency;
250
251        let mut divisor = ((src_freq as u64) << 8) / frequency as u64 / precision as u64;
252
253        if divisor > LEDC_TIMER_DIV_NUM_MAX && cfg!(soc_ref_tick_hz_is_set) {
254            self.use_ref_tick = true;
257            divisor = (1_000_000u64 << 8) / frequency as u64 / precision as u64;
258        }
259
260        if !(256..LEDC_TIMER_DIV_NUM_MAX).contains(&divisor) {
261            return Err(Error::Divisor);
262        }
263
264        self.configure_hw(divisor as u32);
265        self.update_hw();
266
267        self.configured = true;
268
269        Ok(())
270    }
271
272    fn is_configured(&self) -> bool {
274        self.configured
275    }
276
277    fn duty(&self) -> Option<config::Duty> {
279        self.duty
280    }
281
282    fn number(&self) -> Number {
284        self.number
285    }
286
287    fn frequency(&self) -> u32 {
289        self.frequency
290    }
291}
292
293impl<'a, S: TimerSpeed> Timer<'a, S> {
294    pub fn new(ledc: &'a pac::ledc::RegisterBlock, number: Number) -> Self {
296        Timer {
297            ledc,
298            number,
299            duty: None,
300            frequency: 0u32,
301            configured: false,
302            use_ref_tick: false,
303            clock_source: None,
304        }
305    }
306}
307
308impl TimerHW<LowSpeed> for Timer<'_, LowSpeed> {
310    fn freq_hw(&self) -> Option<Rate> {
312        self.clock_source.map(|source| match source {
313            LSClockSource::APBClk => {
314                let clocks = Clocks::get();
315                clocks.apb_clock
316            }
317        })
318    }
319
320    #[cfg(esp32)]
321    fn configure_hw(&self, divisor: u32) {
323        let duty = unwrap!(self.duty) as u8;
324        let use_apb = !self.use_ref_tick;
325
326        self.ledc
327            .lstimer(self.number as usize)
328            .conf()
329            .modify(|_, w| unsafe {
330                w.tick_sel().bit(use_apb);
331                w.rst().clear_bit();
332                w.pause().clear_bit();
333                w.div_num().bits(divisor);
334                w.duty_res().bits(duty)
335            });
336    }
337
338    #[cfg(not(esp32))]
339    fn configure_hw(&self, divisor: u32) {
341        let duty = unwrap!(self.duty) as u8;
342        let use_ref_tick = self.use_ref_tick;
343
344        self.ledc
345            .timer(self.number as usize)
346            .conf()
347            .modify(|_, w| unsafe {
348                w.tick_sel().bit(use_ref_tick);
349                w.rst().clear_bit();
350                w.pause().clear_bit();
351                w.clk_div().bits(divisor);
352                w.duty_res().bits(duty)
353            });
354    }
355
356    fn update_hw(&self) {
358        cfg_if::cfg_if! {
359            if #[cfg(esp32)] {
360                let tmr = self.ledc.lstimer(self.number as usize);
361            } else {
362                let tmr = self.ledc.timer(self.number as usize);
363            }
364        }
365
366        tmr.conf().modify(|_, w| w.para_up().set_bit());
367    }
368}
369
370#[cfg(esp32)]
371impl TimerHW<HighSpeed> for Timer<'_, HighSpeed> {
373    fn freq_hw(&self) -> Option<Rate> {
375        self.clock_source.map(|source| match source {
376            HSClockSource::APBClk => {
377                let clocks = Clocks::get();
378                clocks.apb_clock
379            }
380        })
381    }
382
383    fn configure_hw(&self, divisor: u32) {
385        let duty = unwrap!(self.duty) as u8;
386        let sel_hstimer = self.clock_source == Some(HSClockSource::APBClk);
387
388        self.ledc
389            .hstimer(self.number as usize)
390            .conf()
391            .modify(|_, w| unsafe {
392                w.tick_sel().bit(sel_hstimer);
393                w.rst().clear_bit();
394                w.pause().clear_bit();
395                w.div_num().bits(divisor);
396                w.duty_res().bits(duty)
397            });
398    }
399
400    fn update_hw(&self) {
402        }
404}