diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index 4d6c59f0f..8c8cdf055 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -35,13 +35,19 @@ // Forward dec'l extern const mp_obj_type_t machine_pwm_type; + typedef struct _esp32_pwm_obj_t { mp_obj_base_t base; gpio_num_t pin; uint8_t active; uint8_t channel; + uint8_t timer; + uint8_t mode; } esp32_pwm_obj_t; +// Number of available timers +#define LEDC_TIMER_MAX 4 + // Which channel has which GPIO pin assigned? // (-1 if not assigned) STATIC int chan_gpio[LEDC_CHANNEL_MAX]; @@ -49,42 +55,32 @@ STATIC int chan_gpio[LEDC_CHANNEL_MAX]; // Params for PW operation // 5khz #define PWFREQ (5000) -// High speed mode -#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 = { - .bit_num = 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; } - // Init with default timer params - ledc_timer_config(&timer_cfg); -} - -STATIC int set_freq(int newval) { - int oval = timer_cfg.freq_hz; - - timer_cfg.freq_hz = newval; - if (ledc_timer_config(&timer_cfg) != ESP_OK) { - timer_cfg.freq_hz = oval; - return 0; + // prepare all timers + ledc_timer_config_t timer_cfg = { + .bit_num = PWRES, + .freq_hz = PWFREQ, + .speed_mode = LEDC_LOW_SPEED_MODE, + .timer_num = 0, + }; + for (int mode = 0; mode < LEDC_SPEED_MODE_MAX; ++mode) { + for (int idx = 0; idx < LEDC_TIMER_MAX; ++idx) { + timer_cfg.timer_num = idx; + timer_cfg.speed_mode = mode; + ledc_timer_config(&timer_cfg); + } } - return 1; } /******************************************************************************/ @@ -93,20 +89,23 @@ STATIC int set_freq(int newval) { STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { esp32_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "PWM(%u", self->pin); + mp_printf(print, "PWM(%u, timer=%u, speed_mode=%u", self->pin, self->timer, self->mode); 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", + ledc_get_freq(self->mode, self->timer), + ledc_get_duty(self->mode, self->channel)); } mp_printf(print, ")"); } STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_freq, ARG_duty }; + enum { ARG_freq, ARG_duty, ARG_timer, ARG_mode }; static const mp_arg_t allowed_args[] = { { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_timer, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_speed_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = LEDC_HIGH_SPEED_MODE} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, @@ -133,16 +132,31 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, } self->channel = channel; + // set timer + if (0 <= args[ARG_timer].u_int && args[ARG_timer].u_int <= 3) { + self->timer = args[ARG_timer].u_int; + } else { + mp_raise_ValueError("invalid timer"); + } + + // set speed mode + if (0 <= args[ARG_mode].u_int && args[ARG_mode].u_int <= LEDC_SPEED_MODE_MAX) { + self->mode = args[ARG_mode].u_int; + } else { + mp_raise_ValueError("invalid speed_mode"); + } + // New PWM assignment self->active = 1; if (chan_gpio[channel] == -1) { + // configure channel ledc_channel_config_t cfg = { .channel = channel, .duty = (1 << PWRES) / 2, .gpio_num = self->pin, .intr_type = LEDC_INTR_DISABLE, - .speed_mode = PWMODE, - .timer_sel = PWTIMER, + .speed_mode = self->mode, + .timer_sel = self->timer, }; if (ledc_channel_config(&cfg) != ESP_OK) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, @@ -152,22 +166,23 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, } // Maybe change PWM timer - int tval = args[ARG_freq].u_int; - if (tval != -1) { - if (tval != timer_cfg.freq_hz) { - if (!set_freq(tval)) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Bad frequency %d", tval)); - } - } + int fval = args[ARG_freq].u_int; + if (fval != -1 && ledc_set_freq(self->mode, self->timer, fval) != ESP_OK) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "Bad frequency %d", fval)); } // Set duty cycle? int dval = args[ARG_duty].u_int; if (dval != -1) { dval &= ((1 << PWRES)-1); - ledc_set_duty(PWMODE, channel, dval); - ledc_update_duty(PWMODE, channel); + ledc_set_duty(self->mode, channel, dval); + ledc_update_duty(self->mode, channel); + } + + // Reset the timer if low speed + if (self->mode == LEDC_LOW_SPEED_MODE) { + ledc_timer_rst(self->mode, self->timer); } } @@ -210,28 +225,42 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) { // Valid channel? if ((chan >= 0) && (chan < LEDC_CHANNEL_MAX)) { - // Mark it unused, and tell the hardware to stop routing + // Mark it unused, and tell the hardware to stop chan_gpio[chan] = -1; - ledc_stop(PWMODE, chan, 0); + ledc_stop(self->mode, chan, 0); self->active = 0; self->channel = -1; + // Disable ledc signal for the pin + if (self->mode == LEDC_LOW_SPEED_MODE) { + gpio_matrix_out(self->pin, LEDC_LS_SIG_OUT0_IDX + self->channel, false, true); + } else { + gpio_matrix_out(self->pin, LEDC_HS_SIG_OUT0_IDX + self->channel, false, true); + } } return mp_const_none; } 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(ledc_get_freq(self->mode, self->timer)); } // set int tval = mp_obj_get_int(args[1]); - if (!set_freq(tval)) { + if (tval <= 0 || ledc_set_freq(self->mode, self->timer, tval) != ESP_OK) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "Bad frequency %d", tval)); + "bad frequency %d", tval)); } + + // Reset the timer if low speed + if (self->mode == LEDC_LOW_SPEED_MODE) { + ledc_timer_rst(self->mode, self->timer); + } + return mp_const_none; } @@ -243,15 +272,15 @@ 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 = ledc_get_duty(self->mode, self->channel); return MP_OBJ_NEW_SMALL_INT(duty); } // set duty = mp_obj_get_int(args[1]); duty &= ((1 << PWRES)-1); - ledc_set_duty(PWMODE, self->channel, duty); - ledc_update_duty(PWMODE, self->channel); + ledc_set_duty(self->mode, self->channel, duty); + ledc_update_duty(self->mode, self->channel); return mp_const_none; } @@ -263,6 +292,8 @@ STATIC const mp_rom_map_elem_t esp32_pwm_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&esp32_pwm_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&esp32_pwm_freq_obj) }, { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&esp32_pwm_duty_obj) }, + { MP_ROM_QSTR(MP_QSTR_HIGH_SPEED_MODE), MP_ROM_INT(LEDC_HIGH_SPEED_MODE) }, + { MP_ROM_QSTR(MP_QSTR_LOW_SPEED_MODE), MP_ROM_INT(LEDC_LOW_SPEED_MODE) }, }; STATIC MP_DEFINE_CONST_DICT(esp32_pwm_locals_dict, 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