Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the LEDC driver to reduce duplicated code #130

Merged
merged 1 commit into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -29,7 +31,9 @@ pub enum Number {
Channel3,
Channel4,
Channel5,
#[cfg(not(feature = "esp32c3"))]
Channel6,
#[cfg(not(feature = "esp32c3"))]
Channel7,
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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.[<hpoint>]().bits(0x0) });
Expand All @@ -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.[<ch $num _hpoint>]
.write(|w| unsafe { w.[<hpoint>]().bits(0x0) });
$self.ledc.[<ch $num _conf0>].modify(|_, w| unsafe {
w.[<sig_out_en>]()
.set_bit()
.[<timer_sel>]()
.bits($channel_number)
});
$self.ledc.[<ch $num _conf1>].write(|w| unsafe {
w.[<duty_start>]()
.set_bit()
.[<duty_inc>]()
.set_bit()
.[<duty_num>]()
.bits(0x1)
.[<duty_cycle>]()
.bits(0x1)
.[<duty_scale>]()
.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>]
Expand All @@ -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
.[<ch $num _duty>]
.write(|w| unsafe { w.[<duty>]().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
.[<lsch $num _conf0>]
Expand All @@ -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
.[<ch $num _conf0>]
.modify(|_, w| w.[<para_up>]().set_bit());
}
};
}

#[cfg(feature = "esp32")]
/// Channel HW interface for HighSpeed channels
impl<'a, O> ChannelHW<O> for Channel<'a, HighSpeed, O>
where
Expand Down Expand Up @@ -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);
Expand All @@ -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),
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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::<LowSpeed>(timer::Number::Timer0);
//! lstimer0
//! .configure(timer::config::Config {
Expand All @@ -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::<HighSpeed>(timer::Number::Timer0);
//! hstimer0
//! .configure(timer::config::Config {
Expand All @@ -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,
Expand All @@ -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 {}
Expand All @@ -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
Expand Down
Loading