diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c old mode 100755 new mode 100644 index 9308fcd3cbfc6..bf928395652ae --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -74,7 +74,8 @@ STATIC ledc_timer_config_t timers[PWM_TIMER_MAX]; // Params for PWM operation // 5khz is default frequency #define PWM_FREQ (5000) -// default 10-bit resolution (compatible with esp8266 PWM) + +// 10-bit resolution (compatible with esp8266 PWM) #define PWM_RES_10_BIT (LEDC_TIMER_10_BIT) // Maximum duty value on 10-bit resolution @@ -84,15 +85,17 @@ STATIC ledc_timer_config_t timers[PWM_TIMER_MAX]; // duty_u16() and duty_ns() use 16-bit resolution or less // Possible highest resolution in device -#if CONFIG_IDF_TARGET_ESP32 -#define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT) // 20 bit for ESP32, but 16 bit is used +#if (LEDC_TIMER_BIT_MAX - 1) < LEDC_TIMER_16_BIT +#define HIGHEST_PWM_RES (LEDC_TIMER_BIT_MAX - 1) #else -#define HIGHEST_PWM_RES (LEDC_TIMER_BIT_MAX - 1) // 14 bit is used +#define HIGHEST_PWM_RES (LEDC_TIMER_16_BIT) // 20 bit for ESP32, but 16 bit is used #endif // Duty resolution of user interface in `duty_u16()` and `duty_u16` parameter in constructor/initializer #define UI_RES_16_BIT (16) // Maximum duty value on highest user interface resolution #define UI_MAX_DUTY ((1 << UI_RES_16_BIT) - 1) +// How much to shift from the HIGHEST_PWM_RES duty resolution to the user interface duty resolution UI_RES_16_BIT +#define UI_RES_SHIFT (UI_RES_16_BIT - HIGHEST_PWM_RES) // 0 for ESP32, 2 for S2, S3, C3 // If the PWM frequency is less than EMPIRIC_FREQ, then LEDC_REF_CLK_HZ(1 MHz) source is used, else LEDC_APB_CLK_HZ(80 MHz) source is used #define EMPIRIC_FREQ (10) // Hz @@ -108,7 +111,7 @@ typedef struct _machine_pwm_obj_t { int mode; int channel; int timer; - int duty_x; // PWM_RES_10_BIT if duty(), UI_RES_16_BIT if duty_u16(), -UI_RES_16_BIT if duty_ns() + int duty_x; // PWM_RES_10_BIT if duty(), HIGHEST_PWM_RES if duty_u16(), -HIGHEST_PWM_RES if duty_ns() int duty_u10; // stored values from previous duty setters int duty_u16; // - / - int duty_ns; // - / - @@ -208,7 +211,6 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf if (freq < EMPIRIC_FREQ) { i = LEDC_REF_CLK_HZ; // 1 MHz } - #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) // original code i /= freq; @@ -237,7 +239,6 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf } // Configure the new resolution and frequency - unsigned int save_duty_resolution = timer->duty_resolution; timer->duty_resolution = res; timer->freq_hz = freq; timer->clk_cfg = LEDC_USE_APB_CLK; @@ -258,17 +259,15 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf if (self->mode == LEDC_LOW_SPEED_MODE) { check_esp_err(ledc_timer_rst(self->mode, self->timer)); } + } - // Save the same duty cycle when frequency is changed - if (save_duty_resolution != timer->duty_resolution) { - if (self->duty_x == UI_RES_16_BIT) { - set_duty_u16(self, self->duty_u16); - } else if (self->duty_x == PWM_RES_10_BIT) { - set_duty_u10(self, self->duty_u10); - } else if (self->duty_x == -UI_RES_16_BIT) { - set_duty_ns(self, self->duty_ns); - } - } + // Save the same duty cycle when frequency is changed + if (self->duty_x == HIGHEST_PWM_RES) { + set_duty_u16(self, self->duty_u16); + } else if (self->duty_x == PWM_RES_10_BIT) { + set_duty_u10(self, self->duty_u10); + } else if (self->duty_x == -HIGHEST_PWM_RES) { + set_duty_ns(self, self->duty_ns); } } @@ -293,11 +292,18 @@ STATIC int duty_to_ns(machine_pwm_obj_t *self, int duty) { #define get_duty_raw(self) ledc_get_duty(self->mode, self->channel) STATIC uint32_t get_duty_u16(machine_pwm_obj_t *self) { - return ledc_get_duty(self->mode, self->channel) << (UI_RES_16_BIT - timers[TIMER_IDX(self->mode, self->timer)].duty_resolution); + int resolution = timers[TIMER_IDX(self->mode, self->timer)].duty_resolution; + int duty = ledc_get_duty(self->mode, self->channel); + if (resolution <= UI_RES_16_BIT) { + duty <<= (UI_RES_16_BIT - resolution); + } else { + duty >>= (resolution - UI_RES_16_BIT); + } + return duty; } STATIC uint32_t get_duty_u10(machine_pwm_obj_t *self) { - return get_duty_u16(self) >> (UI_RES_16_BIT - LEDC_TIMER_10_BIT); + return get_duty_u16(self) >> 6; // Scale down from 16 bit to 10 bit resolution } STATIC uint32_t get_duty_ns(machine_pwm_obj_t *self) { @@ -309,7 +315,12 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_u16 must be from 0 to %d"), UI_MAX_DUTY); } ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)]; - int channel_duty = duty >> (UI_RES_16_BIT - timer.duty_resolution); + int channel_duty; + if (timer.duty_resolution <= UI_RES_16_BIT) { + channel_duty = duty >> (UI_RES_16_BIT - timer.duty_resolution); + } else { + channel_duty = duty << (timer.duty_resolution - UI_RES_16_BIT); + } int max_duty = (1 << timer.duty_resolution) - 1; if (channel_duty < 0) { channel_duty = 0; @@ -333,7 +344,7 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) { } */ - self->duty_x = UI_RES_16_BIT; + self->duty_x = HIGHEST_PWM_RES; self->duty_u16 = duty; } @@ -341,7 +352,7 @@ STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty) { if ((duty < 0) || (duty > MAX_DUTY_U10)) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty must be from 0 to %u"), MAX_DUTY_U10); } - set_duty_u16(self, duty << (UI_RES_16_BIT - LEDC_TIMER_10_BIT)); + set_duty_u16(self, duty << (UI_RES_16_BIT - PWM_RES_10_BIT)); self->duty_x = PWM_RES_10_BIT; self->duty_u10 = duty; } @@ -351,7 +362,7 @@ STATIC void set_duty_ns(machine_pwm_obj_t *self, int ns) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_ns must be from 0 to %d ns"), duty_to_ns(self, UI_MAX_DUTY)); } set_duty_u16(self, ns_to_duty(self, ns)); - self->duty_x = -UI_RES_16_BIT; + self->duty_x = -HIGHEST_PWM_RES; self->duty_ns = ns; } @@ -424,7 +435,7 @@ STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_p if (self->duty_x == PWM_RES_10_BIT) { mp_printf(print, ", duty=%d", get_duty_u10(self)); - } else if (self->duty_x == -UI_RES_16_BIT) { + } else if (self->duty_x == -HIGHEST_PWM_RES) { mp_printf(print, ", duty_ns=%d", get_duty_ns(self)); } else { mp_printf(print, ", duty_u16=%d", get_duty_u16(self));
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: