diff --git a/micro-rdk/src/esp32/pwm.rs b/micro-rdk/src/esp32/pwm.rs index 257bade57..41cb22217 100644 --- a/micro-rdk/src/esp32/pwm.rs +++ b/micro-rdk/src/esp32/pwm.rs @@ -1,8 +1,9 @@ use crate::esp32::esp_idf_svc::hal::gpio::AnyIOPin; use crate::esp32::esp_idf_svc::hal::gpio::Pin; use crate::esp32::esp_idf_svc::hal::ledc::{ - config::TimerConfig, LedcDriver, LedcTimerDriver, SpeedMode, CHANNEL0, CHANNEL1, CHANNEL2, - CHANNEL3, CHANNEL4, CHANNEL5, CHANNEL6, CHANNEL7, TIMER0, TIMER1, TIMER2, TIMER3, + config::TimerConfig, LedcDriver, LedcTimer, LedcTimerDriver, LowSpeed, SpeedMode, CHANNEL0, + CHANNEL1, CHANNEL2, CHANNEL3, CHANNEL4, CHANNEL5, CHANNEL6, CHANNEL7, TIMER0, TIMER1, TIMER2, + TIMER3, }; use crate::esp32::esp_idf_svc::hal::peripheral::Peripheral; use crate::esp32::esp_idf_svc::hal::prelude::FromValueType; @@ -56,23 +57,78 @@ enum PwmChannel { C7, } -fn get_ledc_driver_by_channel<'a>( +impl PwmChannel { + fn into_ledc_driver<'a, T>( + self, + timer: &LedcTimerDriver<'a, T>, + pin: AnyIOPin, + ) -> Result, Esp32PwmError> + where + T: LedcTimer, + { + crate::esp32::esp_idf_svc::hal::into_ref!(pin); + + Ok(match self { + Self::C0 => LedcDriver::new(unsafe { CHANNEL0::new() }, timer, pin)?, + Self::C1 => LedcDriver::new(unsafe { CHANNEL1::new() }, timer, pin)?, + Self::C2 => LedcDriver::new(unsafe { CHANNEL2::new() }, timer, pin)?, + Self::C3 => LedcDriver::new(unsafe { CHANNEL3::new() }, timer, pin)?, + Self::C4 => LedcDriver::new(unsafe { CHANNEL4::new() }, timer, pin)?, + Self::C5 => LedcDriver::new(unsafe { CHANNEL5::new() }, timer, pin)?, + Self::C6 => LedcDriver::new(unsafe { CHANNEL6::new() }, timer, pin)?, + Self::C7 => LedcDriver::new(unsafe { CHANNEL7::new() }, timer, pin)?, + }) + } +} + +fn get_ledc_driver_by_channel_by_timer<'a>( channel: PwmChannel, - timer: &LedcTimerDriver<'a>, + timer_opt: &LedcTimerOption<'a>, pin: AnyIOPin, ) -> Result, Esp32PwmError> { - crate::esp32::esp_idf_svc::hal::into_ref!(pin); - - Ok(match channel { - PwmChannel::C0 => LedcDriver::new(unsafe { CHANNEL0::new() }, timer, pin)?, - PwmChannel::C1 => LedcDriver::new(unsafe { CHANNEL1::new() }, timer, pin)?, - PwmChannel::C2 => LedcDriver::new(unsafe { CHANNEL2::new() }, timer, pin)?, - PwmChannel::C3 => LedcDriver::new(unsafe { CHANNEL3::new() }, timer, pin)?, - PwmChannel::C4 => LedcDriver::new(unsafe { CHANNEL4::new() }, timer, pin)?, - PwmChannel::C5 => LedcDriver::new(unsafe { CHANNEL5::new() }, timer, pin)?, - PwmChannel::C6 => LedcDriver::new(unsafe { CHANNEL6::new() }, timer, pin)?, - PwmChannel::C7 => LedcDriver::new(unsafe { CHANNEL7::new() }, timer, pin)?, - }) + match timer_opt { + LedcTimerOption::Timer0(timer) => channel.into_ledc_driver(timer, pin), + LedcTimerOption::Timer1(timer) => channel.into_ledc_driver(timer, pin), + LedcTimerOption::Timer2(timer) => channel.into_ledc_driver(timer, pin), + LedcTimerOption::Timer3(timer) => channel.into_ledc_driver(timer, pin), + } +} + +bitfield! { + struct PwmChannelInUse(u8); + impl Debug; + channels, _ : 7,0; +} + +impl From for PwmChannel { + fn from(value: u8) -> Self { + match value { + 0 => PwmChannel::C0, + 1 => PwmChannel::C1, + 2 => PwmChannel::C2, + 3 => PwmChannel::C3, + 4 => PwmChannel::C4, + 5 => PwmChannel::C5, + 6 => PwmChannel::C6, + 7 => PwmChannel::C7, + _ => unreachable!(), + } + } +} + +impl From for usize { + fn from(value: PwmChannel) -> Self { + match value { + PwmChannel::C0 => 0, + PwmChannel::C1 => 1, + PwmChannel::C2 => 2, + PwmChannel::C3 => 3, + PwmChannel::C4 => 4, + PwmChannel::C5 => 5, + PwmChannel::C6 => 6, + PwmChannel::C7 => 7, + } + } } pub(crate) struct PwmDriver<'a> { @@ -87,7 +143,7 @@ impl<'a> PwmDriver<'a> { let mut ledc_manager = LEDC_MANAGER.lock().unwrap(); let channel = ledc_manager.allocate_pin(pin.pin(), starting_frequency_hz)?; let timer = ledc_manager.get_configure_timer_instance(channel.1); - let ledc_driver = get_ledc_driver_by_channel(channel.0, timer, pin)?; + let ledc_driver = get_ledc_driver_by_channel_by_timer(channel.0, timer, pin)?; Ok(PwmDriver { ledc_driver, timer_number: channel.1 as usize, @@ -109,8 +165,7 @@ impl<'a> PwmDriver<'a> { pub fn get_timer_frequency(&self) -> u32 { let timer: ledc_timer_t = (self.timer_number as u8).into(); - // TODO(RSDK-10199): SpeedMode is now a trait in ESP-IDF 5 - unsafe { ledc_get_freq(SpeedMode::LowSpeed.into(), timer) } + unsafe { ledc_get_freq(LowSpeed::SPEED_MODE, timer) } } pub fn set_timer_frequency(&mut self, frequency_hz: u32) -> Result<(), Esp32PwmError> { @@ -129,39 +184,46 @@ impl Drop for PwmDriver<'_> { } } -bitfield! { - struct PwmChannelInUse(u8); - impl Debug; - channels, _ : 7,0; +pub enum LedcTimerOption<'a> { + Timer0(LedcTimerDriver<'a, TIMER0>), + Timer1(LedcTimerDriver<'a, TIMER1>), + Timer2(LedcTimerDriver<'a, TIMER2>), + Timer3(LedcTimerDriver<'a, TIMER3>), } -impl From for PwmChannel { - fn from(value: u8) -> Self { - match value { - 0 => PwmChannel::C0, - 1 => PwmChannel::C1, - 2 => PwmChannel::C2, - 3 => PwmChannel::C3, - 4 => PwmChannel::C4, - 5 => PwmChannel::C5, - 6 => PwmChannel::C6, - 7 => PwmChannel::C7, +impl<'a> LedcTimerOption<'a> { + pub fn new(timer: u8, conf: &TimerConfig) -> Result { + match timer { + 0 => { + let driver = LedcTimerDriver::new(unsafe { TIMER0::new() }, conf) + .map_err(Esp32PwmError::EspError)?; + Ok(Self::Timer0(driver)) + } + 1 => { + let driver = LedcTimerDriver::new(unsafe { TIMER1::new() }, conf) + .map_err(Esp32PwmError::EspError)?; + Ok(Self::Timer1(driver)) + } + 2 => { + let driver = LedcTimerDriver::new(unsafe { TIMER2::new() }, conf) + .map_err(Esp32PwmError::EspError)?; + Ok(Self::Timer2(driver)) + } + 3 => { + let driver = LedcTimerDriver::new(unsafe { TIMER3::new() }, conf) + .map_err(Esp32PwmError::EspError)?; + Ok(Self::Timer3(driver)) + } _ => unreachable!(), } } -} -impl From for usize { - fn from(value: PwmChannel) -> Self { - match value { - PwmChannel::C0 => 0, - PwmChannel::C1 => 1, - PwmChannel::C2 => 2, - PwmChannel::C3 => 3, - PwmChannel::C4 => 4, - PwmChannel::C5 => 5, - PwmChannel::C6 => 6, - PwmChannel::C7 => 7, + pub fn timer(&'a self) -> ledc_timer_t { + match self { + Self::Timer0(_) => TIMER0::timer(), + Self::Timer1(_) => TIMER1::timer(), + Self::Timer2(_) => TIMER2::timer(), + Self::Timer3(_) => TIMER3::timer(), } } } @@ -176,8 +238,7 @@ struct LedcManager<'a> { struct LedcTimerWrapper<'a> { frequency: u32, count: u8, - // TODO(RSDK-10192): LedcTimerDriver expects an additional template argument in ESP-IDF 5 - timer: OnceCell>, + timer: OnceCell>, } impl Debug for LedcTimerWrapper<'_> { @@ -190,24 +251,11 @@ impl Debug for LedcTimerWrapper<'_> { } } -fn create_timer_driver<'a>( - timer: u8, - conf: &TimerConfig, -) -> Result, Esp32PwmError> { - match timer { - 0 => LedcTimerDriver::new(unsafe { TIMER0::new() }, conf).map_err(Esp32PwmError::EspError), - 1 => LedcTimerDriver::new(unsafe { TIMER1::new() }, conf).map_err(Esp32PwmError::EspError), - 2 => LedcTimerDriver::new(unsafe { TIMER2::new() }, conf).map_err(Esp32PwmError::EspError), - 3 => LedcTimerDriver::new(unsafe { TIMER3::new() }, conf).map_err(Esp32PwmError::EspError), - _ => unreachable!(), - } -} - impl LedcTimerWrapper<'_> { fn new(id: u8, frequency_hz: u32) -> Result { let timer_config = TimerConfig::default().frequency(frequency_hz.Hz()); let timer = OnceCell::new(); - let _ = timer.set(create_timer_driver(id, &timer_config)?); + let _ = timer.set(LedcTimerOption::new(id, &timer_config)?); Ok(Self { count: 0, frequency: frequency_hz, @@ -232,7 +280,7 @@ impl LedcTimerWrapper<'_> { // We have to reconfigure the timer so the appropriate clock source for that frequency may be // selected. If no appropriate clock source exists the previous timer frequency // will be retained - match create_timer_driver(id, &timer_config) { + match LedcTimerOption::new(id, &timer_config) { Ok(driver) => { let _ = self.timer.set(driver); self.frequency = frequency_hz; @@ -242,7 +290,7 @@ impl LedcTimerWrapper<'_> { let timer_config = TimerConfig::default().frequency(self.frequency.Hz()); let _ = self.timer - .set(create_timer_driver(id, &timer_config).unwrap_or_else(|_| { + .set(LedcTimerOption::new(id, &timer_config).unwrap_or_else(|_| { panic!("bad frequency previously set on timer {:?}", id) })); Err(err) @@ -272,7 +320,7 @@ impl<'a> LedcManager<'a> { } } - fn get_configure_timer_instance<'d>(&'d self, timer_number: u32) -> &'d LedcTimerDriver<'a> { + fn get_configure_timer_instance<'d>(&'d self, timer_number: u32) -> &'d LedcTimerOption<'a> { self.timer_allocation[timer_number as usize] .timer .get() @@ -352,8 +400,7 @@ impl<'a> LedcManager<'a> { .ok_or(Esp32PwmError::NoTimersAvailable)?; unsafe { ledc_bind_channel_timer( - // TODO(RSDK-10199): SpeedMode is now a trait in ESP-IDF 5 - SpeedMode::LowSpeed.into(), + LowSpeed::SPEED_MODE, Into::::into(channel) as u32, new_timer as u32, )