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. |
Symmetric Multiprocessing in RTOS
There are several ways to set up an RTOS on a multi-core controller.
- 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)
- You can run it on one core and let the second core run in isolation (e.g.: memory protection/validation)
- You can run it on one core and make the other sleep
- You can run it on multiple cores, and make the individual schedulers pick tasks from shared task lists (automatic load balancing)
- 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: 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...
Top Comments