Add ESP32 PWM support, mirroring the API of the ESP8266. #79
Conversation
That's brilliant, thanks for your contribution.
I skimmed through it and it looks pretty good, I'll have a closer look
most likely tomorrow.
-----Nick
|
@vandys thanks! For licensing/copyright purposes, can you please outline which parts of the code you wrote, which parts are copied (and from where), what information you used to work out the ESP32 API and what other code you looked at during the writing. For such a large piece of new code we need to be sure it can retain the MIT license. Just a note on code style: maximum line length in this project is roughly 90-100 characters, so no need to break lines under that. |
I started by copying the esp8266 machine_pwm.c. I used information from the ESP32 Technical Reference Manual, the esp-idf documentation, and the SDK's sample ledc example code (but I did not copy that code, just studied it to understand the SDK's API for PWM). So aside from the code copied from the esp8266 PWM support, everything else you see there is just new code I wrote. I wasn't an employee of anybody when I wrote it, and I wrote it with the understanding and intention that it's simply a derivative work of the existing micropython code. I freely and willingly contribute it to the project and intend that it not change the legal status of the micropython code base in any way, even if it is included in that base in whole or part. |
Hi, I tried to enable PWM for pin 13 - everything works great :) Then for pin 34, which according to pinout should support PWM, it says: E (169529) ledc: ledc_channel_config(258): LEDC GPIO output number error As I understandand you used LEDC PWM backend for your code and for other PWM pins there is different implementation, which pins actually use LEDC? Also it seems to think that enabling PWM for pin 15 is perfectly okay, pin 15 is connected to ground :D |
The PWM code here is just using the SDK's API, and if there's some other PWM implementation then I haven't caught a whiff of it. In driver/gpio.h they list GPIO pins 0 through 33 as input and output. Pin 15 on my own board does not seem to be connected to ground, FWIW. |
Hi, where have here something similar to this https://raw.githubusercontent.com/gojimmypi/ESP32/master/images/myESP32%20DevKitC%20pinout.png According to this PWM should work on 34 |
Well, you need to talk with the SDK folks at Espressif. For instance, from their headers:
What in the image you sent makes you believe it'll do output on that pin? |
I was thinking of adding a wrapper around the MCPWM; PWM would be a sub-object of this module. Mostly, I want to do accurate pulse timing. Yes, I'm aware of |
int x; | ||
|
||
// Initial condition: no channels assigned | ||
for (x = 0; x < LEDC_CHANNEL_MAX; ++x) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style: variable decls go in the for loop (if not needed after the loop).
timer_cfg.freq_hz = newval; | ||
if (ledc_timer_config(&timer_cfg) != ESP_OK) { | ||
timer_cfg.freq_hz = oval; | ||
return(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style: should be return 0;
// MicroPython bindings for PWM | ||
|
||
STATIC void esp32_pwm_print(const mp_print_t *print, | ||
mp_obj_t self_in, mp_print_kind_t kind) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style: single line
if (self->active) { | ||
mp_printf(print, ", freq=%u, duty=%u", | ||
timer_cfg.freq_hz, | ||
ledc_get_duty(PWMODE, self->channel)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only break the line if its larger than 90-100 chars.
} | ||
|
||
// Maybe change PWM timer | ||
tval = args[ARG_freq].u_int; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tval should be declared here.
if (channel >= LEDC_CHANNEL_MAX) { | ||
if (avail == -1) { | ||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, | ||
"Out of PWM channels")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error messages start with lower case letter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, use the short-hand mp_raise_ValueError("...")
if (chan_gpio[channel] == -1) { | ||
ledc_channel_config_t cfg = { | ||
.channel = channel, | ||
.duty = (1 << PWRES)/2, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
code style: space around "/"
} | ||
|
||
// Set duty cycle? | ||
dval = args[ARG_duty].u_int; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int dval
} | ||
|
||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_pwm_freq_obj, | ||
1, 2, esp32_pwm_freq); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put on one line
@laurivosandi that pin out looks wrong. |
It looks like MCPWM and LEDC are 2 different ways to do PWM on a pin. It doesn't really matter what the underlying implementation is, as long as the machine.PWM class works as expected (it's not yet properly specified in the docs so it's subject to change). If MCPWM provides lots of extra functionality that doesn't fit a standard peripheral (is it similar enough to a Timer?) then it could go in a new "esp32" module as MCPWM class. |
I'm sorry, which pin out? The one from the earlier discussion? Pin 34? |
Sorry, yes, the link that @laurivosandi posted above to "myESP32 DevKitC pinout.png" looks wrong in that it says all IO pins should be able to do PWM when (as you pointed out) higher-numbered pins are input only. |
Ok, thanks. I'm closing this pull request too, will change code and re-test against new SDK. |
It's more focused around motor control -- you could drive BLDC motors, for example. Or generate servo signals. But, it has a separate "capture" module that's mostly for edge capture / pulse timing. Not purely PWM. It looks like LEDC is more about using timers, and animating led brightness? |
The follow-up to this was merged in #96 |
Hi, first time contribution to micropython, so just let me know if anything should be changed
and bounce this request. Thanks!