ESP32 - What is the minimum PWM frequency?

Hi,
I can find lots of "hits" for MAX PWM Frequency, but I want Sub-Hz values (0.1 - 0.5Hz).
Using this commonly found technique:

int PWM_FREQUENCY = 1;   // this variable is used to define the time period 
int PWM_CHANNEL = 0;     // this variable is used to select the channel number
int PWM_RESOUTION = 8;   // this will define the resolution of the signal which is 8 in this case
int GPIOPIN =2 ;         // GPIO to which we want to attach this channel signal
int dutyCycle = 8;       // it will define the width of signal or also the one time

void setup()
{
   ledcSetup(PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOUTION);
   ledcAttachPin(GPIOPIN, PWM_CHANNEL);
   ledcWrite(PWM_CHANNEL, dutyCycle);
}

void loop() 
{
   //Do Stuff....
}

... gets me near what I want. But I can not provide a value less than 1 for the PWM_FREQUENCY.

Can anyone offer an alternative hardware solution?

Regards, Martin

Hi mprowe,

Here's an example using the ESP32's MCPWM peripheral to generate a 0.1Hz PWM signal, 50% duty-cycle on GPIO pin 27 with timer 0:

// ESP32: Output PWM 0.1Hz (10 second period), 50% duty-cycle on GPIO pin 27
#include "soc/mcpwm_reg.h"
#include "soc/mcpwm_struct.h"
#include "driver/mcpwm.h"

#define GPIO_PWM0A_OUT 27

void setup() {
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);     // Initialise channel MCPWM0A on GPIO pin 27
  MCPWM0.clk_cfg.prescale = 199;                // Set the 160MHz clock prescaler to 199 (160MHz/(199+1)=800kHz)
  MCPWM0.timer[0].period.prescale = 199;        // Set timer 0 prescaler to 199 (800kHz/(199+1))=4kHz)
  MCPWM0.timer[0].period.period = 39999;        // Set the PWM period to 0.1Hz (4kHz/(39999+1)=0.1Hz)  
  MCPWM0.channel[0].cmpr_value[0].val = 20000;  // Set the counter compare for 50% duty-cycle
  MCPWM0.channel[0].generator[0].utez = 2;      // Set the PWM0A ouput to go high at the start of the timer period
  MCPWM0.channel[0].generator[0].utea = 1;      // Clear on compare match
  MCPWM0.timer[0].mode.mode = 1;                // Set timer 0 to increment
  MCPWM0.timer[0].mode.start = 2;               // Set timer 0 to free-run
}

void loop() {}

Note that "clk_cfg" and "period" prescaler register bifields are 8-bit (0 to 255 + 1), while "period" is 16-bit (0 to 65535 + 1).

Thanks Martin,

Very helpful.

Regards, ~Martin~

The esp32-hal-ledc.h file has the following prototype:

double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits);

You could try and just set the frequency to 0.5. e.g.

double PWM_FREQUENCY = 0.5;

You can find the file under

C:\Users\UserName\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\cores\esp32

There is a lower limit to how low the hardware can divide the clock. You can find more information in the ESP documentation. The ESP-IDF API is different to the ESP Arduino API but the hardware information is valid.

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/ledc.html