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 #[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 fn freq(&self) -> Option<Rate> {
239 self.freq_hw()
240 }
241
242 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 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 fn is_configured(&self) -> bool {
277 self.configured
278 }
279
280 fn duty(&self) -> Option<config::Duty> {
282 self.duty
283 }
284
285 fn number(&self) -> Number {
287 self.number
288 }
289
290 fn frequency(&self) -> u32 {
292 self.frequency
293 }
294}
295
296impl<'a, S: TimerSpeed> Timer<'a, S> {
297 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
312impl TimerHW<LowSpeed> for Timer<'_, LowSpeed> {
314 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 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 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 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)]
375impl TimerHW<HighSpeed> for Timer<'_, HighSpeed> {
377 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 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 fn update_hw(&self) {
406 }
408}