Programming The ESP32 In C - PWM First Example
Written by Harry Fairhead   
Wednesday, 05 February 2025
Article Index
Programming The ESP32 In C - PWM First Example
ESP32 PWM
Duty Cycle and Phase
A First Example
Changing the PWM

Changing the PWM

There are a great many functions which can be used to change the operation of the PWM hardware after it has been configured. The first acts on the channel.

  • ledc_stop(speed_mode, channel, idle_level)
    Stops the specified channel, setting the output to idle_level, 0 or 1

There are three that act on the timer:

  • ledc_timer_pause(speed_mode, timer_sel)
    Pauses the timer’s count
  • ledc_timer_resume(speed_mode, timer_sel)
    Resumes the timer’s count
  • ledc_timer_rst(speed_mode, timer_sel)
    Resets the timer’s count to start again from zero

You can also change the clock divider, duty resolution and the choice of clock using:

  • ledc_timer_set(speed_mode, timer_sel, clock_divider,

duty_resolution, clk_src)

To work with the PWM’s frequency you can use:

  • ledc_set_freq(speed_mode, timer_num, freq_hz)
    Changes the frequency
  • freq=ledc_get_freq(speed_mode,  timer_num)
    Changes the frequency at the next timer rollover

In most cases it is the duty cycle of the PWM output you need to change and this can be done with the help of the following functions:

  • ledc_set_duty(speed_mode, channel,  duty)
  • ledc_update_duty(speed_mode, channel)
  • duty=ledc_get_duty(speed_mode, channel)

The set_duty function doesn’t actually change the duty cycle; we need to call update_duty to enforce the change which happens at the next timer restart.

If you want to change the hpoint you can use:

  • ledc_set_duty_with_hpoint(speed_mode, channel, duty, hpoint)
  • hpoint=ledc_get_hpoint(speed_mode, channel)

The functions to update the duty cycle are not threadsafe and should not be used in different tasks at the same time. For concurrent tasks use the alternative threadsafe function:

  • ledc_set_duty_and_update(speed_mode, channel, duty, hpoint)

As an example of changing the duty cycle, this small function changes it in terms of a percentage:

void changeDutyLow(int chan,  int res, float duty) {
  ledc_set_duty(LEDC_LOW_SPEED_MODE, chan, 
                      ((float)(2 << (res - 1))) * duty);
  ledc_update_duty(LEDC_LOW_SPEED_MODE, chan);
}

For example to use this to modulate the duty cycle:

#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "esp_rom_sys.h"
#include "driver/ledc.h"
#include <unistd.h>
void delay_us(int t) {
  usleep(t);
}
void PWMconfigLow(int gpio, int chan, int timer, int res,
                                 int freq, float duty) {
  ledc_timer_config_t ledc_timer = {
      .speed_mode = LEDC_LOW_SPEED_MODE,
      .clk_cfg = LEDC_APB_CLK
  };
  ledc_timer.timer_num = timer;
  ledc_timer.duty_resolution = res;
  ledc_timer.freq_hz = freq;
  ledc_channel_config_t ledc_channel = {
    .speed_mode = LEDC_LOW_SPEED_MODE,
    .hpoint = 0,
    .intr_type = LEDC_INTR_DISABLE,
  };
  ledc_channel.channel = chan;
  ledc_channel.timer_sel = timer;
  ledc_channel.gpio_num = gpio;
  ledc_channel.duty = ((float)(2 << (res - 1))) * duty;
  ledc_timer_config(&ledc_timer);
  ledc_channel_config(&ledc_channel);
}
void changeDutyLow(int chan,  int res, float duty) {
  ledc_set_duty(LEDC_LOW_SPEED_MODE, chan, 
                     ((float)(2 << (res - 1))) * duty);
  ledc_update_duty(LEDC_LOW_SPEED_MODE, chan);
}

 

void app_main(void)
{
  PWMconfigLow(2, 0, 3, 13, 4000, 0.25);
  while (true) {
    delay_us(1000);
    changeDutyLow(0, 13,0.5);
    delay_us(1000);
    changeDutyLow(0, 13,0.25);
  } 
}


Notice that the changeDutyLow function needs to know the resolution to convert the fractional duty cycle into a count. If you try this out you will see the duty cycle change every millisecond:

There are two functions which can be used to change the configuration of the channel:

  • ledc_bind_channel_timer(speed_mode, channel,
    timer_sel) Swaps a channel to another timer
  • ledc_set_pin(id, speed_mode, channel)
    Routes the output of the PWM onto another GPIO line

Notice that this adds the new pin to the pin selected during the setup and that you can have the same PWM signal on more than one GPIO line.

In chapter but not in this extract

  • Uses of PWM – Digital to Analog
  • Frequency Modulation
  • Controlling an LED
  • Hardware Fade
  • Phase
  • What Else Can You Use PWM For?

Summary

  • PWM, Pulse Width Modulation, has a fixed repetition rate but a variable duty cycle, i.e. the amount of time the signal is high or low changes.

  • PWM can be generated by software simply by changing the state of a GPIO line correctly, but it can also be generated in hardware so relieving the processor of some work.

  • As well as being a way of signaling, PWM can also be used to vary the amount of power or voltage transferred. The higher the duty cycle, the more power/voltage.

  • The ESP32 has 16 hardware PWM generators and the ESP32 S3 has 8. These can be used with any of the GPIO lines capable of output.

  • There are only four timers per 8 PWM generator block which determine the frequency that the PWM lines work at. A single timer can be connected to multiple controllers.

  • The higher the frequency of the PWM the lower the duty cycle resolution.

  • You can modify the frequency and duty cycle of a running PWM generator.

  • PWM can be used to implement digital-to-analog conversion simply by varying the duty cycle. You can dim an LED in the same way.

  • The PWM controllers can be set to auto fade an LED by varying the duty cycle.

  • By adjusting hpoint you can generate a signal with a fixed phase relationship to another signal.

Programming The ESP32 In C
Using The Espressif IDF

By Harry Fairhead

espC360

Available as a softback, hardback and kindle from Amazon

Contents

       Preface

  1. The ESP32 – Before We Begin
  2. Getting Started
  3. Getting Started With The GPIO 
  4. Simple Output
  5. Some Electronics
  6. Simple Input
  7. Advanced Input – Interrupts
  8. Pulse Width Modulation
         Extract: PWM First Example***NEW!
  9. The Motor Control PWM
         Extact: MCPWM First Example 
  10. Controlling Motors And Servos
  11. Getting Started With The SPI Bus
  12. Using Analog Sensors
  13. Using The I2C Bus
  14. One-Wire Protocols
         
    Extract: The S3's RGB LED 
  15. The Serial Port
  16. Using WiFi
          Extract:Socket Web Client
  17. Direct To The Hardware
  18. Free RTOS 

<ASIN:1871962919>

<ASIN:187196282X>

espbook

 

Comments




or email your comment to: comments@i-programmer.info

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

Banner



Last Updated ( Wednesday, 05 February 2025 )