• Raspberry Pi Pico - Multicore Adventures

    02/04/2021 at 23:16 0 comments

    Introduction

    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 »