Hey everyone, I hope you are enjoying the Raspberry Pi Pico tutorial series. In this tutorial, we are going to control two LEDs by multithreading with dual-core programming on the Raspberry Pi Pico using MicroPython. So far we have seen how to interface an OLED, a LCD, a Servo, an Ultrasonic Sensor and we have implemented the I2C, ADC, Bluetooth communication with the Raspberry Pi Pico. The RP2040 microcontroller of the pico board has dual cores. If you're unfamiliar with multithreaded execution, then just think about your computer system. It can execute multiple programs at the same time which can be operated by an operating system using multithreading. But we don’t have any operating system on the Raspberry Pi Pico that controls CPU cycles, it can only support one thread per core, which is two in this situation.
Components required for the Dual-Core Programming on Raspberry Pi Pico
You need to make sure that you have the following components to demonstrate the dual-core programming on the Pico board.
- Raspberry Pi Pico
- LED x2
- Resistors x2 (330 ohms)
- Breadboard
- Connecting Wires
Servo Motor Circuit Diagram using the Raspberry Pi Pico Board
The circuit diagram of Servo Motor is so simple. I have attached two LEDs using two 330ohm resistors respectively with the GPIO15 and GPIO16. The ground pins of the LEDs have been connected to the ground pins of the Pico board.
Multithreading on Raspberry Pi Pico using Dual Core Programming
You need to clone our Raspberry Pi Pico Tutorial GitHub repository. Then open the “T9_DualCore_Program_PIco” folder. Inside this folder, you can find the “Codes” folder. Open the “main.py” python file in the Thonny editor. Now, let’s discuss about the main.py file.
from machine import Pin import utime import _thread
At first, we need to import the Pin() class from the machine.py library as mentioned above. In our previous tutorials, we have used the machine library so many times and I hope you are now familiar with the machine library. Then we need to import the “utime” library to use the internal clock of the pico. We are using the “_thread” library to use the threading functions made by the raspberry pi pico community.
led1 = Pin(16, machine.Pin.OUT) led2 = Pin(15, machine.Pin.OUT) sLock = _thread.allocate_lock()
In the above code I have initialized the two LEDs with GPIO15 and GPIO16 as OUPUT by using the “Pin(16, machine.Pin.OUT)” and the “Pin(15, machine.Pin.OUT)” functions. The “_thread.allocate_lock()” function can be used to provide a semaphore lock to both threads. If you want to know about this function in detail, then you can refer to the documentation of the “_thread” library.
def CoreTask(): while True: sLock.acquire() print("Entered into the second Thred") utime.sleep(1) led2.high() print("Led 2 turned on") utime.sleep(2) led2.low() print("Led 2 turned off") utime.sleep(1) print("Exiting from the 2nd Thread") utime.sleep(1) sLock.release() _thread.start_new_thread(CoreTask, ())
We are going to use the “CoreTask()” function in the other core with a single thread. In the while loop within the function, we are engaging a semaphore lock to hold the thread until it will get completed. Then I turned the led2 high for 1 second and printed the instruction on the output terminal of the Thonny. Then I am releasing the semaphore lock when the thread is completed. The “_thread.start_new_thread(CoreTask, ())” function will start the thread. This function takes the target function name as the first parameter. In my case it is “CoreTask” and it takes arguments in the second parameter. In my case, I don’t have any arguments to be passed.
while True: # We acquire the semaphore lock sLock.acquire() print("Entered into the main Thred") led1.toggle() utime.sleep(0.15) print("Led 1 started to toggle.") print("Exiting from the main Thread") utime.sleep(1) # We release the semaphore lock sLock.release()
In the above while loop, we are similarly using another semaphore lock so that the main thread keeps running until it gets completed. It will toggle the led1 and then release the semaphore lock. Now, in the Thonny IDE, open the “main.py” file. To begin, save the “main.py” file on the Pico board by pressing the “ctrl+shift+s” keys on your keyboard. Before saving the files, make sure your Pico board is connected to your laptop. When you save the code, a popup window will appear, as shown in the image below. You must first select the Raspberry Pi Pico, then name the file “main.py” and save it. This procedure enables you to run the program when the Pico is turned on.
When you upload and run the code on Pico board, you will see that led1 that is connected to the GPIO16 is toggling with a delay of 1.15 seconds. But the led2 that is connected to the GPIO15 is blinking with a delay of 2 seconds. You can refer to the following video below for more details.
main.py
import machine import utime import _thread led1 = machine.Pin(16, machine.Pin.OUT) led2 = machine.Pin(15, machine.Pin.OUT) sLock = _thread.allocate_lock() def CoreTask(): while True: sLock.acquire() print("Entered into the second Thred") utime.sleep(1) led2.high() print("Led 2 turned on") utime.sleep(2) led2.low() print("Led 2 turned off") utime.sleep(1) print("Exiting from the 2nd Thread") utime.sleep(1) sLock.release() _thread.start_new_thread(CoreTask, ()) while True: # We acquire the semaphore lock sLock.acquire() print("Entered into the main Thred") led1.toggle() utime.sleep(0.15) print("Led 1 started to toggle.") utime.sleep(1) print("Exiting from the main Thread") utime.sleep(1) # We release the semaphore lock sLock.release()