Skip to content

Commit 26d4ebe

Browse files
committed
ports/esp32: pwm: Prevent duty glitch on init.
When a new channel was assigned, configure_channel would seet the duty to 50% before resetting to the actual user specified duty. This results in unintentional glitches. Example code ``` p1 = machine.PWM(self.pin1, self.pwm_freq, duty_u16=0) ``` This would brieflt glitch a pwm motor driver when it's created, instead of leaving it at duty=0 as intended. Instead, we calculate the duty into native units first, and apply it separately in a second step where needed. Signed-off-by: Karl Palsson <karlp@tweak.au>
1 parent e00a144 commit 26d4ebe

File tree

1 file changed

+30
-23
lines changed

1 file changed

+30
-23
lines changed

ports/esp32/machine_pwm.c

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ typedef struct _machine_pwm_obj_t {
118118
int duty_u10; // stored values from previous duty setters
119119
int duty_u16; // - / -
120120
int duty_ns; // - / -
121+
int channel_duty; // What we actually want to write, in esp32 units.
121122
} machine_pwm_obj_t;
122123

123124
STATIC bool is_timer_in_use(int current_channel_idx, int timer_idx);
@@ -196,7 +197,7 @@ void machine_pwm_deinit_all(void) {
196197
STATIC void configure_channel(machine_pwm_obj_t *self) {
197198
ledc_channel_config_t cfg = {
198199
.channel = self->channel,
199-
.duty = (1 << (timers[TIMER_IDX(self->mode, self->timer)].duty_resolution)) / 2,
200+
.duty = self->channel_duty,
200201
.gpio_num = self->pin,
201202
.intr_type = LEDC_INTR_DISABLE,
202203
.speed_mode = self->mode,
@@ -321,26 +322,28 @@ STATIC uint32_t get_duty_ns(machine_pwm_obj_t *self) {
321322
return duty_to_ns(self, get_duty_u16(self));
322323
}
323324

324-
STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
325+
STATIC void set_duty_apply(machine_pwm_obj_t *self) {
325326
pwm_is_active(self);
327+
check_esp_err(ledc_set_duty(self->mode, self->channel, self->channel_duty));
328+
check_esp_err(ledc_update_duty(self->mode, self->channel));
329+
}
330+
331+
STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
326332
if ((duty < 0) || (duty > UI_MAX_DUTY)) {
327333
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_u16 must be from 0 to %d"), UI_MAX_DUTY);
328334
}
329335
ledc_timer_config_t timer = timers[TIMER_IDX(self->mode, self->timer)];
330-
int channel_duty;
331336
if (timer.duty_resolution <= UI_RES_16_BIT) {
332-
channel_duty = duty >> (UI_RES_16_BIT - timer.duty_resolution);
337+
self->channel_duty = duty >> (UI_RES_16_BIT - timer.duty_resolution);
333338
} else {
334-
channel_duty = duty << (timer.duty_resolution - UI_RES_16_BIT);
339+
self->channel_duty = duty << (timer.duty_resolution - UI_RES_16_BIT);
335340
}
336341
int max_duty = (1 << timer.duty_resolution) - 1;
337-
if (channel_duty < 0) {
338-
channel_duty = 0;
339-
} else if (channel_duty > max_duty) {
340-
channel_duty = max_duty;
342+
if (self->channel_duty < 0) {
343+
self->channel_duty = 0;
344+
} else if (self->channel_duty > max_duty) {
345+
self->channel_duty = max_duty;
341346
}
342-
check_esp_err(ledc_set_duty(self->mode, self->channel, channel_duty));
343-
check_esp_err(ledc_update_duty(self->mode, self->channel));
344347

345348
/*
346349
// Bug: Sometimes duty is not set right now.
@@ -361,7 +364,6 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
361364
}
362365

363366
STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty) {
364-
pwm_is_active(self);
365367
if ((duty < 0) || (duty > MAX_DUTY_U10)) {
366368
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty must be from 0 to %u"), MAX_DUTY_U10);
367369
}
@@ -371,7 +373,6 @@ STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty) {
371373
}
372374

373375
STATIC void set_duty_ns(machine_pwm_obj_t *self, int ns) {
374-
pwm_is_active(self);
375376
if ((ns < 0) || (ns > duty_to_ns(self, UI_MAX_DUTY))) {
376377
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));
377378
}
@@ -539,6 +540,17 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
539540
self->timer = TIMER_IDX_TO_TIMER(timer_idx);
540541
self->channel = CHANNEL_IDX_TO_CHANNEL(channel_idx);
541542

543+
// Note: doesn't set, just calculates...
544+
if (duty_u16 != -1) {
545+
set_duty_u16(self, duty_u16);
546+
} else if (duty_ns != -1) {
547+
set_duty_ns(self, duty_ns);
548+
} else if (duty != -1) {
549+
set_duty_u10(self, duty);
550+
} else if (self->duty_x == 0) {
551+
set_duty_u10(self, (1 << PWM_RES_10_BIT) / 2); // 50%
552+
}
553+
542554
// New PWM assignment
543555
if ((chans[channel_idx].pin == -1) || (chans[channel_idx].timer_idx != timer_idx)) {
544556
configure_channel(self);
@@ -549,17 +561,9 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
549561

550562
// Set timer frequency
551563
set_freq(self, freq, &timers[timer_idx]);
564+
// This will _re-apply_ duty, if it's a new channel, but that's ok....
565+
set_duty_apply(self);
552566

553-
// Set duty cycle?
554-
if (duty_u16 != -1) {
555-
set_duty_u16(self, duty_u16);
556-
} else if (duty_ns != -1) {
557-
set_duty_ns(self, duty_ns);
558-
} else if (duty != -1) {
559-
set_duty_u10(self, duty);
560-
} else if (self->duty_x == 0) {
561-
set_duty_u10(self, (1 << PWM_RES_10_BIT) / 2); // 50%
562-
}
563567
}
564568

565569
// This called from PWM() constructor
@@ -664,6 +668,7 @@ STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self) {
664668

665669
STATIC void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty) {
666670
set_duty_u10(self, duty);
671+
set_duty_apply(self);
667672
}
668673

669674
STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
@@ -672,6 +677,7 @@ STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
672677

673678
STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16) {
674679
set_duty_u16(self, duty_u16);
680+
set_duty_apply(self);
675681
}
676682

677683
STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
@@ -680,4 +686,5 @@ STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
680686

681687
STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns) {
682688
set_duty_ns(self, duty_ns);
689+
set_duty_apply(self);
683690
}

0 commit comments

Comments
 (0)
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