In this tutorial, we will learn how to use PWM channels of Raspberry Pi Pico using MicroPython Thonny IDE and UpyCraft IDE. Firstly, we will see PWM pins of Pico board which can provide pulse width modulation signals. After that, we will look at how to produce the PWM signals with the GPIO pins of the pico board. In the end, we will see LED fading as well as brightness control examples.
Prerequisites Raspberry Pi Pico PWM Tutorial
In order to start, make sure you have performed the following procedures already:
- Downloaded and installed the latest version of Python 3 on your PC.
- Downloaded and installed the latest version of Thonny IDE.
- Set up MicroPython in Raspberry Pi Pico.
If you want to know how to perform the above steps, you can follow this step by step guide:
If you are using uPyCraft IDE, you can check this getting started guide:
PWM means pulse width modulation. It is a type of signal which is obtained from a microcontroller in our case the Raspberry Pi Pico board. The output signal is a square waveform which at a particular instance is either high or low. If we are using a 3.3V power supply then the PWM signal would be either high which is 3.3V or low which is 0V. The ‘on time is the duration till which the signal stays high and the ‘off time’ is the duration till which it stays low. In order to better understand the concepts of PWM in our board we need to know about the following two terms which are closely associated with the digital signal:
What is Duty Cycle?
Duty cycle is the percentage of time in which the PWM signal is ‘on time’ meaning it remains High. For example if the signal is always OFF it is 0% duty cycle and if it is always ON it is 100% duty signal. The special feature about this is that the user can control the ‘on time’ by controlling the duty cycle. The formula for duty cycle is shown in following expression:
Duty Cycle = ON time of signal / Time period of signal
The frequency of a PWM signal is the number of cycles per second and it defines how quickly a PWM signal completes one cycle (Period). That means the Period of a PWM signal is the sum of the ON and OFF time of a PWM signal. For example, if the time period of a signal is 20ms, its frequency will be 50Hz where Hz is the unit of frequency. This formula is used to calculate the frequency:
Frequency = 1/Time Period Time Period = ON time + OFF time
PWM Pins Raspberry Pi Pico
Raspberry Pi Pico microcontroller contains 8 PWM blocks and each PWM block provides two PWM signals. That means each slice can drive up to two PWM signals. Hence, there is a total of 16 PWM signal output available on Raspberry Pi Pico. All GPIO pins can be configured to get any PWM signal output.
How to Initialize PWM in MicroPython for Raspberry Pi Pico
We are going to follow the steps stated below in order to configure PWM in our Raspberry Pi Pico.
- Firstly, we have to choose the PWM pin.
- Next, we set a particular frequency for our digital signal. 1000Hz is a good value to start off with to work with an LED.
- Raspberry Pi Pico has 12 bit resolution but in MicroPython it is scaled to 16 bits. Hence the duty cycle will be set from 0-65535 which corresponds to 0-100%
MicroPython LED Fading Example using PWM
Now we will learn how to build a simple circuit that fades the LED according to PWM signals. The following components are required to perform this procedure:
- Raspberry Pi Pico
- One LED
- One 220 ohm resistor
- Connecting Wire
We will connect the LED’s anode pin to GPIO13 through a 220 ohm resistor. The cathode pin will be grounded. But you can choose any other suitable PWM pin as well. Make your circuit connections as shown in the diagram below:
MicroPython PWM Library
In order to use the PWM module in our raspberry Pi Pico we have to follow steps:
- Importing the PWM class.
- Secondly, creating a PWM pin object for the LED. In the PWM object we will the pin the LED is connected to as as a parameter. For example: pwmObject = PWM(Pin(13) shows the PWM is connected on GPIO13.
- Next we set the frequency using the PWM pin object: pwmObject.freq(1000). This sets the PWM frequency to 1000Hz.
- Lastly, we will set a duty cycle for the PWM signal. For example: pwmObject.duty_u16(duty). Currently, MicroPython implementation of PWM for Raspberry Pi Pico supports 16-bit duty cycle resolution. Therefore, the value of duty cycle can vary between 0 and 65,535. That means, if we set the duty of PWM signal to 0% LED will not glow at all and similarly with 100% duty cycle, LED will go with its full brightness capacity.
MicroPython PWM Script
We will fade the LED (low to high) by increasing the duty cycle in our program code. To set a PWM signal, we will define these following parameters in the code:
- Frequency of the signal
- Duty cycle
- GPIO pin where you want to output the signal
We will create a script for PWM for Raspberry Pi Pico in MicroPython.
from machine import Pin, PWM from time import sleep led = PWM(Pin(13)) led.freq(1000) while True: for duty in range(0,65535): led.duty_u16(duty) sleep(0.0001)
How Code Works?
Now I will explain the steps in which the program code is working.
Importing PWM and Pin Classes
Firstly, in order to interact with the PWM module, we will import the PWM class from the machine module of MicroPython. In order to create a PWM pin to read input/output GPIOs, we will also import the PWM class. We will import the machine module that contains classes to interact with the GPIOs. The sleep module is also imported for use in delays.
from machine import Pin, PWM from time import sleep
Create PWM Pin Object
Next we create a PWM pin object called led to pass the pwm pin as a parameter. The parameter shows where the pin is connected in our case GPIO13.
led = PWM(Pin(13))
Then we will set up the frequency of the PWM signal.
Generate Variable Duty Cycle PWM
Inside the infinite loop, we will generate a ‘for’ loop which increases the duty cycle by 1 in each loop. We also use the range() function to initiate the start, stop, and step. The range() function has three parameters and written as follows: range(start, stop, step).
- Start: This shows the starting value for the duty cycle. In our case, we start with 0 duty cycle.
- Stop: This shows the stopping value for the duty cycle range except for this value. Because the range of duty cycle for Raspberry Pi Pico is between 0-65535 and we want to increment the duty cycle by 1 value on each iteration of for loop. Therefore, we will set the stop value to 65535.
- Step: This shows the incrementation value. As we did not pass the third parameter it is set as default which is 1.
while True: for duty in range(0,65535): led.duty_u16(duty) sleep(0.0001)
During each iteration of for loop, we set the LED’s duty cycle to the current duty value:
After that, the duty variable is incremented by 1. Changing the duty cycle is how you produce different levels of brightness.
To see the demo of above code, copy this code to Thonny IDE. Also, attach the LED to GPIO13 of Raspberry Pi Pico. You will see that the brightness of LED increases from low to the highest value as shown in the video below:
You can also see the output PWM waveform by connecting an oscilloscope to the GPIO13 pin of Raspberry Pi Pico. By doing so, you will see that that the frequency of out signal is 1kHz and duty cycle will also vary from 0% to a maximum value of 100%.
Raspberry Pi Pico Brightness Control using PWM and Variable Resistor
Now, we will learn how to control the brightness of an LED using the PWM module in Raspberry Pi Pico. In the previous example we achieved this feature by increasing the duty cycle but this time we will change the brightness using a potentiometer. In order to perform this project we need the following equipment:
- Raspberry Pi Pico
- One LED
- One 220 ohm resistor
- One 10k potentiometer
- Connecting wires
Connect the components as shown in the schematic diagram below:
Brightness Control MicroPython Script
from machine import Pin, ADC, PWM #importing Pin, ADC and PWM classes from time import sleep #importing sleep class led=PWM(Pin(13)) #GPIO13 set as pin led.freq(1000) potentiometer=ADC(28) #creating potentiometer object while True: potentiometer_value=potentiometer.read_u16() #reading analog pin print(potentiometer_value) led.duty_u16(potentiometer_value) #setting duty cycle value as that of the potentiometer value sleep(0.25)
How the Code works?
Firstly we are importing the pin, ADC, and the PWM classes from the machine module and the sleep class from the time module.
from machine import Pin, ADC, PWM #importing Pin, ADC and PWM classes from time import sleep
Next, we are creating a Pin object specifying the GPIO pin connected with the LED. This is getting stored in the variable ‘led’ which acts as the output. Then we set up the frequency of the PWM signal.
led=PWM(Pin(13)) #GPIO13 set as pin led.freq(1000)
‘potentiometer’ variable stores the value for the input ADC object connected on pin GPIO28.
You can read this article on Raspberry Pi Pico ADC:
Read Analog Signal and Set Duty Cycle
Inside the infinite loop we are reading the analog pin through the method read_u16() from the potentiometer variable and storing it in potentiometer_value. This value will vary from 0-65536 because we have 16 bit resolution. You will be able to see the values getting printed on the screen. This value is given as a parameter inside the duty_u16() method which is being accessed through the ‘led’ object.
while True: potentiometer_value=potentiometer.read_u16() #reading analog pin print(potentiometer_value) led.duty_u16(potentiometer_value) #setting duty cycle value as that of the potentiometer value sleep(0.25)
When you run this code on your Raspberry Pi Pico and rotate the potentiometer knob, you will get the value of ADC after every 0.25 seconds as you can see in the figure below:
Increasing input values from the potentiometer act as increasing duty cycle hence the brightness of the led increases .
In this tutorial, we learned about the PWM module of Raspberry Pi Pico by fading LED as well as controlling its brightness through a variable resistor using MicroPython.
You may also like to read: