8. PWM
8.1 Introduction to PWM
PWM (Pulse Width Modulation) is a very effective technique that uses the digital output of a microprocessor to control analog circuits. PWM is a method of digitally encoding the level of an analog signal. It refers to the proportion of time occupied by the high level (i.e., the 1 state) of the waveform within a certain period of time. Through the use of a high-resolution counter, the duty cycle of a square wave is modulated to encode the level of a specific analog signal. The PWM signal is still digital, because at any given moment, the full-amplitude DC supply is either completely on or completely off. For example, if our voltage output is 5V, then by changing the duty cycle of the PWM, we can achieve the effect of outputting 3.3V or 1.3V within a certain period of time.
An Example
Imagine you have an LED and a switch, and you repeatedly turn it on and off at a speed that the naked eye cannot discern. This way, the LED will be on for half the time and off for half the time. If you do this quickly, to the observer, the LED will appear to be continuously on at half brightness. This is the basic principle of PWM. If you keep the switch off for most of the time, the LED will appear dimmer; conversely, if you keep the switch on for most of the time, the LED will appear brighter. This is the process of using PWM to adjust the duty cycle to control brightness.
8.2 Basic Parameters of PWM
PWM is pulse width modulation, and it has two very important parameters: frequency and duty cycle.
Frequency: The period length of the PWM signal, usually expressed in Hertz (Hz), which indicates how many pulses there are per second. The frequency of PWM is the reciprocal of the entire period. It refers to the number of times the signal goes from high level to low level and back to high level (one cycle) within 1 second.Duty cycle: The duty cycle refers to the proportion of high level within one period. The duty cycle can be expressed as a percentage. For example, a 50% duty cycle means the high level lasts for half of the period, and then the low level lasts for the other half.Resolution: The resolution of the PWM signal supported by ESP32 refers to the number of different duty cycle levels that the device can output. For example, 8-bit resolution means the device can output 2^8 different duty cycle levels, that is, 0%, 1/256, 2/256 ... up to 100%.
8.3 PWM on the ESP32S3
There are two hardware peripherals on the ESP32-S3 that can output PWM signals: the LED PWM Controller (LEDC) and the Motor Control Pulse Width Modulator (MCPWM). Each has its own characteristics and uses:
LED PWM Controller (LEDC): The main design goal of this module is to generate high-precision PWM waveforms for controlling LED brightness or generating sound. The resolution of LEDC can reach 16 bits, capable of producing accurate and smooth variations, suitable for controlling LED brightness and generating sound. In addition, LEDC supports up to 8 channels of PWM output. Users can configure the frequency and duty cycle of each channel.Motor Control Pulse Width Modulator (MCPWM): This module is mainly used for motor control, including servo motors, stepper motors, and regular motors. MCPWM supports more complex control modes, such as forward/reverse drive of motors, coasting brake, etc., and supports closed-loop control modes to meet more complex motor control requirements. MCPWM supports up to 6 channels of independent PWM output, and also supports dead-time control and external signal capture.
In summary, the two differ in handling PWM and are applied in different scenarios. LEDC is more suitable for controlling linear devices such as lights and sound, while MCPWM contains more advanced features and is suitable for motor control. In this chapter, we use the LED PWM Controller as a case to output PWM, hereafter referred to as LEDC.
8.4 PWM Control Process
The process of using ESP32S3's PWM function in MicroPython is as follows:
- Import the relevant modules and libraries:
import machine- Initialize the PWM object:
classmachine.PWM(dest, \*, freq, duty_u16, duty_ns)PWM can be output through all GPIO pins of the ESP32S3. All channels have one specific frequency, ranging from 1 to 40M (unit is Hz). The duty cycle value ranges from 0 to 1023.
PWM is in the machine's PWM module. We also only need to understand its object constructor and usage:
Constructor machine.PWM(dest, freq, duty, duty_u16, duty_ns), constructs and returns a new PWM object with the following parameters:
- dest is the entity that outputs PWM, usually a machine.Pin object;
- freq should be an integer used to set the frequency of the PWM period (in Hz);
- duty: duty cycle, range is 0 - 1023;
- duty_u16: duty cycle, range is 0 - 65535, 2 to the power of 16;
- duty_ns: sets the pulse width in nanoseconds, range is 0 - 50000.
Example:
pin_number = 48
pwm = machine.PWM(machine.Pin(pin_number))2
- Configure the frequency and duty cycle of the PWM signal:
pwm.freq(desired_frequency) # Get or set the current frequency of the PWM output.
pwm.duty(desired_duty_cycle)# Set the duty cycle of the PWM output.2
The desired_frequency parameter is the frequency of the PWM signal you want to set, in Hz.
The desired_duty_cycle parameter is the duty cycle of the PWM signal, ranging from 0-1023, representing 0%-100% duty cycle.
After initializing the PWM, you can change the frequency and duty cycle of the PWM signal at any time by calling the freq() and duty() methods.
- Modify PWM parameters:c
pwm.deinit() # First turn off the PWM output to ensure an initialized state pwm.init()1
2cModify the settings of the PWM object. For details about the parameters, please refer to the previous constructor PWM.PWM.init(\*, freq, duty_u16, duty_ns)1
It is best to call deinit() to turn off the PWM before calling the init() method to ensure that it is in an initialized state.
- Turn off the PWM output:
pwm.deinit()This will turn off the PWM output and release related resources.
Refer to the official MicroPython documentation:
http://www.86x.org/en/latet/library/machine.PWM.html#machine-pwm
8.5 Hardware Connection and Preparation
This case uses the onboard LED for a breathing light test. Generally, the human eye has no sense of flicker for refresh rates above 80Hz. Since flicker is not visible at high frequencies, the larger the duty cycle, the brighter the LED, and the smaller the duty cycle, the dimmer the LED. So at a certain frequency, different duty cycles can be used to change the brightness of the LED, achieving a breathing light effect (gradually brightening and then gradually dimming, repeating this cycle).
The onboard LED is connected to GPIO48, so when initializing, we need to bind the LEDC function to GPIO48.
8.6 PWM Breathing Light Verification
import time from machine import Pin, PWM
# Create an LED control object
led = PWM(Pin(48), freq=1000)
while True:
# Gradually brighten
for i in range(0, 1024):
led.duty(i)
time.sleep_ms(1)
# Gradually dim
for i in range(1023, 0, -1):
led.duty(i)
time.sleep_ms(1)2
3
4
5
6
7
8
9
10
11
12
13