Two Tasks on Two Cores

For my next project I had a closer look on the Raspberry Pi Pico. It is a nice little board using a Cortex M0 based MCU. The Raspberry Foundation developed its own controller: The RP2040.

Cortex M0 is a dual core MCU. Combined with its 28 GPIO pins there seems to be a lot of space for it in a maker’s lab. Currently the Pico only supports one task per core to be executed. To be able to interchange data between the two tasks the SDK introduces two queues. Each of them can be written by one task and read by the other.

Queues for interchanging data between the cores

All you have to to is to include Pico’s SDK multicore header:

#include "pico/multicore.h"

And start a second task on core1. We use core1 because core0 is the default core. To start a task on core1 we pass the task’s name to function multicore_launch_core1() in our main function.

multicore_launch_core1(function_to_execute_on_core1);

Writing (push) and reading (pop) to the queues is done by the blocking funcions:

void multicore_fifo_push_blocking (uint32_t data)
uint32_t multicore_fifo_pop_blocking (void)

If you don’t like your programm to be blocked until a message in the queue is available, you can use multicore_fifo_rvalid () to check if there are new messages before reading.

static bool multicore_fifo_rvalid (void)

For further information on the functions and all other multicore functions please refer to the API documentation.

#include "pico/multicore.h"
#include "pico/stdlib.h"
#include <iostream>

void core1Blink(void)
{
int pin = 14;
uint32_t fromCore0 = 0;

gpio_init(pin);
gpio_set_dir(pin, GPIO_OUT);

while(true)
{
if( multicore_fifo_rvalid() == true )
{
fromCore0 = multicore_fifo_pop_blocking();
std::cout<<"R core1: "<<fromCore0<<std::endl;

fromCore0 += 10;
}

gpio_put(pin, true);
sleep_ms(200);
gpio_put(pin, false);
sleep_ms(200);

multicore_fifo_push_blocking(fromCore0);
std::cout<<"S core1: "<<fromCore0<<std::endl;
}
}

int main()
{
uint32_tfromCore1 = 0;

stdio_init_all();
multicore_launch_core1(core1Blink);

int pin = 15;

gpio_init(pin);
gpio_set_dir(pin, GPIO_OUT);

multicore_fifo_push_blocking(fromCore1);

while(true)
{
if( multicore_fifo_rvalid() == true )
{
fromCore1 = multicore_fifo_pop_blocking();
std::cout<<"R core0: "<<fromCore1<<std::endl;
}

gpio_put(pin, true);
sleep_ms(100);
gpio_put(pin, false);
sleep_ms(100);

fromCore1++;
multicore_fifo_push_blocking(fromCore1);
std::cout<<"S core0: "<<fromCore1<<std::endl;
}
}

The above programm generates two differnet PWM signals on pins 14 and 15. A uint32_t variable is interchanged using the FIFOs and incremented.

Before you build this program don’t forget to add library pico_multicore in your CMAkeLists.txt to the target_link_libraries.

Each PWM signal is generated by a different core. I did not set up a circuit with two blinking LEDs. Instead I meassured the output of both pins with my oscilloscope: