From dbd13070e55c80a522e63b7e9b23884edcac1150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henry=20Kotz=C3=A9?= Date: Tue, 30 Sep 2025 21:15:06 +0200 Subject: [PATCH] esp32: pwm register updates correctly on change (#25653) - removed the bug where some overflow would occur on the PWM signal when changing the duty cycle of the signal after power up. (PWM_MAIN_DIS, PWM_MAIN_MIN or PWM_MAIN_MAX) removed commented code cleanup of previous cherry-pick Co-authored-by: henrykotze --- .../px4/espressif/esp32/io_pins/pwm_servo.c | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/platforms/nuttx/src/px4/espressif/esp32/io_pins/pwm_servo.c b/platforms/nuttx/src/px4/espressif/esp32/io_pins/pwm_servo.c index da2b7e932a..f171621aee 100644 --- a/platforms/nuttx/src/px4/espressif/esp32/io_pins/pwm_servo.c +++ b/platforms/nuttx/src/px4/espressif/esp32/io_pins/pwm_servo.c @@ -78,7 +78,6 @@ #define LEDC_LSCH0_DUTY_REG (DR_REG_LEDC_BASE + 0x00A8) #define LEDC_CONF_REG (DR_REG_LEDC_BASE + 0x0190) - #define LEDC_SIG_OUT_EN_LSCH0 1 << 2 #define LEDC_PARA_UP_LSCH0 1 << 4 #define DPORT_LEDC_CLK_EN 1 << 11 @@ -129,7 +128,8 @@ void get_optimal_timer_setup(uint32_t desired_freq) uint32_t shifted = 1; timer_rate = desired_freq; - reload = (20480000000 / desired_freq + LEDC_CLKDIV_MAX) / LEDC_CLKDIV_MAX; + uint64_t pwm_clk = 80000000; + reload = (pwm_clk * 256 / desired_freq + LEDC_CLKDIV_MAX) / LEDC_CLKDIV_MAX; if (reload == 0) { reload = 1; @@ -148,7 +148,7 @@ void get_optimal_timer_setup(uint32_t desired_freq) } shift = shifted; - prescaler = (20480000000 / reload) / desired_freq; + prescaler = (pwm_clk * 256 / reload) / desired_freq; } int up_pwm_servo_set(unsigned channel, uint16_t value) @@ -157,10 +157,23 @@ int up_pwm_servo_set(unsigned channel, uint16_t value) uint32_t regval = b16toi(duty * reload + b16HALF); irqstate_t flags; - flags = px4_enter_critical_section(); + SET_CHAN_REG(channel, LEDC_LSCH0_CONF0_REG, 0); + SET_CHAN_REG(channel, LEDC_LSCH0_CONF1_REG, 0); + + /* Set pulse phase 0 */ + SET_CHAN_REG(channel, LEDC_LSCH0_HPOINT_REG, 0); SET_CHAN_REG(channel, LEDC_LSCH0_DUTY_REG, regval << 4); + + SET_CHAN_BITS(channel, LEDC_LSCH0_CONF0_REG, LEDC_SIG_OUT_EN_LSCH0); + + /* Start Duty counter */ + SET_CHAN_BITS(channel, LEDC_LSCH0_CONF1_REG, LEDC_DUTY_START_LSCH0); + + /* Update duty and phase to hardware */ SET_CHAN_BITS(channel, LEDC_LSCH0_CONF0_REG, LEDC_PARA_UP_LSCH0); + + px4_leave_critical_section(flags); return OK;