esp32/machine_pwm: Support higher PWM freq by auto-scaling timer res.

This commit is contained in:
Damien George 2018-12-06 16:40:26 +11:00
parent 87623082e3
commit 287b02d98a
1 changed files with 23 additions and 2 deletions

View File

@ -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);