diff options
-rw-r--r-- | ports/esp32/machine_pwm.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index 4d6c59f0f..4833c1f02 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -59,7 +59,7 @@ STATIC int chan_gpio[LEDC_CHANNEL_MAX]; // 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, + .duty_resolution = PWRES, .freq_hz = PWFREQ, .speed_mode = PWMODE, .timer_num = PWTIMER @@ -77,10 +77,28 @@ STATIC void pwm_init(void) { } STATIC int set_freq(int newval) { + int ores = timer_cfg.duty_resolution; int oval = timer_cfg.freq_hz; + // Find the highest bit resolution for the requested frequency + if (newval <= 0) { + newval = 1; + } + unsigned int res = 0; + for (unsigned int i = LEDC_APB_CLK_HZ / newval; i > 1; i >>= 1, ++res) { + } + if (res == 0) { + res = 1; + } else if (res > PWRES) { + // Limit resolution to PWRES to match units of our duty + res = PWRES; + } + + // 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; return 0; } @@ -138,7 +156,7 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, if (chan_gpio[channel] == -1) { ledc_channel_config_t cfg = { .channel = channel, - .duty = (1 << PWRES) / 2, + .duty = (1 << timer_cfg.duty_resolution) / 2, .gpio_num = self->pin, .intr_type = LEDC_INTR_DISABLE, .speed_mode = PWMODE, @@ -166,6 +184,7 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self, int dval = args[ARG_duty].u_int; if (dval != -1) { dval &= ((1 << PWRES)-1); + dval >>= PWRES - timer_cfg.duty_resolution; ledc_set_duty(PWMODE, channel, dval); ledc_update_duty(PWMODE, channel); } @@ -244,12 +263,14 @@ 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; return MP_OBJ_NEW_SMALL_INT(duty); } // set duty = mp_obj_get_int(args[1]); duty &= ((1 << PWRES)-1); + duty >>= PWRES - timer_cfg.duty_resolution; ledc_set_duty(PWMODE, self->channel, duty); ledc_update_duty(PWMODE, self->channel); |