First of all I ask you to be lenient for my English if it is clumsy; I don't speak English fluently. The same goes for my programming skills: I was a hardware technician before I retired.
After playing for a while with Arduino, I started recently with the ESP32. My need was to create two PWMs, without overlap, of different durations each, and with an offset of 180°. I googled for a while and couldn't find any examples that I could trim to meet my requirements. I delved a little further into the various Espressif documents concerning PWM generation modules.
ESP32 PWM generation devicesBasically the ESP32 has two devices to generate PWM: Motor Control Pulse Width Modulator (MCPWM) and LED Control (LEDC). Both can be used for generating two PWMs 180° out of phase. In each case the settings need to be cleverly calculated to meet your requirements, but this isn't difficult with a little thought... You can create overlapping or non-overlapping waveforms.
Hardware setup for testingI have used "ESP32 DEVKIT V1 DOIT" with ESP32-D0WD chip on it. But some other ESP32 boards could also be used. Note that some ESP32 chips do not have MCPWM. You can then only test LEDC.
More about features of the different ESP32 chips at: https://products.espressif.com/#/product-comparison and/or: https://docs.espressif.com/projects/esp-idf/en/v5.0/esp32s3/hw-reference/chip-series-comparison.html
On the breadboard, two analog inputs of the ESP32 are connected to potentiometers wipers (0 to 3.3V) to allow the timings to be adjusted. Two other GPIO pins outputs the PWM signals. These are connected to two LEDs with a 1KΩ serie resistor each. The hardware wiring is the same for testing both sketches (Test_MCPWM and TEST_LEDC_pwm).
See the appended diagram PWM_schema.png
If you can have an oscilloscope, it is interesting to visualize the generated waveforms.
Be careful not to send more than 3.3V to any input of your ESP32 otherwise you will see it send a smoke signal !!!
MCPWMThe MCPWM API seems at first to be the simplest solution. The following explanation refers to the attached sketch "test_MCPWM.ino". This sketch creates non-overlapping waveforms but you can easily modify it for overlapping.
I tried to comment sufficiently on the sketches for understanding them, so I won't repeat everything here.
The MCPWM_UNIT_0 is used. Two GPIOs are attached to MCPWM0A and MCPWM0B. The duty cycle will be defined respectively with pwm_config.cmpr_a and pwm_config.cmpr_b.
TIMER 0 is set to count up and down. This is necessary so that two centered symmetrical PWM waveforms are generated. The PWM_1 is output directly to a GPIO pin. The output of the second GPIO pin is inverted to create the 180° phase shift. So the PWM_2 LOW level corresponds to the HIGH level on the GPIO pin.
You can find the full MCPWM API documentation at: https://docs.espressif.com/projects/esp-idf/en/v4.3/esp32/api-reference/peripherals/mcpwm.html
LEDC pwmThe calculations may seem a little more complicated than with the MCPWM device. We have to calculate the time interval between falling edge of first PWM and rising edge of second PWM and then, calculate the startpoint (phase) of the second PWM signal.
As you can see in the diagram below:
- PWM_1 is set to HIGH when clock-ticks count is reset to 0 (hpoint(PWM_1))
- PWM_1 is set to LOW whenlpoint(PWM_1) clock-ticks count is reached
- PWM_2 is set to HIGH when hpoint(PWM_2) is reached
- PWM_2 is set to LOW when lpoint(PWM_2) is reached
In order to obtain a 180° phase shift, the clock tick count interval between lpoint(PWM_1) and hpoint(PWM_2) is half the remaining time where neither is HIGH. The other half is between lpoint(PWM_2) and hpoint(PWM_1).
In the diagram below you see the switch-points of PWM_1 and PWM_2. "Duty" is respectively the number of clock-ticks between the high switch-points (hpoint) and the low switch-points (lpoint) of each PWM.
Resolution can be increased up to 14 bits but depends on frequency. You can find guidelines in the excerpt below chapter 35.3.2.3 page 1277 of espressif.com "esp32-s3_technical_reference_manual_en.pdf".
The use of the library <pwmWrite.h> found at "https://github.com/Dlloydev/ESP32-ESP32S2-AnalogWrite" simplifies a lot the writing of the sketch.Once you have calculated the duty (in number of clock ticks taking into account the chosen resolution) for each pwm an the startpoint (called "phase" in the sketch), wrote them for each output-pin with "pwm.write(Pin, duty, frequency, resolution, phase);" you are done.
Much simpler and more flexible than MCPWM !
Comments