element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Raspberry Pi
  • Products
  • More
Raspberry Pi
Blog Four Multicore C programs for Raspberry Pi Pico using Arduino IDE
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Raspberry Pi to participate - click to join for free!
Featured Articles
Announcing Pi
Technical Specifications
Raspberry Pi FAQs
Win a Pi
GPIO Pinout
Raspberry Pi Wishlist
Comparison Chart
Quiz
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: BigG
  • Date Created: 28 May 2021 7:20 PM Date Created
  • Views 16546 views
  • Likes 11 likes
  • Comments 2 comments
Related
Recommended
  • raspberry_pi_pico
  • rp2040
  • arduino-pico
  • multicore

Four Multicore C programs for Raspberry Pi Pico using Arduino IDE

BigG
BigG
28 May 2021

  • Introduction
  • Examples
    • FIFO Blocking routines
    • Non-Blocking (Polling) for FIFO
  • Summary

 

 

Introduction

 

Earlier this week, I spotted that Arduino had updated their ArduinoCore-mbed Boards Manager files for Arduino Mbed OS RP2040 Boards to version 2.1.0.

 

image

 

The exciting part of this update is that it includes the pico-sdk multicore library, which I have been eager to try out for some time now.

 

Unfortunately for Arduino fans, there is no ready-made Arduino multicore examples available on the Arduino IDE. Instead you have to go to the Raspberry Pi Github page and grab the multicore C examples from their pico-examples repository.

 

At the time of writing this blog, there were 4 multicore examples listed on Github.

 

Unfortunately, I found that when inserting these examples into an Arduino sketch, not all compiled as-is via the Arduino IDE.

 

I also found that none of these code examples were designed to run continuously on the RPI Pico, as in, there was no repeated multicore data exchange within a while(true) function or the sketch's loop() function. This made it more difficult for me to work out how the runtime interaction between the two cores actually worked as the examples were all one off events.

 

Thankfully I've made progress and solved a few issues myself, which I now want to share with others.

 

 

Examples

 

FIFO Blocking routines

 

To understand the fundamentals I'll start with two FIFO blocking examples, namely the hello_multicore example and then the multicore_runner example, which uses the same core functions as hello_multicore but in a slightly different way. This latter example uses function pointers, which I hadn't used in Arduino before.

 

The core functions highlighted in both examples are:

 

  • multicore_launch_core1( --NameOfCore1RunTimeEntryFunction--);     // This launches the entry function for core1.
    • This "entry function" can only be a void function. In Arduino terms, think of it as setup() and loop() rolled into one function.
    • You would typically place this multicore_launch_core1 function in your Arduino sketch setup() routine, as it only needs to be called once. You also have the option inside your main code to reset Core1 (using the multicore_reset_core1 (void) function). You cannot "unlaunch" a Core1 entry function during runtime.
    • There are also two other launch functions available:
      • multicore_launch_core1_raw ( void(*entry)(void), uint32_t *sp, uint32_t vector_table )
      • multicore_launch_core1_with_stack ( void(*entry)(void), uint32_t *stack_bottom, size_t stack_size_bytes )

 

  • multicore_fifo_push_blocking(--Data in int32 format--);   // This pushes data on to the FIFO.
    • This function will block until there is space for the data to be sent.
    • You can use the multicore_fifo_wready() function to check if the FIFO is ready to write to.

 

  • multicore_fifo_pop_blocking(void);   // This "pops" data from the FIFO. The data is returned as int32 format.
    • Similarly, this function will block until there is data ready to be read.
    • You can use the multicore_fifo_rvalid() function to check if there is data on the FIFO to be read. This is handy if you do not want to block and wait for data.

 

Now as these two examples don't really do much in terms of bells and whistles, I decided to beef things up a bit and created my own versions of the "hello world" sketch and an alternative "multicore_runner" sketch. Please note that I am using a bit of mbedOS code syntax for my LEDs and I am using Serial1 instead of Serial for my serial output which means the serial stream is transmitted via GP0.

 

Here is the code for my new "hello multicore world" sketch:

 

 

#include <stdio.h>
#include <mbed.h>
#include "pico/multicore.h"


mbed::DigitalOut led1(LED1, 0);
mbed::DigitalOut led2(p2, 0);


void core1_entry() {
  bool Flop = false;
  uint32_t cntr = 0;

  while(1) {
    Flop = multicore_fifo_pop_blocking();
    if (Flop) {
      led2 = !led2;
      Serial1.println("...One!");
    }
    cntr += 10;
    multicore_fifo_push_blocking(cntr);
  }    
}


bool Flip = false;;

void setup() {

  Serial1.begin(115200);
  sleep_ms(500);
  Serial1.print("\r\nHello...");
  sleep_ms(1000);
  Serial1.println("let's hear from our multicores!");
  
  multicore_launch_core1(core1_entry);
  sleep_ms(1400);
  
}

void loop() {
  led1 = !led1;
  multicore_fifo_push_blocking(Flip);
  uint32_t SleepCntr = multicore_fifo_pop_blocking();
  sleep_ms(100 + SleepCntr);
  if (Flip) {
    Serial1.println("...Zero!");
  }
  Flip = !Flip;
}

 

And here is a short video demonstrating the output. You will notice that the onboard LED (led1) blink interval is controlled by Core1 and the 2nd added LED (led2) blink interval is controlled by the multicore_fifo_pop_blocking function inside the Core1 entry function.

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

And here is my new "multicore_runner" sketch:

 

#include <stdio.h>
#include <mbed.h>
#include "pico/multicore.h"

mbed::DigitalOut led1(LED1, 0);
mbed::DigitalOut led2(p2, 0);

void core1_entry() {
    
  while (1) {
    // Function pointer is passed to us via the FIFO
    // We have one incoming int32_t as a parameter, and will provide an
    // int32_t return value by simply pushing it back on the FIFO
    // which also indicates the result is ready.

    int32_t (*func)(int32_t) = (int32_t(*)(int32_t)) multicore_fifo_pop_blocking();
    int32_t p = (int32_t)multicore_fifo_pop_blocking();
    led2 = !led2;    
    int32_t result = (*func)(p);
    multicore_fifo_push_blocking(result);
    
  } 
}


int32_t factorial(int32_t n) {
    int32_t f = 1;
    for (int i = 2; i <= n; i++) {
        f *= i;
    }
    return f;
}

int32_t fibonacci(int32_t n) {
    if (n == 0) return 0;
    if (n == 1) return 1;

    int n1 = 0, n2 = 1, n3;

    for (int i = 2; i <= n; i++) {
        n3 = n1 + n2;
        n1 = n2;
        n2 = n3;
    }
    return n3;
}

int32_t rNum = 0;

void setup() {

  Serial1.begin(115200);
  sleep_ms(100);
  Serial1.println("\r\nHello, multicore_runner!");

  randomSeed(analogRead(A0));
  
  // This example dispatches arbitrary functions to run on the second core
  // To do this we run a dispatcher on the second core that accepts a function
  // pointer and runs it
  multicore_launch_core1(core1_entry);
  
}

void loop() {
  int32_t result;
  led1 = !led1;
  sleep_ms(500);
  
  rNum = random(0, 16);
  
  multicore_fifo_push_blocking((int32_t) &factorial);
  multicore_fifo_push_blocking(rNum);

  // We could now do a load of stuff on core 0 and get our result later

  result = multicore_fifo_pop_blocking();

  Serial1.println("Factorial " + String(rNum,DEC) + " is " + String(result, DEC));

  // Now try a different function
  led1 = !led1;
  sleep_ms(500);
  multicore_fifo_push_blocking((int32_t) &fibonacci);
  multicore_fifo_push_blocking(rNum);

  result = multicore_fifo_pop_blocking();

  Serial1.println("Fibonacci " + String(rNum,DEC) + " is " + String(result, DEC));
}

 

And another short video demonstrating the output. Here you will notice that the onboard LED (led1) blink interval is simply controlled by the sleep duration while the 2nd added LED (led2) blink interval is controlled by the multicore_fifo_pop_blocking function inside the Core1 entry function.

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

 

Non-Blocking (Polling) for FIFO

 

If you want both cores to run independently without the "pop" or "push" functions holding things up by waiting to receive and send data you can use two other functions. These essentially provide a means to peek inside the pop FIFO buffer to see if any data is available or peeks inside the push FIFO to see if data can be written into this buffer and then lets you know.

 

  • bool multicore_fifo_rvalid (void); This checks the read FIFO buffer to see if there is data waiting and returns true if the FIFO has data.
  • bool multicore_fifo_wready (void); This checks the write FIFO buffer to see if it is available or otherwise and returns true if ready (note SDK documentation states that it returns true if full but it does not appear to do so).

 

For my first home-grown non-blocking example I included just the multicore_fifo_rvalid check in the Core 1. In the video you will see that the onboard LED (led1) eventually stops blinking when the write buffer gets full.

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

Then in the second non-blocking example I included both the multicore_fifo_rvalid check in the Core 1 and a multicore_fifo_wready check in Core 0. In this video you will notice that both LED's (led1 and led2) continue to behave independtly and there is no blocking with the onboard LED (led1) when the write buffer gets full.

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

In terms of code, the only difference between these two non-blocking examples is this line of code, which was added to the 2nd non-blocking example. In the 1st non-blocking example we simply use multicore_fifo_push_blocking(t_int2) without the if statement.

 

if (multicore_fifo_wready()) multicore_fifo_push_blocking(t_int2);

 

 

The complete code is as follows:

 

#include <stdio.h>
#include <mbed.h>
#include "pico/multicore.h"
#include "hardware/irq.h"


mbed::DigitalOut led1(LED1,0);
mbed::DigitalOut led2(p2,0);


void core1_entry() {

  uint32_t t_int = millis();
  uint8_t cntr = 0;
  int32_t LEDint = 500;

  while(1) {
    if ((millis() - t_int) > LEDint) {
      t_int = millis();
      led2 = !led2;
      cntr++;
    }
    if (multicore_fifo_rvalid()) {
      if (cntr > 10) {
        LEDint = multicore_fifo_pop_blocking();
        cntr = 0;
      }
    }
  }
    
}

uint8_t cntr2 = 0;
int32_t t_int2 = 1000;

void setup() {

  pinMode(LED1, OUTPUT);
  pinMode(p2, OUTPUT);

  Serial1.begin(115200);
  sleep_ms(100);
  Serial1.print("\r\nHello this is fancy FIFO IRQ's");
  
  //analogWrite(p2, value);
  multicore_launch_core1(core1_entry);
  
}

void loop() {
  led1 = !led1;
  sleep_ms(250);
  if (cntr2 > 3) {
    if (multicore_fifo_wready()) multicore_fifo_push_blocking(t_int2);
    t_int2 += 1000;
    cntr2=0;
  }
  else cntr2++;
}

 

 

Summary

 

Hopefully these four two examples have helped you understand how multicore works using both the blocking and non-blocking functionality during runtime. I have still to test the use of non-blocking service interrupt routines, as found in the multicore_fifo_irqs example. I did try to use the queues library functions but at the time of writing I had problems with getting the pico queue library working via the Arduino IDE.

  • Sign in to reply

Top Comments

  • BigG
    BigG over 4 years ago in reply to Jan Cumps +4
    PSoC6 remains the gold standard, in my opinion. There's still plenty of teething problems with the Pico. For example you cannot use delay (or sleep_ms) in Core1. It locks up.
  • Jan Cumps
    Jan Cumps over 4 years ago +2
    I've been plying with multicores too - 2 ARM cores on the Infineon PSoC6 . What you do here looks and feels like some of the examples there ...
  • BigG
    BigG over 4 years ago in reply to Jan Cumps

    PSoC6 remains the gold standard, in my opinion. There's still plenty of teething problems with the Pico. For example you cannot use delay (or sleep_ms) in Core1. It locks up.

    • Cancel
    • Vote Up +4 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 4 years ago

    I've been plying with multicores too - 2 ARM cores on the Infineon PSoC6 .

    What you do here looks and feels like some of the examples there ...

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube