From b017c8407ad9fe038e88f99e6d1a4815ea84baf0 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Tue, 2 Aug 2022 10:19:15 -0700 Subject: [PATCH] Refactor the LEDC driver to reduce code duplication --- .../src/ledc/{esp32 => }/channel.rs | 75 ++++- esp-hal-common/src/ledc/{esp32 => }/mod.rs | 57 ++-- esp-hal-common/src/ledc/others/channel.rs | 273 ------------------ esp-hal-common/src/ledc/others/mod.rs | 104 ------- esp-hal-common/src/ledc/others/timer.rs | 263 ----------------- esp-hal-common/src/ledc/{esp32 => }/timer.rs | 128 ++++++-- esp-hal-common/src/lib.rs | 4 - esp-hal-common/src/prelude.rs | 2 - 8 files changed, 210 insertions(+), 696 deletions(-) rename esp-hal-common/src/ledc/{esp32 => }/channel.rs (82%) rename esp-hal-common/src/ledc/{esp32 => }/mod.rs (70%) delete mode 100644 esp-hal-common/src/ledc/others/channel.rs delete mode 100644 esp-hal-common/src/ledc/others/mod.rs delete mode 100644 esp-hal-common/src/ledc/others/timer.rs rename esp-hal-common/src/ledc/{esp32 => }/timer.rs (72%) diff --git a/esp-hal-common/src/ledc/esp32/channel.rs b/esp-hal-common/src/ledc/channel.rs similarity index 82% rename from esp-hal-common/src/ledc/esp32/channel.rs rename to esp-hal-common/src/ledc/channel.rs index e44bff3f897..811b9db738d 100644 --- a/esp-hal-common/src/ledc/esp32/channel.rs +++ b/esp-hal-common/src/ledc/channel.rs @@ -1,14 +1,16 @@ use paste::paste; +#[cfg(feature = "esp32")] +use super::HighSpeed; use super::{ timer::{TimerIFace, TimerSpeed}, - HighSpeed, LowSpeed, }; use crate::{ gpio::{types::OutputSignal, OutputPin}, pac::ledc::RegisterBlock, }; + /// Channel errors #[derive(Debug)] pub enum Error { @@ -29,7 +31,9 @@ pub enum Number { Channel3, Channel4, Channel5, + #[cfg(not(feature = "esp32c3"))] Channel6, + #[cfg(not(feature = "esp32c3"))] Channel7, } @@ -115,7 +119,7 @@ where return Err(Error::Channel); } - let duty_range = 2_u32.pow(duty_exp); + let duty_range = 2u32.pow(duty_exp); let duty_value = (duty_range as f32 * duty_pct) as u32; if duty_value == 0 || duty_pct > 1.0 { @@ -130,9 +134,10 @@ where } } +#[cfg(feature = "esp32")] /// Macro to configure channel parameters in hw macro_rules! set_channel { - ( $self: ident, $speed: ident, $num: literal, $channel_number: ident ) => { + ($self: ident, $speed: ident, $num: literal, $channel_number: ident) => { paste! { $self.ledc.[<$speed sch $num _hpoint>] .write(|w| unsafe { w.[]().bits(0x0) }); @@ -158,9 +163,39 @@ macro_rules! set_channel { }; } +#[cfg(not(feature = "esp32"))] +/// Macro to configure channel parameters in hw +macro_rules! set_channel { + ($self: ident, $speed: ident, $num: literal, $channel_number: ident) => { + paste! { + $self.ledc.[] + .write(|w| unsafe { w.[]().bits(0x0) }); + $self.ledc.[].modify(|_, w| unsafe { + w.[]() + .set_bit() + .[]() + .bits($channel_number) + }); + $self.ledc.[].write(|w| unsafe { + w.[]() + .set_bit() + .[]() + .set_bit() + .[]() + .bits(0x1) + .[]() + .bits(0x1) + .[]() + .bits(0x0) + }); + } + }; +} + +#[cfg(feature = "esp32")] /// Macro to set duty parameters in hw macro_rules! set_duty { - ( $self: ident, $speed: ident, $num: literal, $duty: ident ) => { + ($self: ident, $speed: ident, $num: literal, $duty: ident) => { paste! { $self.ledc .[<$speed sch $num _duty>] @@ -169,9 +204,22 @@ macro_rules! set_duty { }; } +#[cfg(not(feature = "esp32"))] +/// Macro to set duty parameters in hw +macro_rules! set_duty { + ($self: ident, $speed: ident, $num: literal, $duty: ident) => { + paste! { + $self.ledc + .[] + .write(|w| unsafe { w.[]().bits($duty << 4) }) + } + }; +} + +#[cfg(feature = "esp32")] /// Macro to update channel configuration (only for LowSpeed channels) macro_rules! update_channel { - ( $self: ident, $num: literal) => { + ($self: ident, $num: literal) => { paste! { $self.ledc .[] @@ -180,6 +228,19 @@ macro_rules! update_channel { }; } +#[cfg(not(feature = "esp32"))] +/// Macro to update channel configuration (only for LowSpeed channels) +macro_rules! update_channel { + ($self: ident, $num: literal) => { + paste! { + $self.ledc + .[] + .modify(|_, w| w.[]().set_bit()); + } + }; +} + +#[cfg(feature = "esp32")] /// Channel HW interface for HighSpeed channels impl<'a, O> ChannelHW for Channel<'a, HighSpeed, O> where @@ -312,12 +373,14 @@ where self.output_pin .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG5); } + #[cfg(not(feature = "esp32c3"))] Number::Channel6 => { set_channel!(self, l, 6, channel_number); update_channel!(self, 6); self.output_pin .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG6); } + #[cfg(not(feature = "esp32c3"))] Number::Channel7 => { set_channel!(self, l, 7, channel_number); update_channel!(self, 7); @@ -341,7 +404,9 @@ where Number::Channel3 => set_duty!(self, l, 3, duty), Number::Channel4 => set_duty!(self, l, 4, duty), Number::Channel5 => set_duty!(self, l, 5, duty), + #[cfg(not(feature = "esp32c3"))] Number::Channel6 => set_duty!(self, l, 6, duty), + #[cfg(not(feature = "esp32c3"))] Number::Channel7 => set_duty!(self, l, 7, duty), }; } diff --git a/esp-hal-common/src/ledc/esp32/mod.rs b/esp-hal-common/src/ledc/mod.rs similarity index 70% rename from esp-hal-common/src/ledc/esp32/mod.rs rename to esp-hal-common/src/ledc/mod.rs index ece3cc15f87..70f94377278 100644 --- a/esp-hal-common/src/ledc/esp32/mod.rs +++ b/esp-hal-common/src/ledc/mod.rs @@ -1,16 +1,19 @@ //! LEDC (LED PWM Controller) peripheral control //! -//! Currently only supports fixed frequency output. Hardware fade support and -//! interrupts are not currently implemented. High Speed (only ESP32) and Low -//! Speed channels are available. +//! Currently only supports fixed-frequency output. Hardware fade support and +//! interrupts are not currently implemented. High Speed channels are availble +//! for the ESP32 only, while Low Speed channels are available for all supported +//! chips. //! //! # LowSpeed Example: +//! //! The following will configure the Low Speed Channel0 to 24kHz output with -//! 10% duty using the ABPClock ``` -//! let mut ledc = LEDC::new(&clock_control, &mut -//! system.peripheral_clock_control); +//! 10% duty using the ABPClock //! +//! ```rust,ignore +//! let mut ledc = LEDC::new(&clock_control, &mut system.peripheral_clock_control); //! ledc.set_global_slow_clock(LSGlobalClkSource::APBClk); +//! //! let mut lstimer0 = ledc.get_timer::(timer::Number::Timer0); //! lstimer0 //! .configure(timer::config::Config { @@ -28,11 +31,15 @@ //! }) //! .unwrap(); //! ``` -//! # HighSpeed (only ESP32) Example: +//! +//! # HighSpeed Example (ESP32 only): +//! //! The following will configure the High Speed Channel0 to 24kHz output with -//! 10% duty using the ABPClock ``` -//! let ledc = LEDC::new(&clock_control, &mut -//! system.peripheral_clock_control); +//! 10% duty using the ABPClock +//! +//! ```rust,ignore +//! let ledc = LEDC::new(&clock_control, &mut system.peripheral_clock_control); +//! //! let mut hstimer0 = ledc.get_timer::(timer::Number::Timer0); //! hstimer0 //! .configure(timer::config::Config { @@ -50,14 +57,17 @@ //! }) //! .unwrap(); //! ``` +//! //! # TODO +//! +//! - Source clock selection //! - Hardware fade support //! - Interrupts -use channel::Channel; -use timer::Timer; - -use self::timer::TimerSpeed; +use self::{ + channel::Channel, + timer::{Timer, TimerSpeed}, +}; use crate::{ clock::Clocks, gpio::OutputPin, @@ -79,13 +89,16 @@ pub struct LEDC<'a> { clock_control_config: &'a Clocks, } +#[cfg(feature = "esp32")] /// Used to specify HighSpeed Timer/Channel pub struct HighSpeed {} + /// Used to specify LowSpeed Timer/Channel pub struct LowSpeed {} pub trait Speed {} +#[cfg(feature = "esp32")] impl Speed for HighSpeed {} impl Speed for LowSpeed {} @@ -103,11 +116,21 @@ impl<'a> LEDC<'a> { } /// Set global slow clock source + #[cfg(feature = "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 - .lstimer0_conf - .modify(|_, w| w.para_up().set_bit()); + self.ledc.lstimer0_conf.modify(|_, w| w.para_up().set_bit()); + } + + #[cfg(not(feature = "esp32"))] + /// Set global slow clock source + pub fn set_global_slow_clock(&mut self, clock_source: LSGlobalClkSource) { + match clock_source { + LSGlobalClkSource::APBClk => { + self.ledc.conf.write(|w| unsafe { w.apb_clk_sel().bits(1) }) + } + } + self.ledc.timer0_conf.modify(|_, w| w.para_up().set_bit()); } /// Return a new timer diff --git a/esp-hal-common/src/ledc/others/channel.rs b/esp-hal-common/src/ledc/others/channel.rs deleted file mode 100644 index c875cfe6f20..00000000000 --- a/esp-hal-common/src/ledc/others/channel.rs +++ /dev/null @@ -1,273 +0,0 @@ -use paste::paste; - -use super::{ - timer::{TimerIFace, TimerSpeed}, - LowSpeed, -}; -use crate::{ - gpio::{types::OutputSignal, OutputPin}, - pac::ledc::RegisterBlock, -}; -/// Channel errors -#[derive(Debug)] -pub enum Error { - /// Invalid duty % value - Duty, - /// Timer not configured - Timer, - /// Channel not configured - Channel, -} - -/// Channel number -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub enum Number { - Channel0, - Channel1, - Channel2, - Channel3, - Channel4, - Channel5, - #[cfg(not(feature = "esp32c3"))] - Channel6, - #[cfg(not(feature = "esp32c3"))] - Channel7, -} - -/// Channel configuration -pub mod config { - use crate::ledc::timer::{TimerIFace, TimerSpeed}; - - /// Channel configuration - #[derive(Copy, Clone)] - pub struct Config<'a, S: TimerSpeed> { - pub timer: &'a dyn TimerIFace, - pub duty_pct: f32, - } -} - -/// Channel interface -pub trait ChannelIFace<'a, S: TimerSpeed + 'a, O: OutputPin> -where - Channel<'a, S, O>: ChannelHW, -{ - /// Configure channel - fn configure(&mut self, config: config::Config<'a, S>) -> Result<(), Error>; - - /// Set channel duty HW - fn set_duty(&self, duty_pct: f32) -> Result<(), Error>; -} - -/// Channel HW interface -pub trait ChannelHW { - /// Configure Channel HW except for the duty which is set via - /// [`Self::set_duty_hw`]. - fn configure_hw(&mut self) -> Result<(), Error>; - - /// Set channel duty HW - fn set_duty_hw(&self, duty: u32); -} - -/// Channel struct -pub struct Channel<'a, S: TimerSpeed, O: OutputPin> { - ledc: &'a RegisterBlock, - timer: Option<&'a dyn TimerIFace>, - number: Number, - output_pin: O, -} - -impl<'a, S: TimerSpeed, O: OutputPin> Channel<'a, S, O> { - /// Return a new channel - pub fn new(number: Number, output_pin: O) -> Self { - let ledc = unsafe { &*crate::pac::LEDC::ptr() }; - Channel { - ledc, - timer: None, - number, - output_pin, - } - } -} - -impl<'a, S: TimerSpeed, O: OutputPin> ChannelIFace<'a, S, O> for Channel<'a, S, O> -where - Channel<'a, S, O>: ChannelHW, -{ - /// Configure channel - fn configure(&mut self, config: config::Config<'a, S>) -> Result<(), Error> { - self.timer = Some(config.timer); - - self.set_duty(config.duty_pct)?; - self.configure_hw()?; - - Ok(()) - } - - /// Set duty % of channel - fn set_duty(&self, duty_pct: f32) -> Result<(), Error> { - let duty_exp; - if let Some(timer) = self.timer { - if let Some(timer_duty) = timer.get_duty() { - duty_exp = timer_duty as u32; - } else { - return Err(Error::Timer); - } - } else { - return Err(Error::Channel); - } - - let duty_range = 2_u32.pow(duty_exp); - let duty_value = (duty_range as f32 * duty_pct) as u32; - - if duty_value == 0 || duty_pct > 1.0 { - // Not enough bits to represent the requested duty % or duty_pct greater than - // 1.0 - return Err(Error::Duty); - } - - self.set_duty_hw(duty_value); - - Ok(()) - } -} - -/// Macro to configure channel parameters in hw -macro_rules! set_channel { - ( $self: ident, $speed: ident, $num: literal, $channel_number: ident ) => { - paste! { - $self.ledc.[] - .write(|w| unsafe { w.[]().bits(0x0) }); - $self.ledc.[].modify(|_, w| unsafe { - w.[]() - .set_bit() - .[]() - .bits($channel_number) - }); - $self.ledc.[].write(|w| unsafe { - w.[]() - .set_bit() - .[]() - .set_bit() - .[]() - .bits(0x1) - .[]() - .bits(0x1) - .[]() - .bits(0x0) - }); - } - }; -} - -/// Macro to set duty parameters in hw -macro_rules! set_duty { - ( $self: ident, $speed: ident, $num: literal, $duty: ident ) => { - paste! { - $self.ledc - .[] - .write(|w| unsafe { w.[]().bits($duty << 4) }) - } - }; -} - -/// Macro to update channel configuration (only for LowSpeed channels) -macro_rules! update_channel { - ( $self: ident, $num: literal) => { - paste! { - $self.ledc - .[] - .modify(|_, w| w.[]().set_bit()); - } - }; -} - -/// Channel HW interface for LowSpeed channels -impl<'a, O: OutputPin> ChannelHW for Channel<'a, LowSpeed, O> -where - O: OutputPin, -{ - /// Configure Channel HW - fn configure_hw(&mut self) -> Result<(), Error> { - if let Some(timer) = self.timer { - if !timer.is_configured() { - return Err(Error::Timer); - } - - self.output_pin.set_to_push_pull_output(); - - let channel_number = timer.get_number() as u8; - match self.number { - Number::Channel0 => { - set_channel!(self, l, 0, channel_number); - update_channel!(self, 0); - self.output_pin - .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG0); - } - Number::Channel1 => { - set_channel!(self, l, 1, channel_number); - update_channel!(self, 1); - self.output_pin - .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG1); - } - Number::Channel2 => { - set_channel!(self, l, 2, channel_number); - update_channel!(self, 2); - self.output_pin - .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG2); - } - Number::Channel3 => { - set_channel!(self, l, 3, channel_number); - update_channel!(self, 3); - self.output_pin - .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG3); - } - Number::Channel4 => { - set_channel!(self, l, 4, channel_number); - update_channel!(self, 4); - self.output_pin - .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG4); - } - Number::Channel5 => { - set_channel!(self, l, 5, channel_number); - update_channel!(self, 5); - self.output_pin - .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG5); - } - #[cfg(not(feature = "esp32c3"))] - Number::Channel6 => { - set_channel!(self, l, 6, channel_number); - update_channel!(self, 6); - self.output_pin - .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG6); - } - #[cfg(not(feature = "esp32c3"))] - Number::Channel7 => { - set_channel!(self, l, 7, channel_number); - update_channel!(self, 7); - self.output_pin - .connect_peripheral_to_output(OutputSignal::LEDC_LS_SIG7); - } - } - } else { - return Err(Error::Timer); - } - - Ok(()) - } - - /// Set duty in channel HW - fn set_duty_hw(&self, duty: u32) { - match self.number { - Number::Channel0 => set_duty!(self, l, 0, duty), - Number::Channel1 => set_duty!(self, l, 1, duty), - Number::Channel2 => set_duty!(self, l, 2, duty), - Number::Channel3 => set_duty!(self, l, 3, duty), - Number::Channel4 => set_duty!(self, l, 4, duty), - Number::Channel5 => set_duty!(self, l, 5, duty), - #[cfg(not(feature = "esp32c3"))] - Number::Channel6 => set_duty!(self, l, 6, duty), - #[cfg(not(feature = "esp32c3"))] - Number::Channel7 => set_duty!(self, l, 7, duty), - }; - } -} diff --git a/esp-hal-common/src/ledc/others/mod.rs b/esp-hal-common/src/ledc/others/mod.rs deleted file mode 100644 index 60e64f71cbe..00000000000 --- a/esp-hal-common/src/ledc/others/mod.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! LEDC (LED PWM Controller) peripheral control -//! -//! Currently only supports fixed frequency output. Hardware fade support and -//! interrupts are not currently implemented. Low Speed channels are available. -//! -//! # LowSpeed Example: -//! The following will configure the Low Speed Channel0 to 24kHz output with -//! 10% duty using the ABPClock ``` -//! let mut ledc = LEDC::new(&clock_control, &mut -//! system.peripheral_clock_control); -//! -//! ledc.set_global_slow_clock(LSGlobalClkSource::APBClk); -//! let mut lstimer0 = ledc.get_timer::(timer::Number::Timer0); -//! lstimer0 -//! .configure(timer::config::Config { -//! duty: timer::config::Duty::Duty5Bit, -//! clock_source: timer::LSClockSource::APBClk, -//! frequency: 24u32.kHz(), -//! }) -//! .unwrap(); -//! -//! let mut channel0 = ledc.get_channel(channel::Number::Channel0, led); -//! channel0 -//! .configure(channel::config::Config { -//! timer: &lstimer0, -//! duty: 0.1, -//! }) -//! .unwrap(); -//! ``` -//! # TODO -//! - Hardware fade support -//! - Interrupts - -use channel::Channel; -use timer::Timer; - -use self::timer::TimerSpeed; -use crate::{ - clock::Clocks, - gpio::OutputPin, - system::{Peripheral, PeripheralClockControl}, -}; - -pub mod channel; -pub mod timer; - -/// Global slow clock source -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub enum LSGlobalClkSource { - APBClk, -} - -/// LEDC (LED PWM Controller) -pub struct LEDC<'a> { - ledc: &'a crate::pac::ledc::RegisterBlock, - clock_control_config: &'a Clocks, -} - -/// Used to specify LowSpeed Timer/Channel -pub struct LowSpeed {} - -pub trait Speed {} - - -impl Speed for LowSpeed {} - -impl<'a> LEDC<'a> { - /// Return a new LEDC - pub fn new(clock_control_config: &'a Clocks, system: &mut PeripheralClockControl) -> Self { - system.enable(Peripheral::Ledc); - - let ledc = unsafe { &*crate::pac::LEDC::ptr() }; - LEDC { - ledc, - clock_control_config, - } - } - - /// Set global slow clock source - pub fn set_global_slow_clock(&mut self, _clock_source: LSGlobalClkSource) { - match _clock_source { - LSGlobalClkSource::APBClk => { - self.ledc.conf.write(|w| unsafe { w.apb_clk_sel().bits(1) }) - } /* LSGlobalClkSource::XTALClk => { - * self.ledc.conf.write(|w| unsafe { w.apb_clk_sel().bits(3) }) - * } */ - } - self.ledc.timer0_conf.modify(|_, w| w.para_up().set_bit()); - } - - /// Return a new timer - pub fn get_timer(&self, number: timer::Number) -> Timer { - Timer::new(self.ledc, self.clock_control_config, number) - } - - /// Return a new channel - pub fn get_channel( - &self, - number: channel::Number, - output_pin: O, - ) -> Channel { - Channel::new(number, output_pin) - } -} diff --git a/esp-hal-common/src/ledc/others/timer.rs b/esp-hal-common/src/ledc/others/timer.rs deleted file mode 100644 index 644c68d80e9..00000000000 --- a/esp-hal-common/src/ledc/others/timer.rs +++ /dev/null @@ -1,263 +0,0 @@ -use super::{LowSpeed, Speed}; -use crate::{clock::Clocks, pac::ledc, prelude::_fugit_MegahertzU32}; -/// Timer errors -#[derive(Debug)] -pub enum Error { - /// Invalid Divisor - Divisor, -} - -/// Clock source for LS Timers -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub enum LSClockSource { - APBClk, - // TODO SLOWClk - // SLOWClk, -} - -/// Timer number -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub enum Number { - Timer0, - Timer1, - Timer2, - Timer3, -} - -/// Timer configuration -pub mod config { - - use crate::prelude::_fugit_HertzU32; - - /// Number of bits reserved for duty cycle adjustment - #[derive(PartialEq, Eq, Copy, Clone, Debug)] - pub enum Duty { - Duty1Bit = 1, - Duty2Bit, - Duty3Bit, - Duty4Bit, - Duty5Bit, - Duty6Bit, - Duty7Bit, - Duty8Bit, - Duty9Bit, - Duty10Bit, - Duty11Bit, - Duty12Bit, - Duty13Bit, - Duty14Bit, - } - - /// Timer configuration - #[derive(Copy, Clone)] - pub struct Config { - pub duty: Duty, - pub clock_source: CS, - pub frequency: _fugit_HertzU32, - } -} - -/// Trait defining the type of timer source -pub trait TimerSpeed: Speed { - type ClockSourceType; -} - -/// Timer source type for LowSpeed timers -impl TimerSpeed for LowSpeed { - type ClockSourceType = LSClockSource; -} - -/// Interface for Timers -pub trait TimerIFace { - /// Return the frequency of the timer - fn get_freq(&self) -> Option<_fugit_MegahertzU32>; - - /// Configure the timer - fn configure(&mut self, config: config::Config) -> Result<(), Error>; - - /// Check if the timer has been configured - fn is_configured(&self) -> bool; - - /// Return the duty resolution of the timer - fn get_duty(&self) -> Option; - - /// Return the timer number - fn get_number(&self) -> Number; -} - -/// Interface for HW configuration of timer -pub trait TimerHW { - /// Get the current source timer frequency from the HW - fn get_freq_hw(&self) -> Option<_fugit_MegahertzU32>; - - /// Configure the HW for the timer - fn configure_hw(&self, divisor: u32); - - /// Update the timer in HW - fn update_hw(&self); -} - -/// Timer struct -pub struct Timer<'a, S: TimerSpeed> { - ledc: &'a crate::pac::ledc::RegisterBlock, - clock_control_config: &'a Clocks, - number: Number, - duty: Option, - configured: bool, - clock_source: Option, -} - -impl<'a, S: TimerSpeed> TimerIFace for Timer<'a, S> -where - Timer<'a, S>: TimerHW, -{ - /// Return the frequency of the timer - fn get_freq(&self) -> Option<_fugit_MegahertzU32> { - self.get_freq_hw() - } - - /// Configure the timer - fn configure(&mut self, config: config::Config) -> 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 = 2_u64.pow(config.duty as u32); - let frequency: u32 = config.frequency.raw(); - - let divisor = (((src_freq as u64) << 8) + ((frequency as u64 * precision) / 2)) - / (frequency as u64 * precision); - - if divisor >= 0x10_0000 || divisor == 0 { - return Err(Error::Divisor); - } - - self.configure_hw(divisor as u32); - self.update_hw(); - - self.configured = true; - - Ok(()) - } - - /// Check if the timer has been configured - fn is_configured(&self) -> bool { - self.configured - } - - /// Return the duty resolution of the timer - fn get_duty(&self) -> Option { - self.duty - } - - /// Return the timer number - fn get_number(&self) -> Number { - self.number - } -} - -impl<'a, S: TimerSpeed> Timer<'a, S> { - /// Create a new intance of a timer - pub fn new( - ledc: &'a ledc::RegisterBlock, - clock_control_config: &'a Clocks, - number: Number, - ) -> Self { - Timer { - ledc, - clock_control_config, - number, - duty: None, - configured: false, - clock_source: None, - } - } - - // TODO This function will be relevant when we add other clk sources - // Helper function that return the current frequency of the LowSpeed global - // source - // fn get_slow_clock_freq(&self) -> _fugit_MegahertzU32 { - // if self.ledc.conf.read().apb_clk_sel().bit_is_clear() { - // 8u32.MHz().into() - // } else { - // // 80u32.MHz().into() - // self.clock_control_config.apb_clock - // } - // } -} - -/// Timer HW implementation for LowSpeed timers -impl<'a> TimerHW for Timer<'a, LowSpeed> { - /// Get the current source timer frequency from the HW - fn get_freq_hw(&self) -> Option<_fugit_MegahertzU32> { - self.clock_source.map(|cs| match cs { - LSClockSource::APBClk => self.clock_control_config.apb_clock, - }) - } - - /// Configure the HW for the timer - fn configure_hw(&self, divisor: u32) { - let duty = self.duty.unwrap() as u8; - let sel_lstimer = self.clock_source.unwrap() == LSClockSource::APBClk; - match self.number { - Number::Timer0 => self.ledc.timer0_conf.modify(|_, w| unsafe { - w.tick_sel() - .bit(sel_lstimer) - .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(sel_lstimer) - .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(sel_lstimer) - .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(sel_lstimer) - .rst() - .clear_bit() - .pause() - .clear_bit() - .clk_div() - .bits(divisor) - .duty_res() - .bits(duty) - }), - }; - } - - /// Update the timer in HW - 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()), - }; - } -} diff --git a/esp-hal-common/src/ledc/esp32/timer.rs b/esp-hal-common/src/ledc/timer.rs similarity index 72% rename from esp-hal-common/src/ledc/esp32/timer.rs rename to esp-hal-common/src/ledc/timer.rs index 3dc0eeb6806..0cd671d2866 100644 --- a/esp-hal-common/src/ledc/esp32/timer.rs +++ b/esp-hal-common/src/ledc/timer.rs @@ -1,5 +1,10 @@ +use fugit::MegahertzU32; + +#[cfg(feature = "esp32")] +use super::HighSpeed; use super::{LowSpeed, Speed}; -use crate::{clock::Clocks, pac::ledc, prelude::_fugit_MegahertzU32}; +use crate::{clock::Clocks, pac::ledc}; + /// Timer errors #[derive(Debug)] pub enum Error { @@ -7,13 +12,12 @@ pub enum Error { Divisor, } -use super::HighSpeed; - +#[cfg(feature = "esp32")] /// Clock source for HS Timers #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum HSClockSource { - // TODO RefTick, APBClk, + // TODO RefTick, } /// Clock source for LS Timers @@ -21,7 +25,6 @@ pub enum HSClockSource { pub enum LSClockSource { APBClk, // TODO SLOWClk - // SLOWClk, } /// Timer number @@ -35,8 +38,7 @@ pub enum Number { /// Timer configuration pub mod config { - - use crate::prelude::_fugit_HertzU32; + use fugit::HertzU32; /// Number of bits reserved for duty cycle adjustment #[derive(PartialEq, Eq, Copy, Clone, Debug)] @@ -55,11 +57,17 @@ pub mod config { Duty12Bit, Duty13Bit, Duty14Bit, + #[cfg(feature = "esp32")] Duty15Bit, + #[cfg(feature = "esp32")] Duty16Bit, + #[cfg(feature = "esp32")] Duty17Bit, + #[cfg(feature = "esp32")] Duty18Bit, + #[cfg(feature = "esp32")] Duty19Bit, + #[cfg(feature = "esp32")] Duty20Bit, } @@ -68,7 +76,7 @@ pub mod config { pub struct Config { pub duty: Duty, pub clock_source: CS, - pub frequency: _fugit_HertzU32, + pub frequency: HertzU32, } } @@ -82,6 +90,7 @@ impl TimerSpeed for LowSpeed { type ClockSourceType = LSClockSource; } +#[cfg(feature = "esp32")] /// Timer source type for HighSpeed timers impl TimerSpeed for HighSpeed { type ClockSourceType = HSClockSource; @@ -90,7 +99,7 @@ impl TimerSpeed for HighSpeed { /// Interface for Timers pub trait TimerIFace { /// Return the frequency of the timer - fn get_freq(&self) -> Option<_fugit_MegahertzU32>; + fn get_freq(&self) -> Option; /// Configure the timer fn configure(&mut self, config: config::Config) -> Result<(), Error>; @@ -108,7 +117,7 @@ pub trait TimerIFace { /// Interface for HW configuration of timer pub trait TimerHW { /// Get the current source timer frequency from the HW - fn get_freq_hw(&self) -> Option<_fugit_MegahertzU32>; + fn get_freq_hw(&self) -> Option; /// Configure the HW for the timer fn configure_hw(&self, divisor: u32); @@ -132,7 +141,7 @@ where Timer<'a, S>: TimerHW, { /// Return the frequency of the timer - fn get_freq(&self) -> Option<_fugit_MegahertzU32> { + fn get_freq(&self) -> Option { self.get_freq_hw() } @@ -141,8 +150,9 @@ where self.duty = Some(config.duty); self.clock_source = Some(config.clock_source); + // TODO: we should return some error here if `unwrap()` fails let src_freq: u32 = self.get_freq().unwrap().to_Hz(); - let precision = 2_u64.pow(config.duty as u32); + let precision = 2u64.pow(config.duty as u32); let frequency: u32 = config.frequency.raw(); let divisor = (((src_freq as u64) << 8) + ((frequency as u64 * precision) / 2)) @@ -192,33 +202,23 @@ impl<'a, S: TimerSpeed> Timer<'a, S> { clock_source: None, } } - - // TODO This function will be relevant when we add other clk sources - // Helper function that return the current frequency of the LowSpeed global - // source - // fn get_slow_clock_freq(&self) -> _fugit_MegahertzU32 { - // if self.ledc.conf.read().apb_clk_sel().bit_is_clear() { - // 8u32.MHz().into() - // } else { - // // 80u32.MHz().into() - // self.clock_control_config.apb_clock - // } - // } } /// Timer HW implementation for LowSpeed timers impl<'a> TimerHW for Timer<'a, LowSpeed> { /// Get the current source timer frequency from the HW - fn get_freq_hw(&self) -> Option<_fugit_MegahertzU32> { + fn get_freq_hw(&self) -> Option { self.clock_source.map(|cs| match cs { LSClockSource::APBClk => self.clock_control_config.apb_clock, }) } + #[cfg(feature = "esp32")] /// Configure the HW for the timer fn configure_hw(&self, divisor: u32) { let duty = self.duty.unwrap() as u8; - let sel_lstimer = self.clock_source.unwrap() == LSClockSource::APBClk; + let sel_lstimer = self.clock_source == Some(LSClockSource::APBClk); + match self.number { Number::Timer0 => self.ledc.lstimer0_conf.modify(|_, w| unsafe { w.tick_sel() @@ -271,6 +271,65 @@ impl<'a> TimerHW for Timer<'a, LowSpeed> { }; } + #[cfg(not(feature = "esp32"))] + /// Configure the HW for the timer + fn configure_hw(&self, divisor: u32) { + let duty = self.duty.unwrap() as u8; + let sel_lstimer = self.clock_source == Some(LSClockSource::APBClk); + + match self.number { + Number::Timer0 => self.ledc.timer0_conf.modify(|_, w| unsafe { + w.tick_sel() + .bit(sel_lstimer) + .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(sel_lstimer) + .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(sel_lstimer) + .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(sel_lstimer) + .rst() + .clear_bit() + .pause() + .clear_bit() + .clk_div() + .bits(divisor) + .duty_res() + .bits(duty) + }), + }; + } + + #[cfg(feature = "esp32")] /// Update the timer in HW fn update_hw(&self) { match self.number { @@ -280,12 +339,24 @@ impl<'a> TimerHW for Timer<'a, LowSpeed> { Number::Timer3 => self.ledc.lstimer3_conf.modify(|_, w| w.para_up().set_bit()), }; } + + #[cfg(not(feature = "esp32"))] + /// Update the timer in HW + 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(feature = "esp32")] /// Timer HW implementation for HighSpeed timers impl<'a> TimerHW for Timer<'a, HighSpeed> { /// Get the current source timer frequency from the HW - fn get_freq_hw(&self) -> Option<_fugit_MegahertzU32> { + fn get_freq_hw(&self) -> Option { self.clock_source.map(|cs| match cs { // TODO RefTick HSClockSource::RefTick => self.clock_control_config.apb_clock, HSClockSource::APBClk => self.clock_control_config.apb_clock, @@ -295,7 +366,8 @@ impl<'a> TimerHW for Timer<'a, HighSpeed> { /// Configure the HW for the timer fn configure_hw(&self, divisor: u32) { let duty = self.duty.unwrap() as u8; - let sel_hstimer = self.clock_source.unwrap() == HSClockSource::APBClk; + let sel_hstimer = self.clock_source == Some(HSClockSource::APBClk); + match self.number { Number::Timer0 => self.ledc.hstimer0_conf.modify(|_, w| unsafe { w.tick_sel() diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index 30d4b84430a..e42b9a08b61 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -40,10 +40,6 @@ pub mod i2c; #[cfg_attr(target_arch = "riscv32", path = "interrupt/riscv.rs")] #[cfg_attr(target_arch = "xtensa", path = "interrupt/xtensa.rs")] pub mod interrupt; -#[cfg_attr(feature = "esp32", path = "ledc/esp32/mod.rs")] -#[cfg_attr(feature = "esp32c3", path = "ledc/others/mod.rs")] -#[cfg_attr(feature = "esp32s2", path = "ledc/others/mod.rs")] -#[cfg_attr(feature = "esp32s3", path = "ledc/others/mod.rs")] pub mod ledc; pub mod prelude; pub mod pulse_control; diff --git a/esp-hal-common/src/prelude.rs b/esp-hal-common/src/prelude.rs index 98c64b4fb93..7d29d73eff8 100644 --- a/esp-hal-common/src/prelude.rs +++ b/esp-hal-common/src/prelude.rs @@ -15,8 +15,6 @@ pub use embedded_hal::{ pub use fugit::{ ExtU32 as _fugit_ExtU32, ExtU64 as _fugit_ExtU64, - HertzU32 as _fugit_HertzU32, - MegahertzU32 as _fugit_MegahertzU32, RateExtU32 as _fugit_RateExtU32, RateExtU64 as _fugit_RateExtU64, };