diff --git a/CHANGELOG.md b/CHANGELOG.md index f63b56b15a0..603c0c179dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Implement Copy and Eq for EspTwaiError (#540) - Add LEDC hardware fade support - Added support for multicore async GPIO (#542) +- Add initial support for MCPWM in ESP32-H2 (#544) ### Fixed diff --git a/esp-hal-common/devices/esp32h2.toml b/esp-hal-common/devices/esp32h2.toml index 58e97758478..2a8df6e750a 100644 --- a/esp-hal-common/devices/esp32h2.toml +++ b/esp-hal-common/devices/esp32h2.toml @@ -29,7 +29,7 @@ peripherals = [ # "lp_peri", # "lp_timer", "lp_wdt", - # "mcpwm0", + "mcpwm0", # "mem_monitor", # "modem_lpcon", # "modem_syscon", diff --git a/esp-hal-common/src/mcpwm/mod.rs b/esp-hal-common/src/mcpwm/mod.rs index e43b633f885..9acc6f0a493 100644 --- a/esp-hal-common/src/mcpwm/mod.rs +++ b/esp-hal-common/src/mcpwm/mod.rs @@ -134,6 +134,22 @@ impl<'d, PWM: PwmPeripheral> MCPWM<'d, PWM> { // TODO: Add other clock sources } + #[cfg(esp32h2)] + { + unsafe { &*crate::peripherals::PCR::PTR } + .pwm_clk_conf + .modify(|_, w| unsafe { + w.pwm_div_num() + .variant(peripheral_clock.prescaler) + .pwm_clkm_en() + .set_bit() + .pwm_clkm_sel() + .bits(0) + }); + + // TODO: Add other clock sources + } + Self { _inner: peripheral, timer0: Timer::new(), @@ -169,6 +185,8 @@ impl<'a> PeripheralClockConfig<'a> { let source_clock = clocks.crypto_clock; #[cfg(esp32s3)] let source_clock = clocks.crypto_pwm_clock; + #[cfg(esp32h2)] + let source_clock = clocks.xtal_clock; Self { frequency: source_clock / (prescaler as u32 + 1), @@ -201,6 +219,8 @@ impl<'a> PeripheralClockConfig<'a> { let source_clock = clocks.crypto_clock; #[cfg(esp32s3)] let source_clock = clocks.crypto_pwm_clock; + #[cfg(esp32h2)] + let source_clock = clocks.xtal_clock; if target_freq.raw() == 0 || target_freq > source_clock { return Err(FrequencyError); diff --git a/esp-hal-common/src/mcpwm/operator.rs b/esp-hal-common/src/mcpwm/operator.rs index e0541caed90..f35e5884141 100644 --- a/esp-hal-common/src/mcpwm/operator.rs +++ b/esp-hal-common/src/mcpwm/operator.rs @@ -224,7 +224,7 @@ impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> } /// Set how a new timestamp syncs with the timer - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] pub fn set_update_method(&mut self, update_method: PwmUpdateMethod) { // SAFETY: // We only write to our GENx_x_UPMETHOD register @@ -300,7 +300,7 @@ impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> /// Write a new timestamp. /// The written value will take effect according to the set /// [`PwmUpdateMethod`]. - #[cfg(esp32c6)] + #[cfg(any(esp32c6, esp32h2))] pub fn set_timestamp(&mut self, value: u16) { // SAFETY: // We only write to our GENx_TSTMP_x register diff --git a/esp-hal-common/src/soc/esp32h2/gpio.rs b/esp-hal-common/src/soc/esp32h2/gpio.rs index 9ceffc6a367..a39c39165f5 100644 --- a/esp-hal-common/src/soc/esp32h2/gpio.rs +++ b/esp-hal-common/src/soc/esp32h2/gpio.rs @@ -183,12 +183,12 @@ pub enum OutputSignal { GPIO_SD1 = 84, GPIO_SD2 = 85, GPIO_SD3 = 86, - PWM0_OUT0A = 87, - PWM0_OUT0B = 88, - PWM0_OUT1A = 89, - PWM0_OUT1B = 90, - PWM0_OUT2A = 91, - PWM0_OUT2B = 92, + PWM0_0A = 87, + PWM0_0B = 88, + PWM0_1A = 89, + PWM0_1B = 90, + PWM0_2A = 91, + PWM0_2B = 92, SIG_IN_FUNC97 = 97, SIG_IN_FUNC98 = 98, SIG_IN_FUNC99 = 99, diff --git a/esp-hal-common/src/soc/esp32h2/peripherals.rs b/esp-hal-common/src/soc/esp32h2/peripherals.rs index 73b3357cc00..27841107d59 100644 --- a/esp-hal-common/src/soc/esp32h2/peripherals.rs +++ b/esp-hal-common/src/soc/esp32h2/peripherals.rs @@ -31,7 +31,7 @@ crate::peripherals! { // LP_PERI => true, // LP_TIMER => true, LP_WDT => true, - // MCPWM0 => true, + MCPWM0 => true, // MEM_MONITOR => true, // MODEM_LPCON => true, // MODEM_SYSCON => true, diff --git a/esp32h2-hal/examples/mcpwm.rs b/esp32h2-hal/examples/mcpwm.rs new file mode 100644 index 00000000000..e63d42cf480 --- /dev/null +++ b/esp32h2-hal/examples/mcpwm.rs @@ -0,0 +1,79 @@ +//! Uses timer0 and operator0 of the MCPWM0 +//! +//! to output a 50% duty +//! signal at 16 kHz. +//! +//! The signal will be output to the pin assigned to `pin`. (GPIO4) + +#![no_std] +#![no_main] + +use esp32h2_hal::{ + clock::ClockControl, + gpio::IO, + mcpwm::{operator::PwmPinConfig, timer::PwmWorkingMode, PeripheralClockConfig, MCPWM}, + peripherals::Peripherals, + prelude::*, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.PCR.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + // Disable the watchdog timers. For the ESP32-H2, this includes the Super WDT, + // and the TIMG WDTs. + let mut rtc = Rtc::new(peripherals.LP_CLKRST); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + // Disable watchdog timers + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + let pin = io.pins.gpio4; + + // initialize peripheral + let clock_cfg = PeripheralClockConfig::with_frequency(&clocks, 32u32.MHz()).unwrap(); + let mut mcpwm = MCPWM::new( + peripherals.MCPWM0, + clock_cfg, + &mut system.peripheral_clock_control, + ); + + // connect operator0 to timer0 + mcpwm.operator0.set_timer(&mcpwm.timer0); + // connect operator0 to pin + let mut pwm_pin = mcpwm + .operator0 + .with_pin_a(pin, PwmPinConfig::UP_ACTIVE_HIGH); + + // start timer with timestamp values in the range of 0..=99 and a frequency of + // 20 kHz + let timer_clock_cfg = clock_cfg + .timer_clock_with_frequency(99, PwmWorkingMode::Increase, 20u32.kHz()) + .unwrap(); + mcpwm.timer0.start(timer_clock_cfg); + + // pin will be high 50% of the time + pwm_pin.set_timestamp(50); + + loop {} +}