element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • 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
  • About Us
  • 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 Raspberry Pico - Review multi-core FreeRTOS SMP
  • 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: Jan Cumps
  • Date Created: 26 Sep 2022 10:02 PM Date Created
  • Views 2128 views
  • Likes 6 likes
  • Comments 4 comments
Related
Recommended
  • pico_freertos_smp
  • pico
  • smp
  • freertos

Raspberry Pico - Review multi-core FreeRTOS SMP

Jan Cumps
Jan Cumps
26 Sep 2022
Raspberry Pico - Review multi-core FreeRTOS SMP

FreeRTOS Symmetric Multiprocessing (SMP) is a recent version of the RTOS that can schedule tasks across multiple controller cores. It's currently in test phase, and they have a version for the RP2040. In this blog post, I review symmetric multiprocessing. I'll also review how SMP is used in the Pico demos.
image
Prerequisite is that you are able to run the SMP blinky from the previous post.

Symmetric Multiprocessing in RTOS

There are several ways to set up an RTOS on a multi-core controller.

  1. You can run it on one core and use the second one to perform specific processor-heavy functionally to offload the RTOS core (e.g.: encrypt/decrypt duty on the second core)
  2. You can run it on one core and let the second core run in isolation (e.g.: memory protection/validation)
  3. You can run it on one core and make the other sleep
  4. You can run it on multiple cores, and make the individual schedulers pick tasks from shared task lists (automatic load balancing)
  5. You can run it on multiple cores, and (deprecated: pin tasks to a particular core) exclude tasks from running on particular cores.

The last two patterns, where cores run their own RTOS, are examples of SMP. The others are AMP, asymmetric multiprocessing.

These two demos use SMP pattern 4, where the RTOS chooses and balances:

  • Blinky demo
  • Comprehensive demo

Then there is an example that shows pattern 2, where the RTOS runs on one core.

  • Multicore demo

This comes in two flavours, one that runs the RTOS on core 0, the other executes it on core 1.

The blog series will focus on the comprehensive demo. That one shows best that different RTOS tasks are actively running at the same time on different cores.
image
image: RTOS tasks vCompetingMathTask3 and vCompetingMathTask4 each running on one of the RP2040 dual cores

Caveats

FreeRTOS makes assumptions that only hold if the scheduler is running on a single core. So do many existing applications that use FreeRTOS. The FreeRTOS SMP Change Description document discusses them. These assumptions are sound and valid. The kernel maintainers decided that the guardrails, needed for safe multitasking, have a too big impact on the code base to incorporate them in the main single-core product. They made a dedicated branch for FreeRTOS SMP. I think this makes sense. These are the main changes and differences (italic means it's a direct quote from the change document):

  • It can be possible for multiple tasks with different priority levels to run simultaneously.
    in a single core environment this [] means that a high priority task can be sure that a lower priority task will not be able to execute until it willingly gives up control. The same cannot be said in an SMP environment.
    It's common for firmware to depend on this. The SMP implementation has a directive that can enforce this in multi-core too. At the cost of having less schedule flexibility. When writing new code, it's a good idea to disable this directive.
#define configRUN_MULTIPLE_PRIORITIES           1
  • simply disabling interrupts is not a viable method for entering a critical section
    Critical sections are those that have guarantee that they will not be disturbed by anything. They have exclusive CPU focus. In a single core, the only possible disturbance is from interrupts. When you entered a critical section, interrupts would be disabled, and nothing could steal CPU ticks or create new locks on resources. With multicore execution, there is now activity that can interfere with the execution. A task on the other core can for instance grab a resource and you're no longer certain to have all critical access. A mechanism is added in the critical section functions to handle this.

  • one idle task is created per core
    There are now as many idle tasks as there are cores. Some projects use these tasks to go to a lower power mode. Others do maintenance activities like memory/resource cleanup/defragmentation. You can still do the same, but take care that you don't put things to sleep that are needed by the other core. Or duplicate the maintenance tasks. Also be careful with activities like memory maintenance. Because there may now be an active task using that memory.

First preview of the Comprehensive demo

This demo is similar to the one you find in the single core FreeRTOS branch. When you execute it, you 'll see different behaviour though. The example has a number of competing tasks, called vCompetingMathTask1() to 4(). They all take significant processor time, and are all submitted with the same priority.

On a single core implementation, these will all get a share of the single processor. When the RTOS is configured for preemption, the scheduler will activate and deactivate task execution based on priority. When preemption isn't enabled, long running tasks like the four math tasks must yield focus back to the scheduler, so that it can give CPU time to the next task. But in essence, all tasks get a similar timeslot (if slicing is enabled; else each runs until it finishes), and will never be active at the same time.

In the SMP version, it is possible (and very likely) that some of the vCompetingMathTaskX() tasks are active at the same time. The image above shows vCompetingMathTask3() to vCompetingMathTask4() active and running at the same time.

The current version of this demo runs in compatibility mode, so that low priority tasks are never running while a higher priority task is active. I haven't found a true FreeRTOS SMP example yet that disabled it. The two MultiCore demos have the compatibility setting disabled, but that doesn't count. In those examples the OS scheduler runs on a single core.

a deeper preview follows. And my first attempt to write a dual core project...

Show All Blog Posts

  • Sign in to reply

Top Comments

  • scottiebabe
    scottiebabe over 3 years ago +2
    RP2040: You can see what core your thread is running on by reading the CPUID register: #include "hardware/regs/sio.h" int core = sio_hw -> cpuid; Perhaps there are other ways too... You might see…
  • DAB
    DAB over 3 years ago

    Nice find Jan.

    I look forward to your future posts.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • scottiebabe
    scottiebabe over 3 years ago in reply to Jan Cumps

    Ohh that's fancy, an inline function. Very neat! We also get atomic test-set functions with the SIO spinlocks. 

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps over 3 years ago in reply to scottiebabe

    int core = sio_hw->cpuid;

    Perhaps there are other ways too...

    There's a function:

    /*! \brief Get the current core number
     *  \ingroup pico_platform
     *
     * \return The core number the call was made from
     */
    __force_inline static uint get_core_num(void) {
        return (*(uint32_t *) (SIO_BASE + SIO_CPUID_OFFSET));
    }

    It uses the SIO_BASE definition from pico-sdk\src\rp2040\hardware_regs\include\hardware\regs\addressmap.h, and SIO_CPUID_OFFSET from ..\sio.h

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • scottiebabe
    scottiebabe over 3 years ago

    RP2040: You can see what core your thread is running on by reading the CPUID register:

    #include "hardware/regs/sio.h"

    int core = sio_hw->cpuid;

    Perhaps there are other ways too...

    You might see one of your threads bounce between cores. 

    • 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