0

I'm trying to setup 4 different PWMs (on GPIOs 4, 25, 26, 27) on a ESP32 using Arduino framework. I can't setup the frequencies on GPIOs 25 and 26, those end up receiving the same frequencies as the other 2 (i.e. GPIO 25 oscillates at the same frequency as GPIO 4, and GPIO 26 oscillates the same frequency as GPIO 27). Relevant code parts:

on the header file:

#define DC_IO_PORTS_QUANTITY 4

typedef enum DC_IO_NUM
{
    DC_IO0,
    DC_IO1,
    DC_IO2,
    DC_IO3

} DC_IO_NUM;

typedef enum DC_IO_PIN
{
    DC_IO0_PIN = 4,
    DC_IO1_PIN = 25,
    DC_IO2_PIN = 26,
    DC_IO3_PIN = 27

} DC_IO_PIN;
//...
void DC_IO_Init(uint8_t resolution, uint16_t freq); //initializes all PWMs with the same frequency and resolution, with 50% duty-cycle
void Set_DC_IO_Freq(DC_IO_NUM dc_iox, uint16_t freq);
//...

on the source file:

const DC_IO_NUM DC_IO_NUM_TABLE[DC_IO_PORTS_QUANTITY]={DC_IO0, DC_IO1, DC_IO2, DC_IO3};
const DC_IO_PIN DC_IO_PIN_TABLE[DC_IO_PORTS_QUANTITY]={DC_IO0_PIN, DC_IO1_PIN, DC_IO2_PIN, DC_IO3_PIN};

uint16_t full_duty_cycle=1;
uint16_t old_duty_cycle[DC_IO_PORTS_QUANTITY]={0};
uint8_t old_res=0;

void DC_IO_Init(uint8_t resolution, uint16_t freq)
{
    uint16_t half_duty_cycle;

    old_res=resolution;

    uint16_t bit_val=1;
    for(uint8_t k=1;k<resolution;k++)
    {
        bit_val *= 2;
        full_duty_cycle += bit_val;
    }

    half_duty_cycle = full_duty_cycle/2; //50%

    for(uint8_t i=0; i<DC_IO_PORTS_QUANTITY; i++)
    {
        old_duty_cycle[i] = half_duty_cycle;

        ledcSetup(DC_IO_NUM_TABLE[i], freq, old_res);
        ledcWrite(DC_IO_NUM_TABLE[i], old_duty_cycle[i]);
        ledcAttachPin(DC_IO_PIN_TABLE[i], DC_IO_NUM_TABLE[i]);
    }
    vTaskDelay(10);
}
//...
void Set_DC_IO_Freq(DC_IO_NUM dc_iox, uint16_t freq)
{
    ledcSetup(dc_iox, freq, old_res);
    ledcWrite(dc_iox, old_duty_cycle[dc_iox]);
    ledcAttachPin(DC_IO_PIN_TABLE[dc_iox], DC_IO_NUM_TABLE[dc_iox]);
    vTaskDelay(10);
}
//...

on the main.cpp setup():

DC_IO_Init(16, 100); //all pwms on 100Hz 16bits
Set_DC_IO_Freq(DC_IO0,50); //PWM0:=GPIO4 on 50Hz
Set_DC_IO_Freq(DC_IO2,200); //PWM2:=GPIO26 on 200Hz
Set_DC_IO_Freq(DC_IO3,300); //PWM3:=GPIO27 on 300Hz

However, on the scope I can see that PWM1 is on 50Hz and PWM2 is on 300Hz...

  • While there are 16 channels for PWM, it looks to me like there's only 4 timers, so only 4 different frequencies at one time: https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-ledc.c I'm not sure this is what the problem is, tho. – aMike Nov 18 '21 at 00:13
  • There are actually 8 timers, four low speed and four high speed and they are configurable through muxes such that each of the high speed PWMs can connect to any of the four high speed timers and each low speed PWM can connect to any of the four low speed timers. However it seems that in the Arduino implementation the mapping is fixed (or at least I don;t know how to change it) such that they are assigned in pairs, so PWM0 and 1 must have the same frequency, PWM2 and 3 must have the same frequency and so on. So if you use PWMs 0,2,4 instead of 0,2,3 you should be OK. – Christian Dec 06 '21 at 17:39

1 Answers1

0

According to the ESP32 Technical Reference Manual, ver 4.5, 2021, page 382:

Figure 14-1 shows the architecture of the LED_PWM controller. As can be seen in the figure, the LED_PWM controller contains eight high-speed and eight low-speed channels. There are four high-speed clock modules for the high-speed channels, from which one h_timerx can be selected. There are also four low-speed clock modules for the low-speed channels, from which one l_timerx can be selected.

(emphasis is mine)

There's a nice picture which shows 4 timers going to a mux which drives 8 pwm outputs, for both slow and fast clocks.

So, I think you're seeing the best you can get - two different PWM rates.

aMike
  • 852
  • 5
  • 14