PWM channel in ESP32

I have a ESP32- PWM sketch that control a motor that work just fine in a standalone (the code below). When I transfer this code to another sketch already full of other devices (IIC, SPI) then the PWM don't work anymore. Since my big sketch can turn the motor on and off using digitalWrite (HIGH / LOW) with no problem, I suspect my problem have to do with the PWM channel selection. My standalone sketch use PWM Channel 0 but maybe this channel is use by I2C or SPI. I also use RX0 and TX0 for serial communication?

My question is: Is there a way to know which one of the 16 PWM channel are available to use and which one are busy? Or maybe you think it is not related to my problem?

The working PWM sketch is here. The other code is very big for posting (I may post if require). The code below use channel 0. I also tried with channel 6 just to see. Even in this simple form, it don't work with channel 6. My device is a 38 pin ESP32 Wroom-32 (Dev. Board).

TEST CODE FOR PWM 
// the PWM pin
const int ledPin = 25;  // 25 corresponds to GPIO25

void setup(){
  // configure PWM functionalitites
  ledcSetup(0, 5000, 8);  // Channel = 0 , Freq = 5000 and resolution = 8
  
  // attach the channel to the GPIO 
  ledcAttachPin(ledPin, 0);    (Channel = 0 here again)
}
 
void loop(){
    ledcWrite(ledChannel, 255);   // Pump max speed
    delay(15000);
    ledcWrite(ledChannel, 0);    // Pump turn off 
    delay(15000);
    ledcWrite(ledChannel, 125);  // Pump half on  
    delay(15000);
    ledcWrite(ledChannel, 0);    // Pump off
    delay(15000);
}

thank you

I always start with timer number 4(3) and work backwards towards one. The safe bet. The ESP32 can assign a hardware timer to a device such as the lcd driver if the device does not ask for a specific timer. Which bring up the issue that is something else is using a hardware timer then which one. As timer 4(3) is the last timer to get an automated assignment, I start there and work backwards.

////// Recommended servo pins include 2,4,12-19,21-23,25-27,32-33
/*
** ledc: 0  => Group: 0, Channel: 0, Timer: 0
** ledc: 1  => Group: 0, Channel: 1, Timer: 0
** ledc: 2  => Group: 0, Channel: 2, Timer: 1
** ledc: 3  => Group: 0, Channel: 3, Timer: 1
** ledc: 4  => Group: 0, Channel: 4, Timer: 2
** ledc: 5  => Group: 0, Channel: 5, Timer: 2
** ledc: 6  => Group: 0, Channel: 6, Timer: 3
** ledc: 7  => Group: 0, Channel: 7, Timer: 3
** ledc: 8  => Group: 1, Channel: 8, Timer: 0
** ledc: 9  => Group: 1, Channel: 9, Timer: 0
** ledc: 10 => Group: 1, Channel: 10, Timer: 1
** ledc: 11 => Group: 1, Channel: 11, Timer: 1
** ledc: 12 => Group: 1, Channel: 12, Timer: 2
** ledc: 13 => Group: 1, Channel: 13, Timer: 2
** ledc: 14 => Group: 1, Channel: 14, Timer: 3
** ledc: 15 => Group: 1, Channel: 15, Timer: 3
*

Maybe the information you are looking for?

I quit using the ESP32's LED thingy for driving motors.

Instead I use the MCPWM which has its own internal timers.

#include "driver/mcpwm.h"

setup()
{
 mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_NUM_4 ); // Azimuth
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_NUM_12 ); // Altitude servo
  //
  mcpwm_config_t pwm_config = {};
  pwm_config.frequency = 50;    //frequency = 50Hz, i.e. for every servo motor time period should be 20ms
  pwm_config.cmpr_a = 0;    //duty cycle of PWMxA = 0
  pwm_config.cmpr_b = 0;    //duty cycle of PWMxb = 0
  pwm_config.counter_mode = MCPWM_UP_COUNTER;
  pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
  log_i( "MCPWM complete" );
  //
  //
  mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);    //Configure PWM0A timer 0 with above settings
  mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_config);    //Configure PWM0A timer 1 with above settings
  //  ////
  fMoveAltitude( 1525 );
  fMoveAzimuth( 1500 );
}

////
void fMoveAltitude( int MoveTo )
{
  mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, MoveTo);
  vTaskDelay( 12 );
}
//////
void fMoveAzimuth( int MoveTo )
{
  mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A, MoveTo);
  vTaskDelay( 12 );
}
////

Should get you started with the MCPWM

The timer look different than the channel. Should I implement this number somewhere or just select the corresponding "ledc" to test. Example, ledc 7 = channel 7 and timer 3?

Just to learn from other experiences, why did you quit using the led thing? It was not reliable? Or too unpredictable just like I see now?

I will look into this library. Thank you

  1. The MCPWM is more accurate for motors than the ledc library.

  2. I do not require to know programmatically which hardware timer is in use or may be used and compensate for the issue.

  3. The MCPWM is more accurate for motors than the ledc library.

The ledc is used as per the LEDC API documentation

Oh forgot.

  1. using MCPWM does not require the use of the microseconds to clock tick formula.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.