Skip to content

Commit

Permalink
Merge branch 'pwm_reduce_inconsist' into OWL_v1.18
Browse files Browse the repository at this point in the history
  • Loading branch information
IhorNehrutsa committed Jul 27, 2023
2 parents 3a71629 + fab9cc4 commit 9ba4f8a
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 41 deletions.
8 changes: 4 additions & 4 deletions docs/esp32/quickref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -296,11 +296,11 @@ Use the :ref:`machine.PWM <machine.PWM>` class::
freq = pwm0.freq() # get current frequency
pwm0.freq(1000) # set PWM frequency from 1Hz to 40MHz

duty = pwm0.duty() # get current duty cycle, range 0-1023 (default 512, 50%)
pwm0.duty(256) # set duty cycle from 0 to 1023 as a ratio duty/1023, (now 25%)
duty = pwm0.duty() # get current duty cycle, range 0-1024 (default 512, 50%)
pwm0.duty(256) # set duty cycle from 0 to 1024 as a ratio duty/1024, (now 25%)

duty_u16 = pwm0.duty_u16() # get current duty cycle, range 0-65535
pwm0.duty_u16(2**16*3//4) # set duty cycle from 0 to 65535 as a ratio duty_u16/65535, (now 75%)
duty_u16 = pwm0.duty_u16() # get current duty cycle, range 0-65536
pwm0.duty_u16(2**16*3//4) # set duty cycle from 0 to 65536 as a ratio duty_u16/65536, (now 75%)

duty_ns = pwm0.duty_ns() # get current pulse width in ns
pwm0.duty_ns(250_000) # set pulse width in nanoseconds from 0 to 1_000_000_000/freq, (now 25%)
Expand Down
6 changes: 3 additions & 3 deletions docs/esp32/tutorial/pwm.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ low all of the time.
PWM(Pin(26), freq=700, duty_u16=53248) # resolution=16, (duty=81.25%, resolution=0.002%), mode=1, channel=4, timer=2
PWM(Pin(27), freq=700, duty_u16=57344) # resolution=16, (duty=87.50%, resolution=0.002%), mode=1, channel=5, timer=2
PWM(Pin(32), freq=799, duty_u16=61440) # resolution=16, (duty=93.75%, resolution=0.002%), mode=1, channel=6, timer=3
PWM(Pin(33), freq=799, duty_u16=65535) # resolution=16, (duty=100.00%, resolution=0.002%), mode=1, channel=7, timer=3
PWM(Pin(33), freq=799, duty_u16=65536) # resolution=16, (duty=100.00%, resolution=0.002%), mode=1, channel=7, timer=3


* Example of a **smooth frequency change**::
Expand Down Expand Up @@ -153,14 +153,14 @@ low all of the time.
PWM(Pin(27), freq=998, duty_u16=65024) # resolution=16, (duty=99.22%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=65280) # resolution=16, (duty=99.61%, resolution=0.002%), mode=0, channel=0, timer=0

PWM(Pin(27), freq=998, duty_u16=65535) # resolution=16, (duty=100.00%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=65536) # resolution=16, (duty=100.00%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=65279) # resolution=16, (duty=99.61%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=65023) # resolution=16, (duty=99.22%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=64767) # resolution=16, (duty=98.83%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=64511) # resolution=16, (duty=98.44%, resolution=0.002%), mode=0, channel=0, timer=0
...
PWM(Pin(27), freq=998, duty_u16=1279) # resolution=16, (duty=1.95%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=1023) # resolution=16, (duty=1.56%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=1024) # resolution=16, (duty=1.56%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=767) # resolution=16, (duty=1.17%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=511) # resolution=16, (duty=0.78%, resolution=0.002%), mode=0, channel=0, timer=0
PWM(Pin(27), freq=998, duty_u16=255) # resolution=16, (duty=0.39%, resolution=0.002%), mode=0, channel=0, timer=0
Expand Down
99 changes: 65 additions & 34 deletions ports/esp32/machine_pwm.c
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ STATIC chan_t chans[LEDC_SPEED_MODE_MAX][LEDC_CHANNEL_MAX];
// List of timer configs
STATIC ledc_timer_config_t timers[LEDC_SPEED_MODE_MAX][LEDC_TIMER_MAX];

// Params for PWM operation
// 5khz is default frequency
#define PWM_FREQ (5000)

// 10-bit resolution (compatible with esp8266 PWM)
#define PWM_RES_10_BIT (LEDC_TIMER_10_BIT)

Expand Down Expand Up @@ -99,7 +103,6 @@ STATIC bool pwm_inited = false;
typedef struct _machine_pwm_obj_t {
mp_obj_base_t base;
gpio_num_t pin;
bool active;
int mode;
int channel;
int timer;
Expand Down Expand Up @@ -175,16 +178,14 @@ STATIC void pwm_deinit(int mode, int channel) {
check_esp_err(ledc_stop(mode, channel, 0));
// Disable ledc signal for the pin
if (mode == LEDC_LOW_SPEED_MODE) {
esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + channel, false, true);
esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + channel, false, false);
} else {
#if LEDC_SPEED_MODE_MAX > 1
#if CONFIG_IDF_TARGET_ESP32
esp_rom_gpio_connect_out_signal(pin, LEDC_HS_SIG_OUT0_IDX + channel, false, true);
#else
#error Add supported CONFIG_IDF_TARGET_ESP32_xxx
#endif
#if SOC_LEDC_SUPPORT_HS_MODE
esp_rom_gpio_connect_out_signal(pin, LEDC_HS_SIG_OUT0_IDX + channel, false, false);
#endif
}
// reconfigure as GPIO
//gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT);
}
unregister_channel(mode, channel);
}
Expand Down Expand Up @@ -220,10 +221,51 @@ STATIC void configure_channel(machine_pwm_obj_t *self) {
PWM_DBG("cfg.duty=%d, cfg.flags.output_invert=%d", cfg.duty, cfg.flags.output_invert);
}
check_esp_err(ledc_channel_config(&cfg));

// reconfigure PWM output for Counter input
gpio_set_direction(self->pin, GPIO_MODE_INPUT_OUTPUT);
if (self->mode == LEDC_LOW_SPEED_MODE) {
esp_rom_gpio_connect_out_signal(self->pin, LEDC_LS_SIG_OUT0_IDX + self->channel, self->output_invert, false);
} else {
#if SOC_LEDC_SUPPORT_HS_MODE
esp_rom_gpio_connect_out_signal(self->pin, LEDC_HS_SIG_OUT0_IDX + self->channel, self->output_invert, false);
PWM_DBG("self->pin=%d, LEDC_HS_SIG_OUT0_IDX + self->channel=%d", self->pin, LEDC_HS_SIG_OUT0_IDX + self->channel);
#endif
}
/*
test.py:
```
import machine
pin = machine.Pin(17)
counter = machine.Counter(0, pin) # must be first !!!
pwm = machine.PWM(pin) # must be second !!!
print(pwm)
print(counter)
print("counter.value()=", counter.value())
print("counter.value()=", counter.value())
print("counter.value()=", counter.value())
print("counter.value()=", counter.value())
print("counter.value()=", counter.value())
print("counter.value()=", counter.value())
print("counter.value()=", counter.value())
```
Output is:
PWM(Pin(17), freq=5000, duty_u16=32768)
Counter(0, src=Pin(17), direction=Counter.UP, edge=Counter.RISING, filter_ns=0)
counter.value()= 92
counter.value()= 94
counter.value()= 95
counter.value()= 95
counter.value()= 142
counter.value()= 142
counter.value()= 143
*/
}

STATIC void pwm_is_active(machine_pwm_obj_t *self) {
if (!self->active) {
if (self->timer < 0) {
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("PWM is inactive"));
}
}
Expand Down Expand Up @@ -289,23 +331,12 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
} else if (channel_duty > max_duty) {
channel_duty = max_duty;
}
check_esp_err(ledc_set_duty(self->mode, self->channel, channel_duty));
check_esp_err(ledc_update_duty(self->mode, self->channel));

self->duty_x = HIGHEST_PWM_RES;
self->duty = duty;

PWM_DBG("set_duty_u16() self->channel_duty=%d, channel_duty=%d, duty=%d\n", self->channel_duty, channel_duty, duty);
if (channel_duty == max_duty) {
self->channel_duty = channel_duty;
configure_channel(self);
} else {
if (self->channel_duty == max_duty) {
self->channel_duty = channel_duty;
configure_channel(self);
}
self->channel_duty = channel_duty;
check_esp_err(ledc_set_duty(self->mode, self->channel, channel_duty));
check_esp_err(ledc_update_duty(self->mode, self->channel));
}
self->channel_duty = channel_duty;
}

STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty) {
Expand Down Expand Up @@ -502,7 +533,7 @@ STATIC void select_a_timer(machine_pwm_obj_t *self, int freq) {
}
}
if (timer < 0) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of the total number of PWM timers:%d"), LEDC_SPEED_MODE_MAX * LEDC_TIMER_MAX);
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM timers:%d"), LEDC_SPEED_MODE_MAX * LEDC_TIMER_MAX);
}
}
self->mode = mode;
Expand All @@ -519,7 +550,7 @@ STATIC void select_a_timer(machine_pwm_obj_t *self, int freq) {
STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "PWM(Pin(%u)", self->pin);
if (self->active && (self->timer >=0)) {
if (self->timer >=0) {
mp_printf(print, ", freq=%u", ledc_get_freq(self->mode, self->timer));

if (self->duty_x == PWM_RES_10_BIT) {
Expand Down Expand Up @@ -572,9 +603,11 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
int duty = args[ARG_duty].u_int;
int duty_u16 = args[ARG_duty_u16].u_int;
int duty_ns = args[ARG_duty_ns].u_int;
/*
if (((duty != -1) && (duty_u16 != -1)) || ((duty != -1) && (duty_ns != -1)) || ((duty_u16 != -1) && (duty_ns != -1))) {
mp_raise_ValueError(MP_ERROR_TEXT("only one of parameters 'duty', 'duty_u16' or 'duty_ns' is allowed"));
}
*/
/*
if ((duty < 0) && (duty_u16 < 0) && (duty_ns < 0)) {
mp_raise_ValueError(MP_ERROR_TEXT("one of parameters 'duty', 'duty_u16', or 'duty_ns' is required"));
Expand All @@ -589,6 +622,9 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
} else if (duty >= 0) {
self->duty_x = PWM_RES_10_BIT;
self->duty = duty;
} else if (self->duty_x == 0) {
self->duty_x = HIGHEST_PWM_RES;
self->duty = (1 << HIGHEST_PWM_RES) / 2; // 50%
}

self->output_invert = args[ARG_invert].u_int == 0 ? 0 : 1;
Expand All @@ -604,7 +640,7 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
channel = find_channel(mode, self->pin);
}
if (channel < 0) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of the total number of PWM channels:%d"), LEDC_SPEED_MODE_MAX * LEDC_CHANNEL_MAX); // in all modes
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("out of PWM channels:%d"), LEDC_SPEED_MODE_MAX * LEDC_CHANNEL_MAX); // in all modes
}
self->mode = mode;
self->channel = channel;
Expand All @@ -619,12 +655,9 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
if (chans[mode][channel].timer >= 0) {
freq = timers[mode][chans[mode][channel].timer].freq_hz;
}
}

self->active = true;

if ((freq < 0) || (self->duty_x == 0)) {
return;
if (freq <= 0) {
freq = PWM_FREQ;
}
}

select_a_timer(self, freq);
Expand All @@ -649,7 +682,6 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
// create PWM object from the given pin
machine_pwm_obj_t *self = mp_obj_malloc(machine_pwm_obj_t, &machine_pwm_type);
self->pin = pin_id;
self->active = false;
self->mode = -1;
self->channel = -1;
self->timer = -1;
Expand All @@ -675,7 +707,6 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type,
// This called from pwm.deinit() method
STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
pwm_deinit(self->mode, self->channel);
self->active = false;
self->mode = -1;
self->channel = -1;
self->timer = -1;
Expand Down

0 comments on commit 9ba4f8a

Please sign in to comment.