Introduction to RTOS Part 12 - Multicore Systems | Digi-Key Electronics
Understanding Multi-Core Microcontrollers
Introduction to Multi-Core Microcontrollers
- Microcontrollers with multiple cores are increasingly popular for parallelizing tasks, particularly in applications like machine learning and Wi-Fi stacks.
- The discussion begins with the distinction between asymmetric multiprocessing (AMP) and symmetric multiprocessing (SMP).
Asymmetric vs. Symmetric Multiprocessing
- AMP involves one core managing the operating system and distributing tasks to other cores, which may have their own OS.
- In contrast, SMP treats all cores equally, sharing a single OS and allowing each core to access a common task list.
- SMP typically uses identical architectures for its cores to ensure tight coupling for resource sharing.
ESP32 Architecture Overview
- The ESP32 features two cores: the protocol core (CPU0) for communication protocols and the application core (CPU1).
- Each core has its own cache memory; however, they share instruction RAM which affects determinism in SMP programming.
Task Management in FreeRTOS on ESP32
- FreeRTOS does not natively support multi-core execution; insights shared are specific to the ESP-IDF port of FreeRTOS.
- Each core operates an independent scheduler with separate tick timers, meaning tasks on different cores may not execute synchronously.
Practical Application Example
- Tasks can be pinned to specific cores or allowed to run on either core using task affinity constants.
- An example is provided where a low-priority task and a high-priority task are created; both initially assigned to Core 0 lead to scheduling issues due to lack of yielding.
Observations from Code Execution
- Running both tasks on Core 0 results in one task monopolizing CPU time until a watchdog timer resets it after several seconds.
- Solutions include pinning tasks across both cores or utilizing task affinity constants for better load distribution.
Scheduler Behavior Insights
- After implementing task affinity constants, both tasks run periodically across available cores without conflict.
Understanding Task Scheduling on ESP32
Core Affinity and Task Scheduling
- The core affinity field determines if a task can run on specific cores (core 0, core 1) or has no affinity. If the calling core matches this field or is set to no affinity, the task can be executed.
- Mixing pinned and unpinned tasks complicates predictions about which core will execute each task. While technically deterministic, calculating exact timing of events becomes nearly impossible due to this complexity.
- Pinning a task to a specific core allows it to utilize that core's cache effectively. Conversely, switching cores without affinity leads to cache misses, increasing data fetching time from main memory.
- On the ESP32 architecture, each core has its own set of interrupts. External events can trigger these interrupts, but knowing which task was halted becomes challenging when schedulers choose tasks arbitrarily.
- Internal peripherals in each core can also trigger interrupts; however, they cannot affect other cores. Understanding these configurations is crucial for effective programming.
Benefits and Drawbacks of Task Pinning
- Deciding whether to pin tasks or let schedulers manage them involves weighing benefits like ease of use against potential drawbacks such as loss of load balancing.
- Allowing schedulers to decide on task execution generally optimizes CPU utilization by minimizing idle time across cores when tasks are ready.
- Pinning tasks provides more control over interrupt locations and reduces cache misses but requires significant effort in optimal scheduling and placement.
- Execution determinism improves with pinned tasks since you know exactly which core runs which task—important for applications requiring precise timing like medical devices or space missions.
- The ESP32 pins Wi-Fi and Bluetooth tasks to core zero for better performance while maintaining shared memory access for kernel objects.
Practical Demonstration: Semaphore Usage
- A demonstration shows how Task 0 runs on Core 0 while Task 1 operates on Core 1 using a binary semaphore created in setup. This illustrates inter-core communication effectively.
- Critical sections in FreeRTOS are marked using
task enterandexit, preventing scheduler activity during execution. This method is stricter than mutexes as it disables interrupts up to a certain priority level.
Complexity with Spin Locks
- In ESP-IDF, entering critical sections requires spin locks—a global variable that forces waiting cores into a loop until the lock is available, differing from traditional mutex behavior.
- An example demonstrates long delays within critical sections affecting scheduling; despite halting one task for an extended period, another continues executing due to running on different cores.
Understanding Critical Sections in ESP32
Core Behavior During Critical Sections
- When Task 1 is inside the critical section, Core 0 spins idly waiting for the lock to be released. This behavior leads to unexpected timing issues with Core 1.
- The expected behavior of pin 12 remaining stable while Core 1 is active does not occur; instead, it toggles unexpectedly due to scheduling interruptions caused by critical sections.
- The ESP-IDF attempts to compensate for lost ticks during long critical sections, which can disrupt task timing and lead to inaccuracies in task management.
- To mitigate these issues, it's recommended to keep critical sections as short as possible or avoid them entirely when feasible.
Modifying Code for Dual-Core Support
- A challenge is presented: convert the existing project to utilize both cores of the ESP32 effectively. Task A (averaging samples) should run on Core 0, while Task B (echoing characters) runs on Core 1.
- The application should maintain its functionality—responding correctly when "avg" is entered in the serial terminal and echoing characters back accurately.
- Utilizing kernel objects for data synchronization between tasks will require minimal code changes to achieve dual-core support.
Conclusion and Future Directions
- The series concludes with a note of gratitude for following along and encouragement for further exploration into real-time operating systems (RTOS).