-
Raspberry Pi Pico - Multicore Adventures
02/04/2021 at 23:16 • 0 commentsIntroduction
While I was writing my first impression post, I was thinking about how to utilize both cores. I grew up on Arduino, which is single core, and wasn’t really messing around that much with ESP, nor big Pi’s. That was, until now. For some reason, the first thing I thought when browsing through C++ SDK Reference was “how can I use both of these cores? Is it as painful as on desktop?” Well, I have answers for you, with some code
Projects
Multicore Blink
So, the first thing you do when learning something new, you are going for the simplest stuff that you can think of. And for me, the simplest thing that I can think of that could be done on microcontroller is blinking LEDs. So naturally, I wanted to know, if I can utilize both cores to blink two LEDs with independent timing. But to explain stuff in better detail, let’s first see, how you would approach this on single core board.
Timer Approach
On Arduino boards, there is this little function called
millis()
, that lot of people get confused about. I don’t understand why, as it simply uses one of AtMega8’s timers to count, how many milliseconds elapsed since the processor booted up. You can compare this value with whatever you want, and do math with it. And if you know what modulo is, you probably now know, how to blink 2 LEDs with different speed. You just check at different values, and if they are true, you blink. Simple.// get the state of the counter; how many ms has elapsed uint64_t time = millis(); // check if they are divisible by 2000ms (2s) or 3000ms (3s), and toggle appropriate LED if(time % 2000 == 0) { toggleLED(); } else if (time % 3000 == 0) { toggleAnotherLED(); }
This would be some simplified code for blinking two LEDs with different speeds on Arduino. But how about Pico.
Just use two cores, duh
If you dig into the documentation, you’ll find out that the lovely devs left us with quite a few methods to access the multicore API. What we are interested in is
multicore_launch_core1()
function. It takes just one parameter, and that is the name of the function that shall be executed on second core. That is it. So, let’s write a simple program that blinks the on-board LED with 333ms delays, and LED on GPIO 0 with 500ms delays.// import libraries #include <stdio.h> #include "pico/stdlib.h" #include "hardware/adc.h" #include "hardware/timer.h" // define on which pins are LEDs #define LEDG 25 #define LEDB 0 //this function will execute on core1 void core1_blink() { //initialize pin, and set to output gpio_init(LEDG); gpio_set_dir(LEDG, GPIO_OUT); // create infinite loop, which will toggle the green on-board LED with 333ms delays while(1) { gpio_put(LEDG, 1); sleep_ms(333); gpio_put(LEDG, 0); sleep_ms(333); } } // this function runs on core0 by default, and is basically the same as the one above, with exception of different pin and delay times void main() { // start the function on core1 multicore_laucnhe_core1(core1_blink); //initialize pin, and set to output gpio_init(LEDB); gpio_set_dir(LEDB, GPIO_OUT); // create infinite loop, which will toggle the blue LED on pin0 with 500ms delays while(1) { gpio_put(LEDB, 1);ä sleep_ms(500); gpio_put(LEDB, 0); sleep_ms(500); } }
It is really that simple. I’ll attach the
CMakeLists.txt
, so you can compile and try for yourself.cmake_minimum_required(VERSION 3.13) include(pico_sdk_import.cmake) project(multicore_blink) pico_sdk_init() add_executable(multicore_blink main.c ) pico_add_extra_outputs(multicore_blink) target_link_libraries(multicore_blink pico_stdlib) target_link_libraries(multicore_blink pico_multicore)
Reading ADC on one core, printing on the other
As it’s well known, handling data between cores/threads is not an easy task. On desktop particuraly, it is really, really complex and you can run into difficult situations. Fortunately for us, everything on Pico is very well documented and set up, so you don’t need anything really special to pass data between cores....
Read more »