use fugit::HertzU32;
#[cfg(esp32)]
use super::HighSpeed;
use super::{LowSpeed, Speed};
use crate::{clock::Clocks, peripherals::ledc};
const LEDC_TIMER_DIV_NUM_MAX: u64 = 0x3FFFF;
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
Divisor,
}
#[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,
Timer1,
Timer2,
Timer3,
}
pub mod config {
use fugit::HertzU32;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
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,
}
#[derive(Copy, Clone)]
pub struct Config<CS> {
pub duty: Duty,
pub clock_source: CS,
pub frequency: HertzU32,
}
}
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 get_freq(&self) -> Option<HertzU32>;
fn configure(&mut self, config: config::Config<S::ClockSourceType>) -> Result<(), Error>;
fn is_configured(&self) -> bool;
fn get_duty(&self) -> Option<config::Duty>;
fn get_number(&self) -> Number;
fn get_frequency(&self) -> u32;
}
pub trait TimerHW<S: TimerSpeed> {
fn get_freq_hw(&self) -> Option<HertzU32>;
fn configure_hw(&self, divisor: u32);
fn update_hw(&self);
}
pub struct Timer<'a, S: TimerSpeed> {
ledc: &'a crate::peripherals::ledc::RegisterBlock,
clock_control_config: &'a Clocks<'a>,
number: Number,
duty: Option<config::Duty>,
frequency: u32,
configured: bool,
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 get_freq(&self) -> Option<HertzU32> {
self.get_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.get_freq().unwrap().to_Hz();
let precision = 1 << config.duty as u32;
let frequency: u32 = config.frequency.raw();
self.frequency = frequency;
let mut divisor = ((src_freq as u64) << 8) / frequency as u64 / precision as u64;
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 get_duty(&self) -> Option<config::Duty> {
self.duty
}
fn get_number(&self) -> Number {
self.number
}
fn get_frequency(&self) -> u32 {
self.frequency
}
}
impl<'a, S: TimerSpeed> Timer<'a, S> {
pub fn new(
ledc: &'a ledc::RegisterBlock,
clock_control_config: &'a Clocks,
number: Number,
) -> Self {
Timer {
ledc,
clock_control_config,
number,
duty: None,
frequency: 0u32,
configured: false,
use_ref_tick: false,
clock_source: None,
}
}
}
impl<'a> TimerHW<LowSpeed> for Timer<'a, LowSpeed> {
fn get_freq_hw(&self) -> Option<fugit::HertzU32> {
self.clock_source.map(|cs| match cs {
LSClockSource::APBClk => self.clock_control_config.apb_clock,
})
}
#[cfg(esp32)]
fn configure_hw(&self, divisor: u32) {
let duty = unwrap!(self.duty) as u8;
let use_apb = !self.use_ref_tick;
match self.number {
Number::Timer0 => self.ledc.lstimer0_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(use_apb)
.rst()
.clear_bit()
.pause()
.clear_bit()
.div_num()
.bits(divisor)
.duty_res()
.bits(duty)
}),
Number::Timer1 => self.ledc.lstimer1_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(use_apb)
.rst()
.clear_bit()
.pause()
.clear_bit()
.div_num()
.bits(divisor)
.duty_res()
.bits(duty)
}),
Number::Timer2 => self.ledc.lstimer2_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(use_apb)
.rst()
.clear_bit()
.pause()
.clear_bit()
.div_num()
.bits(divisor)
.duty_res()
.bits(duty)
}),
Number::Timer3 => self.ledc.lstimer3_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(use_apb)
.rst()
.clear_bit()
.pause()
.clear_bit()
.div_num()
.bits(divisor)
.duty_res()
.bits(duty)
}),
};
}
#[cfg(not(esp32))]
fn configure_hw(&self, divisor: u32) {
let duty = unwrap!(self.duty) as u8;
let use_ref_tick = self.use_ref_tick;
match self.number {
Number::Timer0 => self.ledc.timer0_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(use_ref_tick)
.rst()
.clear_bit()
.pause()
.clear_bit()
.clk_div()
.bits(divisor)
.duty_res()
.bits(duty)
}),
Number::Timer1 => self.ledc.timer1_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(use_ref_tick)
.rst()
.clear_bit()
.pause()
.clear_bit()
.clk_div()
.bits(divisor)
.duty_res()
.bits(duty)
}),
Number::Timer2 => self.ledc.timer2_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(use_ref_tick)
.rst()
.clear_bit()
.pause()
.clear_bit()
.clk_div()
.bits(divisor)
.duty_res()
.bits(duty)
}),
Number::Timer3 => self.ledc.timer3_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(use_ref_tick)
.rst()
.clear_bit()
.pause()
.clear_bit()
.clk_div()
.bits(divisor)
.duty_res()
.bits(duty)
}),
};
}
#[cfg(esp32)]
fn update_hw(&self) {
match self.number {
Number::Timer0 => self
.ledc
.lstimer0_conf()
.modify(|_, w| w.para_up().set_bit()),
Number::Timer1 => self
.ledc
.lstimer1_conf()
.modify(|_, w| w.para_up().set_bit()),
Number::Timer2 => self
.ledc
.lstimer2_conf()
.modify(|_, w| w.para_up().set_bit()),
Number::Timer3 => self
.ledc
.lstimer3_conf()
.modify(|_, w| w.para_up().set_bit()),
};
}
#[cfg(not(esp32))]
fn update_hw(&self) {
match self.number {
Number::Timer0 => self.ledc.timer0_conf().modify(|_, w| w.para_up().set_bit()),
Number::Timer1 => self.ledc.timer1_conf().modify(|_, w| w.para_up().set_bit()),
Number::Timer2 => self.ledc.timer2_conf().modify(|_, w| w.para_up().set_bit()),
Number::Timer3 => self.ledc.timer3_conf().modify(|_, w| w.para_up().set_bit()),
};
}
}
#[cfg(esp32)]
impl<'a> TimerHW<HighSpeed> for Timer<'a, HighSpeed> {
fn get_freq_hw(&self) -> Option<HertzU32> {
self.clock_source.map(|cs| match cs {
HSClockSource::APBClk => self.clock_control_config.apb_clock,
})
}
fn configure_hw(&self, divisor: u32) {
let duty = unwrap!(self.duty) as u8;
let sel_hstimer = self.clock_source == Some(HSClockSource::APBClk);
match self.number {
Number::Timer0 => self.ledc.hstimer0_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_hstimer)
.rst()
.clear_bit()
.pause()
.clear_bit()
.div_num()
.bits(divisor)
.duty_res()
.bits(duty)
}),
Number::Timer1 => self.ledc.hstimer1_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_hstimer)
.rst()
.clear_bit()
.pause()
.clear_bit()
.div_num()
.bits(divisor)
.duty_res()
.bits(duty)
}),
Number::Timer2 => self.ledc.hstimer2_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_hstimer)
.rst()
.clear_bit()
.pause()
.clear_bit()
.div_num()
.bits(divisor)
.duty_res()
.bits(duty)
}),
Number::Timer3 => self.ledc.hstimer3_conf().modify(|_, w| unsafe {
w.tick_sel()
.bit(sel_hstimer)
.rst()
.clear_bit()
.pause()
.clear_bit()
.div_num()
.bits(divisor)
.duty_res()
.bits(duty)
}),
};
}
fn update_hw(&self) {
}
}