Skip to content

Commit 4fa837b

Browse files
committed
esp32/machine_pwm.c: Code refactoring.
Signed-off-by: Ihor Nehrutsa <[email protected]>
1 parent 02d27f4 commit 4fa837b

File tree

1 file changed

+28
-39
lines changed

1 file changed

+28
-39
lines changed

ports/esp32/machine_pwm.c

+28-39
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,26 @@
3535
#include "py/mphal.h"
3636
#include "esp_err.h"
3737
#include "driver/ledc.h"
38-
#include "soc/gpio_sig_map.h"
3938
#include "soc/ledc_periph.h"
39+
#include "soc/gpio_sig_map.h"
4040
#include "esp_clk_tree.h"
4141
#include "py/mpprint.h"
4242

4343
#define debug_printf(...) // mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, " | %d at %s\n", __LINE__, __FILE__);
44-
#define FADE 1
44+
45+
#define FADE
4546

4647
// 10-bit user interface resolution compatible with esp8266 PWM.duty()
4748
#define UI_RES_10_BIT (10)
4849
#define DUTY_10 UI_RES_10_BIT
49-
// Maximum duty value on 10-bit resolution
50-
#define MAX_10_DUTY ((1U << UI_RES_10_BIT) - 1)
50+
// Maximum duty value on 10-bit resolution is 1024 but reduced to 1023 in UI
51+
#define MAX_10_DUTY (1U << UI_RES_10_BIT)
5152

5253
// 16-bit user interface resolution used in PWM.duty_u16()
5354
#define UI_RES_16_BIT (16)
5455
#define DUTY_16 UI_RES_16_BIT
55-
// Maximum duty value on 16-bit resolution
56-
#define MAX_16_DUTY ((1U << UI_RES_16_BIT) - 1)
56+
// Maximum duty value on 16-bit resolution is 65536 but reduced to 65535 in UI
57+
#define MAX_16_DUTY (1U << UI_RES_16_BIT)
5758

5859
// ns user interface used in PWM.duty_ns()
5960
#define DUTY_NS (1)
@@ -63,9 +64,6 @@
6364
// default duty 50%
6465
#define PWM_DUTY ((1U << UI_RES_16_BIT) / 2)
6566

66-
// MAX_timer_duty is the MAX value of a channel_duty
67-
#define MAX_timer_duty ((1U << timers[self->mode][self->timer].duty_resolution) - 1)
68-
6967
// All chips except esp32 and esp32s2 do not have timer-specific clock sources, which means clock source for all timers must be the same one.
7068
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
7169
// 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
@@ -89,7 +87,6 @@ typedef struct _machine_pwm_obj_t {
8987
int channel_duty; // saved values of UI duty, calculated to raw channel->duty
9088
bool output_invert;
9189
bool output_invert_prev;
92-
bool output_is_inverted;
9390
} machine_pwm_obj_t;
9491

9592
typedef struct _chans_t {
@@ -218,14 +215,10 @@ static int duty_to_ns(machine_pwm_obj_t *self, int duty) {
218215

219216
// Reconfigure PWM pin output as input/output. This allows to read the pin level.
220217
static void reconfigure_pin(machine_pwm_obj_t *self) {
221-
bool invert = self->output_invert;
222-
if (self->channel_duty == MAX_timer_duty) {
223-
invert = !invert;
224-
}
225218
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0)
226219
gpio_set_direction(self->pin, GPIO_MODE_INPUT_OUTPUT);
227220
#endif
228-
esp_rom_gpio_connect_out_signal(self->pin, ledc_periph_signal[self->mode].sig_out0_idx + self->channel, invert, 0);
221+
esp_rom_gpio_connect_out_signal(self->pin, ledc_periph_signal[self->mode].sig_out0_idx + self->channel, self->output_invert, 0);
229222
}
230223

231224
static void apply_duty(machine_pwm_obj_t *self) {
@@ -235,13 +228,12 @@ static void apply_duty(machine_pwm_obj_t *self) {
235228
if (self->duty_scale == DUTY_16) {
236229
duty = self->duty_ui;
237230
} else if (self->duty_scale == DUTY_10) {
238-
duty = self->duty_ui == MAX_10_DUTY ? MAX_16_DUTY : self->duty_ui << (UI_RES_16_BIT - UI_RES_10_BIT);
231+
duty = self->duty_ui << (UI_RES_16_BIT - UI_RES_10_BIT);
239232
} else if (self->duty_scale == DUTY_NS) {
240233
duty = ns_to_duty(self, self->duty_ui);
241234
}
242235
self->channel_duty = duty >> (UI_RES_16_BIT - timers[self->mode][self->timer].duty_resolution);
243-
int max_timer_duty = MAX_timer_duty;
244-
if ((chans[self->mode][self->channel].pin == -1) || (self->channel_duty == 0) || (self->channel_duty == max_timer_duty) || (self->output_invert_prev != self->output_invert) || (self->output_is_inverted != self->output_invert)) {
236+
if ((chans[self->mode][self->channel].pin == -1) || (self->output_invert_prev != self->output_invert)) {
245237
self->output_invert_prev = self->output_invert;
246238
// New PWM assignment
247239
ledc_channel_config_t cfg = {
@@ -254,27 +246,21 @@ static void apply_duty(machine_pwm_obj_t *self) {
254246
.hpoint = 0,
255247
.flags.output_invert = self->output_invert,
256248
};
257-
self->output_is_inverted = false;
258-
if (self->channel_duty == max_timer_duty) {
259-
cfg.duty = 0;
260-
cfg.flags.output_invert = !self->output_invert;
261-
self->output_is_inverted = true;
262-
}
263249
check_esp_err(ledc_channel_config(&cfg));
264250
if (self->light_sleep_enable) {
265251
// Disable SLP_SEL to change GPIO status automantically in lightsleep.
266252
check_esp_err(gpio_sleep_sel_dis(self->pin));
267253
chans[self->mode][self->channel].light_sleep_enable = true;
268254
}
255+
reconfigure_pin(self);
269256
} else {
270-
#if FADE
257+
#ifdef FADE
271258
check_esp_err(ledc_set_duty_and_update(self->mode, self->channel, self->channel_duty, 0));
272259
#else
273260
check_esp_err(ledc_set_duty(self->mode, self->channel, self->channel_duty));
274261
check_esp_err(ledc_update_duty(self->mode, self->channel));
275262
#endif
276263
}
277-
reconfigure_pin(self);
278264
register_channel(self->mode, self->channel, self->pin, self->timer);
279265
}
280266

@@ -284,25 +270,24 @@ static uint32_t find_suitable_duty_resolution(uint32_t src_clk_freq, uint32_t ti
284270
// limit resolution to user interface
285271
resolution = UI_RES_16_BIT;
286272
}
287-
/*
288-
// Uncomment if duty is 65536!
289273
// Note: On ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32C6, ESP32H2, ESP32P4, due to a hardware bug,
290274
// 100% duty cycle (i.e. 2**duty_res) is not reachable when the binded timer selects the maximum duty
291275
// resolution. For example, the max duty resolution on ESP32C3 is 14-bit width, then set duty to (2**14)
292276
// will mess up the duty calculation in hardware.
293-
if (resolution >= SOC_LEDC_TIMER_BIT_WIDTH)
277+
// Reduce the resolution from 14 to 13 bits to resolve the hardware bug.
278+
if (resolution >= SOC_LEDC_TIMER_BIT_WIDTH) {
294279
resolution -= 1;
295280
}
296-
*/
297281
return resolution;
298282
}
299283

300284
static uint32_t get_duty_u16(machine_pwm_obj_t *self) {
301285
pwm_is_active(self);
302-
if (self->channel_duty == MAX_timer_duty) {
303-
return MAX_16_DUTY;
286+
int duty = ledc_get_duty(self->mode, self->channel) << (UI_RES_16_BIT - timers[self->mode][self->timer].duty_resolution);
287+
if (duty != MAX_16_DUTY) {
288+
return duty;
304289
} else {
305-
return ledc_get_duty(self->mode, self->channel) << (UI_RES_16_BIT - timers[self->mode][self->timer].duty_resolution);
290+
return MAX_16_DUTY - 1;
306291
}
307292
}
308293

@@ -316,9 +301,12 @@ static uint32_t get_duty_ns(machine_pwm_obj_t *self) {
316301
}
317302

318303
static void check_duty_u16(machine_pwm_obj_t *self, int duty) {
319-
if ((duty < 0) || (duty > MAX_16_DUTY)) {
304+
if ((duty < 0) || (duty > MAX_16_DUTY - 1)) {
320305
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_u16 must be from 0 to %d"), MAX_16_DUTY);
321306
}
307+
if (duty == MAX_16_DUTY - 1) {
308+
duty = MAX_16_DUTY;
309+
}
322310
self->duty_scale = DUTY_16;
323311
self->duty_ui = duty;
324312
}
@@ -329,8 +317,11 @@ static void set_duty_u16(machine_pwm_obj_t *self, int duty) {
329317
}
330318

331319
static void check_duty_u10(machine_pwm_obj_t *self, int duty) {
332-
if ((duty < 0) || (duty > MAX_10_DUTY)) {
333-
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty must be from 0 to %u"), MAX_10_DUTY);
320+
if ((duty < 0) || (duty > MAX_10_DUTY - 1)) {
321+
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty must be from 0 to %u"), MAX_10_DUTY - 1);
322+
}
323+
if (duty == MAX_10_DUTY - 1) {
324+
duty = MAX_10_DUTY;
334325
}
335326
self->duty_scale = DUTY_10;
336327
self->duty_ui = duty;
@@ -656,7 +647,6 @@ static void self_reset(machine_pwm_obj_t *self) {
656647
self->channel_duty = -1;
657648
self->output_invert = false;
658649
self->output_invert_prev = false;
659-
self->output_is_inverted = false;
660650
self->light_sleep_enable = false;
661651
}
662652

@@ -668,7 +658,7 @@ static mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
668658
// start the PWM subsystem if it's not already running
669659
if (!pwm_inited) {
670660
pwm_init();
671-
#if FADE
661+
#ifdef FADE
672662
ledc_fade_func_install(0);
673663
#endif
674664
pwm_inited = true;
@@ -684,7 +674,6 @@ static mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
684674
mp_map_t kw_args;
685675
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
686676
mp_machine_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
687-
688677
return MP_OBJ_FROM_PTR(self);
689678
}
690679

0 commit comments

Comments
 (0)