#![cfg_attr(docsrs, procmacros::doc_replace)]
use self::{
channel::Channel,
timer::{Timer, TimerSpeed},
};
use crate::{
gpio::interconnect::PeripheralOutput,
pac,
peripherals::LEDC,
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
};
pub mod channel;
pub mod timer;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum LSGlobalClkSource {
APBClk,
}
pub struct Ledc<'d> {
_instance: LEDC<'d>,
ledc: &'d pac::ledc::RegisterBlock,
}
#[cfg(esp32)]
#[derive(Clone, Copy)]
pub struct HighSpeed {}
#[derive(Clone, Copy)]
pub struct LowSpeed {}
pub trait Speed {
const IS_HS: bool;
}
#[cfg(esp32)]
impl Speed for HighSpeed {
const IS_HS: bool = true;
}
impl Speed for LowSpeed {
const IS_HS: bool = false;
}
impl<'d> Ledc<'d> {
pub fn new(_instance: LEDC<'d>) -> Self {
if PeripheralClockControl::enable(PeripheralEnable::Ledc) {
PeripheralClockControl::reset(PeripheralEnable::Ledc);
} else {
PeripheralClockControl::disable(PeripheralEnable::Ledc);
}
let ledc = LEDC::regs();
Ledc { _instance, ledc }
}
#[cfg(esp32)]
pub fn set_global_slow_clock(&mut self, _clock_source: LSGlobalClkSource) {
self.ledc.conf().write(|w| w.apb_clk_sel().set_bit());
self.ledc
.lstimer(0)
.conf()
.modify(|_, w| w.para_up().set_bit());
}
#[cfg(not(esp32))]
pub fn set_global_slow_clock(&mut self, clock_source: LSGlobalClkSource) {
#[cfg(any(esp32c6, esp32h2))]
let pcr = unsafe { &*crate::peripherals::PCR::ptr() };
#[cfg(any(esp32c6, esp32h2))]
pcr.ledc_sclk_conf().write(|w| w.ledc_sclk_en().set_bit());
match clock_source {
LSGlobalClkSource::APBClk => {
#[cfg(not(any(esp32c6, esp32h2)))]
self.ledc
.conf()
.write(|w| unsafe { w.apb_clk_sel().bits(1) });
#[cfg(esp32c6)]
pcr.ledc_sclk_conf()
.write(|w| unsafe { w.ledc_sclk_sel().bits(1) });
#[cfg(esp32h2)]
pcr.ledc_sclk_conf()
.write(|w| unsafe { w.ledc_sclk_sel().bits(0) });
}
}
self.ledc
.timer(0)
.conf()
.modify(|_, w| w.para_up().set_bit());
}
pub fn timer<S: TimerSpeed>(&self, number: timer::Number) -> Timer<'d, S> {
Timer::new(self.ledc, number)
}
pub fn channel<S: TimerSpeed>(
&self,
number: channel::Number,
output_pin: impl PeripheralOutput<'d>,
) -> Channel<'d, S> {
Channel::new(number, output_pin)
}
}