#[cfg(esp32)]
use super::HighSpeed;
use super::{LowSpeed, Speed};
use crate::{clock::Clocks, pac, time::Rate};
const LEDC_TIMER_DIV_NUM_MAX: u64 = 0x3FFFF;
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
Divisor,
FrequencyUnset,
}
#[cfg(esp32)]
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum HSClockSource {
APBClk,
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum LSClockSource {
APBClk,
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Number {
Timer0 = 0,
Timer1 = 1,
Timer2 = 2,
Timer3 = 3,
}
pub mod config {
use crate::time::Rate;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(clippy::enum_variant_names)] pub enum Duty {
Duty1Bit = 1,
Duty2Bit,
Duty3Bit,
Duty4Bit,
Duty5Bit,
Duty6Bit,
Duty7Bit,
Duty8Bit,
Duty9Bit,
Duty10Bit,
Duty11Bit,
Duty12Bit,
Duty13Bit,
Duty14Bit,
#[cfg(esp32)]
Duty15Bit,
#[cfg(esp32)]
Duty16Bit,
#[cfg(esp32)]
Duty17Bit,
#[cfg(esp32)]
Duty18Bit,
#[cfg(esp32)]
Duty19Bit,
#[cfg(esp32)]
Duty20Bit,
}
impl TryFrom<u32> for Duty {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
Ok(match value {
1 => Self::Duty1Bit,
2 => Self::Duty2Bit,
3 => Self::Duty3Bit,
4 => Self::Duty4Bit,
5 => Self::Duty5Bit,
6 => Self::Duty6Bit,
7 => Self::Duty7Bit,
8 => Self::Duty8Bit,
9 => Self::Duty9Bit,
10 => Self::Duty10Bit,
11 => Self::Duty11Bit,
12 => Self::Duty12Bit,
13 => Self::Duty13Bit,
14 => Self::Duty14Bit,
#[cfg(esp32)]
15 => Self::Duty15Bit,
#[cfg(esp32)]
16 => Self::Duty16Bit,
#[cfg(esp32)]
17 => Self::Duty17Bit,
#[cfg(esp32)]
18 => Self::Duty18Bit,
#[cfg(esp32)]
19 => Self::Duty19Bit,
#[cfg(esp32)]
20 => Self::Duty20Bit,
_ => Err(())?,
})
}
}
#[derive(Copy, Clone)]
pub struct Config<CS> {
pub duty: Duty,
pub clock_source: CS,
pub frequency: Rate,
}
}
pub trait TimerSpeed: Speed {
type ClockSourceType;
}
impl TimerSpeed for LowSpeed {
type ClockSourceType = LSClockSource;
}
#[cfg(esp32)]
impl TimerSpeed for HighSpeed {
type ClockSourceType = HSClockSource;
}
pub trait TimerIFace<S: TimerSpeed> {
fn freq(&self) -> Option<Rate>;
fn configure(&mut self, config: config::Config<S::ClockSourceType>) -> Result<(), Error>;
fn is_configured(&self) -> bool;
fn duty(&self) -> Option<config::Duty>;
fn number(&self) -> Number;
fn frequency(&self) -> u32;
}
pub trait TimerHW<S: TimerSpeed> {
fn freq_hw(&self) -> Option<Rate>;
fn configure_hw(&self, divisor: u32);
fn update_hw(&self);
}
pub struct Timer<'a, S: TimerSpeed> {
ledc: &'a pac::ledc::RegisterBlock,
number: Number,
duty: Option<config::Duty>,
frequency: u32,
configured: bool,
#[cfg(soc_has_clock_node_ref_tick)]
use_ref_tick: bool,
clock_source: Option<S::ClockSourceType>,
}
impl<'a, S: TimerSpeed> TimerIFace<S> for Timer<'a, S>
where
Timer<'a, S>: TimerHW<S>,
{
fn freq(&self) -> Option<Rate> {
self.freq_hw()
}
fn configure(&mut self, config: config::Config<S::ClockSourceType>) -> Result<(), Error> {
self.duty = Some(config.duty);
self.clock_source = Some(config.clock_source);
let src_freq: u32 = self.freq().ok_or(Error::FrequencyUnset)?.as_hz();
let precision = 1 << config.duty as u32;
let frequency: u32 = config.frequency.as_hz();
self.frequency = frequency;
#[cfg_attr(not(soc_has_clock_node_ref_tick), expect(unused_mut))]
let mut divisor = ((src_freq as u64) << 8) / frequency as u64 / precision as u64;
#[cfg(soc_has_clock_node_ref_tick)]
if divisor > LEDC_TIMER_DIV_NUM_MAX {
self.use_ref_tick = true;
divisor = (1_000_000u64 << 8) / frequency as u64 / precision as u64;
}
if !(256..LEDC_TIMER_DIV_NUM_MAX).contains(&divisor) {
return Err(Error::Divisor);
}
self.configure_hw(divisor as u32);
self.update_hw();
self.configured = true;
Ok(())
}
fn is_configured(&self) -> bool {
self.configured
}
fn duty(&self) -> Option<config::Duty> {
self.duty
}
fn number(&self) -> Number {
self.number
}
fn frequency(&self) -> u32 {
self.frequency
}
}
impl<'a, S: TimerSpeed> Timer<'a, S> {
pub fn new(ledc: &'a pac::ledc::RegisterBlock, number: Number) -> Self {
Timer {
ledc,
number,
duty: None,
frequency: 0u32,
configured: false,
#[cfg(soc_has_clock_node_ref_tick)]
use_ref_tick: false,
clock_source: None,
}
}
}
impl TimerHW<LowSpeed> for Timer<'_, LowSpeed> {
fn freq_hw(&self) -> Option<Rate> {
self.clock_source.map(|source| match source {
LSClockSource::APBClk => {
let clocks = Clocks::get();
clocks.apb_clock
}
})
}
#[cfg(esp32)]
fn configure_hw(&self, divisor: u32) {
let duty = unwrap!(self.duty) as u8;
let use_apb = !self.use_ref_tick;
self.ledc
.lstimer(self.number as usize)
.conf()
.modify(|_, w| unsafe {
w.tick_sel().bit(use_apb);
w.rst().clear_bit();
w.pause().clear_bit();
w.div_num().bits(divisor);
w.duty_res().bits(duty)
});
}
#[cfg(not(esp32))]
fn configure_hw(&self, divisor: u32) {
let duty = unwrap!(self.duty) as u8;
self.ledc
.timer(self.number as usize)
.conf()
.modify(|_, w| unsafe {
#[cfg(soc_has_clock_node_ref_tick)]
w.tick_sel().bit(self.use_ref_tick);
w.rst().clear_bit();
w.pause().clear_bit();
w.clk_div().bits(divisor);
w.duty_res().bits(duty)
});
}
fn update_hw(&self) {
cfg_if::cfg_if! {
if #[cfg(esp32)] {
let tmr = self.ledc.lstimer(self.number as usize);
} else {
let tmr = self.ledc.timer(self.number as usize);
}
}
tmr.conf().modify(|_, w| w.para_up().set_bit());
}
}
#[cfg(esp32)]
impl TimerHW<HighSpeed> for Timer<'_, HighSpeed> {
fn freq_hw(&self) -> Option<Rate> {
self.clock_source.map(|source| match source {
HSClockSource::APBClk => {
let clocks = Clocks::get();
clocks.apb_clock
}
})
}
fn configure_hw(&self, divisor: u32) {
let duty = unwrap!(self.duty) as u8;
let sel_hstimer = self.clock_source == Some(HSClockSource::APBClk);
self.ledc
.hstimer(self.number as usize)
.conf()
.modify(|_, w| unsafe {
w.tick_sel().bit(sel_hstimer);
w.rst().clear_bit();
w.pause().clear_bit();
w.div_num().bits(divisor);
w.duty_res().bits(duty)
});
}
fn update_hw(&self) {
}
}