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 throught 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.
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 firt see, how you would approach this on single core board.
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
This would be some simplified code for blinking two LEDs with different speeds on Arduino. But how about Pico.
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
It is really that simple. I’ll attach the
CMakeLists.txt, so you can compile and try for yourself.
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.
There are two FIFO (First In, First Out registers, each 32-bits wide and 8 entries deep. One can be only used to write from core0, and the other only to write from core1. They both can be read from both cores. That means you can essentially have full duplex communication between cores. But that’s not important. There are few, really self explanatory methods that utilizes these registers. And one very important note, every time you push something onto the FIFO, a corresponding IRQ will be set. Since those operations are not asynchronous, you HAVE to use the interrupts, and handle them accordingly. So, let’s dive into the program.
// import libraries
As we can see, it is nothing really difficult. It took me some time to figure out which interrupt flags correspond to FIFO registers, but eventually I managed to get it to work. How does it works then? Well, it’s commented, go and read the comments.
But for you lazy people, here’s TLDR:
We set up a handler, that prints stuff from FIFO stack. Then, we wait for the interrupt on the core1, while doing some important stuff. On the core0, we take measurement from one of the ADCs each second, and push the value onto the FIFO. When this happens, interrupt request occurs that is handled on core1. Core0 can meanwhile still take measurements and push them onto the stack.
Aaaand I almsot forgot, here’s the
That will be it for program showcase, I think you should get a pretty good idea of how this thing works. It is really simple, and the idea behind it is extremely clever - using the FIFO registers solved so much hassle that would otherwise had to be solved by shennanigans regarding protected memory and heaps. It is well thought system, and after a bit of getting used to, it is no big deal.