From b723f56e79324ca1ba0166c95df493d05d07171f Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Thu, 19 Nov 2020 19:31:59 +0200 Subject: [PATCH 1/2] esp32/machine_pwm.c: Fix duty value printed in esp32_pwm_print(). --- ports/esp32/machine_pwm.c | 199 +++++++++++++++++++++++++++++++------- 1 file changed, 164 insertions(+), 35 deletions(-) diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index 7592f243b76f3..bc3b305ca79f8 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -46,6 +46,13 @@ typedef struct _esp32_pwm_obj_t { // (-1 if not assigned) STATIC int chan_gpio[LEDC_CHANNEL_MAX]; +// Which channel has which timer assigned? +// (-1 if not assigned) +STATIC int chan_timer[LEDC_CHANNEL_MAX]; + +// List of timer configs +STATIC ledc_timer_config_t timers[LEDC_TIMER_MAX]; + // Params for PW operation // 5khz #define PWFREQ (5000) @@ -53,32 +60,36 @@ STATIC int chan_gpio[LEDC_CHANNEL_MAX]; #define PWMODE (LEDC_HIGH_SPEED_MODE) // 10-bit resolution (compatible with esp8266 PWM) #define PWRES (LEDC_TIMER_10_BIT) -// Timer 1 -#define PWTIMER (LEDC_TIMER_1) // Config of timer upon which we run all PWM'ed GPIO pins STATIC bool pwm_inited = false; -STATIC ledc_timer_config_t timer_cfg = { - .duty_resolution = PWRES, - .freq_hz = PWFREQ, - .speed_mode = PWMODE, - .timer_num = PWTIMER -}; STATIC void pwm_init(void) { // Initial condition: no channels assigned for (int x = 0; x < LEDC_CHANNEL_MAX; ++x) { chan_gpio[x] = -1; + chan_timer[x] = -1; } - // Init with default timer params - ledc_timer_config(&timer_cfg); + // Initial condition: no timers assigned + for (int x = 0; x < LEDC_TIMER_MAX; ++x) { + timers[x].duty_resolution = PWRES; + // unset timer is -1 + timers[x].freq_hz = -1; + timers[x].speed_mode = PWMODE; + timers[x].timer_num = x; } +} + +STATIC int set_freq(int newval, ledc_timer_config_t *timer) { + int ores = timer->duty_resolution; + int oval = timer->freq_hz; -STATIC int set_freq(int newval) { - int ores = timer_cfg.duty_resolution; - int oval = timer_cfg.freq_hz; + // If already set, do nothing + if (newval == oval) { + return 1; + } // Find the highest bit resolution for the requested frequency if (newval <= 0) { @@ -95,16 +106,63 @@ STATIC int set_freq(int newval) { } // Configure the new resolution and frequency - timer_cfg.duty_resolution = res; - timer_cfg.freq_hz = newval; - if (ledc_timer_config(&timer_cfg) != ESP_OK) { - timer_cfg.duty_resolution = ores; - timer_cfg.freq_hz = oval; + timer->duty_resolution = res; + timer->freq_hz = newval; + if (ledc_timer_config(timer) != ESP_OK) { + timer->duty_resolution = ores; + timer->freq_hz = oval; return 0; } return 1; } +STATIC int found_timer(int freq, bool same_freq_only) { + int free_timer_found = -1; + int timer; + // Find a free PWM Timer using the same freq + for (timer = 0; timer < LEDC_TIMER_MAX; ++timer) { + if (timers[timer].freq_hz == freq) { + // A timer already use the same freq. Use it now. + return timer; + } + if (!same_freq_only && (free_timer_found == -1) && (timers[timer].freq_hz == -1)) { + free_timer_found = timer; + // Continue to check if a channel with the same freq is in used. + } + } + + return free_timer_found; +} + +// return if the timer is in use in addition to curr_channel +STATIC bool is_timer_in_use(int curr_channel, int timer) { + bool used = false; + int i; + for (i = 0; i < LEDC_CHANNEL_MAX; ++i) { + if (i != curr_channel && chan_timer[i] == timer) { + used = true; + break; + } + } + + return used; +} + +/******************************************************************************/ +STATIC int get_duty(esp32_pwm_obj_t *self) { + int duty; + duty = ledc_get_duty(PWMODE, self->channel); + duty <<= PWRES - timers[chan_timer[self->channel]].duty_resolution; + return duty; +} + +STATIC void set_duty(esp32_pwm_obj_t *self, int duty) { + duty &= ((1 << PWRES) - 1); + duty >>= PWRES - timers[chan_timer[self->channel]].duty_resolution; + ledc_set_duty(PWMODE, self->channel, duty); + ledc_update_duty(PWMODE, self->channel); +} + /******************************************************************************/ // MicroPython bindings for PWM @@ -113,8 +171,8 @@ STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "PWM(%u", self->pin); if (self->active) { - mp_printf(print, ", freq=%u, duty=%u", timer_cfg.freq_hz, - ledc_get_duty(PWMODE, self->channel)); + mp_printf(print, ", freq=%u, duty=%u", timers[chan_timer[self->channel]].freq_hz, + get_duty(self)); } mp_printf(print, ")"); } @@ -151,16 +209,32 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, } self->channel = channel; + int timer; + int freq = args[ARG_freq].u_int; + + // Check if freq wasn't passed as an argument + if (freq == -1) { + // Check if already set, otherwise use the defaut freq + freq = chan_timer[self->channel] != -1 ? timers[chan_timer[self->channel]].freq_hz : PWFREQ; + } + + timer = found_timer(freq, false); + + if (timer == -1) { + mp_raise_ValueError(MP_ERROR_TEXT("out of PWM timers")); + } + chan_timer[channel] = timer; + // New PWM assignment self->active = 1; if (chan_gpio[channel] == -1) { ledc_channel_config_t cfg = { .channel = channel, - .duty = (1 << timer_cfg.duty_resolution) / 2, + .duty = (1 << timers[timer].duty_resolution) / 2, .gpio_num = self->pin, .intr_type = LEDC_INTR_DISABLE, .speed_mode = PWMODE, - .timer_sel = PWTIMER, + .timer_sel = timer, }; if (ledc_channel_config(&cfg) != ESP_OK) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("PWM not supported on pin %d"), self->pin); @@ -168,23 +242,21 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, chan_gpio[channel] = self->pin; } - // Maybe change PWM timer - int tval = args[ARG_freq].u_int; - if (tval != -1) { - if (tval != timer_cfg.freq_hz) { - if (!set_freq(tval)) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval); - } - } + // Set timer frequency + if (!set_freq(freq, &timers[timer])) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), freq); } // Set duty cycle? int dval = args[ARG_duty].u_int; if (dval != -1) { + /* dval &= ((1 << PWRES) - 1); - dval >>= PWRES - timer_cfg.duty_resolution; + dval >>= PWRES - timers[timer].duty_resolution; ledc_set_duty(PWMODE, channel, dval); ledc_update_duty(PWMODE, channel); + */ + set_duty(self, dval); } } @@ -227,6 +299,14 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) { // Valid channel? if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) { + // Clean up timer if necessary + if (!is_timer_in_use(chan, chan_timer[chan])) { + ledc_timer_rst(PWMODE, chan_timer[chan]); + // Flag it unused + timers[chan_timer[chan]].freq_hz = -1; + chan_timer[chan] = -1; + } + // Mark it unused, and tell the hardware to stop routing chan_gpio[chan] = -1; ledc_stop(PWMODE, chan, 0); @@ -239,14 +319,57 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_pwm_deinit_obj, esp32_pwm_deinit); STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) { + esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); if (n_args == 1) { // get - return MP_OBJ_NEW_SMALL_INT(timer_cfg.freq_hz); + return MP_OBJ_NEW_SMALL_INT(timers[chan_timer[self->channel]].freq_hz); } // set int tval = mp_obj_get_int(args[1]); - if (!set_freq(tval)) { + + if (tval == timers[chan_timer[self->channel]].freq_hz) { + return mp_const_none; + } + + int current_timer = chan_timer[self->channel]; + int new_timer = -1; + bool current_in_use = is_timer_in_use(self->channel, current_timer); + + // Check if an already running with the same freq is running + new_timer = found_timer(tval, true); + + // If no existing timer was found, and the current one is in use, then find a new one + if (new_timer == -1 && current_in_use) { + // Have to found a new timer + new_timer = found_timer(tval, false); + + if (new_timer == -1) { + mp_raise_ValueError(MP_ERROR_TEXT("out of PWM timers")); + } + } + + if (new_timer != -1 && new_timer != current_timer) { + // Bind the channel to the new timer + chan_timer[self->channel] = new_timer; + + if (ledc_bind_channel_timer(PWMODE, self->channel, new_timer) != ESP_OK) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Failed to bind timer to channel")); + } + + if (!current_in_use) { + // Free the old timer + ledc_timer_rst(PWMODE, current_timer); + + // Flag it unused + timers[current_timer].freq_hz = -1; + } + + current_timer = new_timer; + } + + // Set the freq + if (!set_freq(tval, &timers[current_timer])) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("bad frequency %d"), tval); } return mp_const_none; @@ -260,17 +383,23 @@ STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) { if (n_args == 1) { // get + /* duty = ledc_get_duty(PWMODE, self->channel); - duty <<= PWRES - timer_cfg.duty_resolution; + duty <<= PWRES - timers[chan_timer[self->channel]].duty_resolution; return MP_OBJ_NEW_SMALL_INT(duty); + */ + return MP_OBJ_NEW_SMALL_INT(get_duty(self)); } // set duty = mp_obj_get_int(args[1]); + /* duty &= ((1 << PWRES) - 1); - duty >>= PWRES - timer_cfg.duty_resolution; + duty >>= PWRES - timers[chan_timer[self->channel]].duty_resolution; ledc_set_duty(PWMODE, self->channel, duty); ledc_update_duty(PWMODE, self->channel); + */ + set_duty(self, duty); return mp_const_none; } From 8c0ad27aa7d1aeec62fb733052cdc531ec1920c1 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Fri, 27 Nov 2020 02:08:23 +0200 Subject: [PATCH 2/2] esp32/machine_pwm.c: Fix PWM.deinit() critical error. pwm_print() show real (duty/resolution) in brackets. Use ESP_EXCEPTIONS() macro. --- ports/esp32/machine_pwm.c | 61 +++++++++++++++------------------------ 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index bc3b305ca79f8..f41a1bbc432ff 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -32,6 +32,8 @@ #include "modmachine.h" #include "mphalport.h" +#include "esp_error.h" + // Forward dec'l extern const mp_obj_type_t machine_pwm_type; @@ -79,7 +81,7 @@ STATIC void pwm_init(void) { timers[x].freq_hz = -1; timers[x].speed_mode = PWMODE; timers[x].timer_num = x; -} + } } STATIC int set_freq(int newval, ledc_timer_config_t *timer) { @@ -134,33 +136,34 @@ STATIC int found_timer(int freq, bool same_freq_only) { return free_timer_found; } -// return if the timer is in use in addition to curr_channel +// return true if the timer is in use in addition to curr_channel STATIC bool is_timer_in_use(int curr_channel, int timer) { - bool used = false; int i; for (i = 0; i < LEDC_CHANNEL_MAX; ++i) { - if (i != curr_channel && chan_timer[i] == timer) { - used = true; - break; + if ((i != curr_channel) && (chan_timer[i] == timer)) { + return true; } } - - return used; + return false; } /******************************************************************************/ -STATIC int get_duty(esp32_pwm_obj_t *self) { - int duty; +STATIC uint32_t get_resolution(esp32_pwm_obj_t *self) { + return timers[chan_timer[self->channel]].duty_resolution; +} + +STATIC uint32_t get_duty(esp32_pwm_obj_t *self) { + uint32_t duty; duty = ledc_get_duty(PWMODE, self->channel); duty <<= PWRES - timers[chan_timer[self->channel]].duty_resolution; return duty; } -STATIC void set_duty(esp32_pwm_obj_t *self, int duty) { +STATIC void set_duty(esp32_pwm_obj_t *self, uint32_t duty) { duty &= ((1 << PWRES) - 1); duty >>= PWRES - timers[chan_timer[self->channel]].duty_resolution; - ledc_set_duty(PWMODE, self->channel, duty); - ledc_update_duty(PWMODE, self->channel); + ESP_EXCEPTIONS(ledc_set_duty(PWMODE, self->channel, duty)); + ESP_EXCEPTIONS(ledc_update_duty(PWMODE, self->channel)); } /******************************************************************************/ @@ -171,8 +174,10 @@ STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "PWM(%u", self->pin); if (self->active) { - mp_printf(print, ", freq=%u, duty=%u", timers[chan_timer[self->channel]].freq_hz, - get_duty(self)); + uint32_t duty; + duty = ledc_get_duty(PWMODE, self->channel); + mp_printf(print, ", freq=%u, duty=%u(%u/%u)", timers[chan_timer[self->channel]].freq_hz, + get_duty(self), duty, 1<>= PWRES - timers[timer].duty_resolution; - ledc_set_duty(PWMODE, channel, dval); - ledc_update_duty(PWMODE, channel); - */ set_duty(self, dval); } } @@ -304,8 +303,8 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) { ledc_timer_rst(PWMODE, chan_timer[chan]); // Flag it unused timers[chan_timer[chan]].freq_hz = -1; - chan_timer[chan] = -1; } + chan_timer[chan] = -1; // channel now don't use a timer!!! // Mark it unused, and tell the hardware to stop routing chan_gpio[chan] = -1; @@ -354,7 +353,7 @@ STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) { chan_timer[self->channel] = new_timer; if (ledc_bind_channel_timer(PWMODE, self->channel, new_timer) != ESP_OK) { - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Failed to bind timer to channel")); + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("failed to bind timer to channel")); } if (!current_in_use) { @@ -374,32 +373,18 @@ STATIC mp_obj_t esp32_pwm_freq(size_t n_args, const mp_obj_t *args) { } return mp_const_none; } - STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_freq_obj, 1, 2, esp32_pwm_freq); STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) { esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]); - int duty; if (n_args == 1) { // get - /* - duty = ledc_get_duty(PWMODE, self->channel); - duty <<= PWRES - timers[chan_timer[self->channel]].duty_resolution; - return MP_OBJ_NEW_SMALL_INT(duty); - */ return MP_OBJ_NEW_SMALL_INT(get_duty(self)); } // set - duty = mp_obj_get_int(args[1]); - /* - duty &= ((1 << PWRES) - 1); - duty >>= PWRES - timers[chan_timer[self->channel]].duty_resolution; - ledc_set_duty(PWMODE, self->channel, duty); - ledc_update_duty(PWMODE, self->channel); - */ - set_duty(self, duty); + set_duty(self, mp_obj_get_int(args[1])); return mp_const_none; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy