Introduction to RTOS Part 12 - Multicore Systems | Digi-Key Electronics

Introduction to RTOS Part 12 - Multicore Systems | Digi-Key Electronics

¿Cómo funcionan los microcontroladores de múltiples núcleos?

Introducción a los microcontroladores de múltiples núcleos

  • Los microcontroladores con más de un núcleo están ganando popularidad, permitiendo la paralelización de tareas, especialmente útiles en aprendizaje automático y pilas Wi-Fi.
  • Se introduce la diferencia entre AMP (multiprocesamiento asimétrico) y SMP (multiprocesamiento simétrico), donde AMP tiene un núcleo encargado del sistema operativo que distribuye tareas a otros núcleos.

Comparación entre AMP y SMP

  • En AMP, un núcleo gestiona el sistema operativo mientras que en SMP todos los núcleos son tratados por igual y comparten una lista común de tareas.
  • Con AMP se pueden usar diferentes arquitecturas para los núcleos, mientras que SMP generalmente utiliza la misma arquitectura para facilitar el acceso compartido a recursos.

Arquitectura del ESP32

  • El ESP32 cuenta con dos núcleos: el núcleo de protocolo (CPU0) y el núcleo de aplicación (CPU1), ambos comparten una memoria y bus de entrada/salida.
  • Aunque parece que hay caché compartida, cada núcleo tiene su propia memoria caché; esto afecta la determinación en programación SMP.

Ejecución de tareas en el ESP32

  • El núcleo de protocolo maneja tareas relacionadas con protocolos como Wi-Fi y Bluetooth, mientras que las aplicaciones deben ejecutarse en el núcleo de aplicación.
  • FreeRTOS no soporta ejecución multi-núcleo por defecto; las implementaciones pueden variar según el RTOS utilizado.

Programación y control de tareas

  • Cada núcleo tiene su propio programador independiente; no se puede asumir sincronización entre las tareas ejecutadas en diferentes núcleos.
  • Al crear una tarea, se puede fijar a un núcleo específico o permitir que cualquier núcleo ejecute la tarea según prioridad.

Ejemplo práctico con código

  • Se presenta un ejemplo donde se crean dos tareas con diferentes prioridades. La tarea alta nunca cede al programador debido a un mal manejo del tiempo.
  • Se observa cómo al fijar ambas tareas al mismo núcleo provoca problemas; se recomienda utilizar constantes para permitir ejecución flexible entre núcleos.

Observaciones finales sobre FreeRTOS

  • Un temporizador watchdog está presente para evitar bloqueos en el núcleo 0. Esto no aplica al núcleo 1 por defecto.

¿Cómo se gestionan las tareas en el ESP32?

Gestión de afinidad de núcleos

  • Un campo determina si una tarea puede ejecutarse en el núcleo 0, núcleo 1 o sin afinidad. Si coincide con el núcleo que llama, la tarea puede ser ejecutada.
  • La mezcla de tareas fijadas y no fijadas complica la predicción del núcleo que ejecutará cada tarea, haciendo que sea casi imposible calcular los tiempos exactos de eventos e instrucciones.
  • Al asignar "sin afinidad" a una tarea, esta puede cambiar de núcleo, lo que provoca fallos en caché y un aumento en el tiempo necesario para acceder a datos desde la memoria principal.

Interrupciones y su manejo

  • En arquitecturas como el ESP32, cada núcleo tiene su propio conjunto de interrupciones. Los eventos externos pueden activar estas interrupciones.
  • Las interrupciones complican aún más la gestión de tareas porque es difícil saber qué tarea fue interrumpida si los programadores deciden arbitrariamente qué ejecutar.

Ventajas y desventajas de fijar tareas

  • Fijar tareas a un núcleo proporciona control sobre las interrupciones; por ejemplo, si se crea una interrupción en el núcleo 0, siempre se ejecutará allí.
  • Permitir que los programadores decidan qué tarea ejecutar optimiza la utilización del CPU al minimizar el tiempo inactivo.
  • Sin embargo, fijar tareas permite un mejor rendimiento al reducir fallos en caché y proporciona determinismo en aplicaciones críticas como equipos médicos.

Ejemplo práctico: semáforos compartidos

  • Se presenta un ejemplo donde la Tarea 0 corre en el Núcleo 0 y la Tarea 1 en el Núcleo 1. La Tarea 0 libera un semáforo cada 500 ms para que la Tarea 1 active un LED.

Secciones críticas y complejidades adicionales

  • En FreeRTOS se utilizan secciones críticas para marcar partes del código donde no debe haber cambios. Estas son más severas que los mutexes ya que detienen al programador e interrumpen hasta cierto nivel.
  • Esp-IDF introduce complejidades adicionales debido a trabajar con dos núcleos; al entrar a una sección crítica es necesario proporcionar un spin lock.

Comportamiento de los Núcleos en Secciones Críticas

Sección Crítica y Comportamiento del Núcleo 0

  • Cuando la tarea 1 está dentro de la sección crítica, el núcleo 0 permanece inactivo esperando que se libere el bloqueo. Se esperaría que el pin 12 mantuviera su nivel actual mientras el núcleo 1 está en la sección crítica.
  • Sin embargo, se observa un comportamiento inesperado: el tiempo de espera del núcleo 1 se altera significativamente, lo que impide que el núcleo cero cambie el estado del pin durante ese período de inactividad.

Problemas con el Temporizador y las Secciones Críticas

  • Al detenerse el programador debido a los marcadores de sección crítica, ESP-IDF intenta calcular cuántas veces debería haberse llamado al temporizador. Esto afecta negativamente a tareas como vtask delay, complicando la gestión del tiempo.
  • La lección es evitar secciones críticas largas; si son necesarias, deben ser lo más cortas posible para minimizar problemas.

Ajustes y Resultados Mejorados

  • Al cambiar el tiempo de retraso a 1 milisegundo y cargar nuevamente el código, se observa una mejora notable: el pin 13 permanece encendido por un milisegundo y permite que el pin 12 cambie durante la inactividad de la tarea 1.

Desafío Propuesto: Soporte para Múltiples Núcleos

  • El desafío consiste en modificar un proyecto existente para soportar ambos núcleos en ESP32. La tarea A (promediar muestras) debe ejecutarse en núcleo cero, mientras que la tarea B (eco de caracteres al terminal serial) debe correr en núcleo uno.
  • Al ingresar "avg" en el terminal serial, debe responder con el promedio más reciente calculado. Aunque esta aplicación es simple para un solo núcleo, proporciona una base sobre cómo trabajar con múltiples núcleos en un RTOS.

Conclusiones Finales sobre RTOS

  • Utilizando objetos del kernel para pasar datos y sincronizar tareas, solo será necesario cambiar unas pocas líneas de código para habilitar soporte dual-core.
Video description

Running tasks in an RTOS on a multicore system can seem daunting at first. Many processors have unique architectures that you must keep in mind when writing programs that use more than one core. We examine the FreeRTOS port for the ESP32 (known as ESP-IDF) and how to synchronize tasks on both cores. The solution to the challenge can be found here: https://www.digikey.com/en/maker/projects/introduction-to-rtos-solution-to-part-12-multicore-systems/369936f5671d4207a2c954c0637e7d50 Code for this video series (including demonstrations, challenges, and solutions) can be found here: https://github.com/ShawnHymel/introduction-to-rtos Programming a multicore system can be separated into two paradigms: asymmetric multiprocessing (AMP) and symmetric multiprocessing (SMP). AMP requires a primary core running an operating system to schedule tasks in other (secondary) cores. In SMP, the OS runs on all cores, and the scheduler is free to pull tasks from a shared list. ESP-IDF is the port of FreeRTOS for the ESP32, and it supports SMP. The ESP32 is a dual-core system (although, single-core variants exist). We look at how the ESP32 architecture is configured and how each core can access memory, resources, and interrupts. In ESP-IDF, we have the option of pinning tasks to a core (so that only that core may run a particular task) or setting a task to “no affinity” (so that the task can run in either core). Using “no affinity” is easier to implement and optimizes CPU utilization and load balancing without much effort. However, it becomes difficult to determine when certain tasks will run, which makes predicting deadlines tougher. As a result, many embedded developers prefer to pin tasks to cores, as it allows for a higher level of determinism. We show how to run tasks on either core in the ESP32 as well as set them to “no affinity.” Kernel objects (e.g. queues, mutexes, and semaphores) work across cores without any modification, as the ESP32’s cores share memory. Product Links: https://www.digikey.com/en/products/detail/adafruit-industries-llc/3405/7244967 Related Videos: Introduction to RTOS Part 1 - What is a Real-Time Operating System (RTOS)? - https://youtu.be/F321087yYy4​ Introduction to RTOS Part 2 - Getting Started with FreeRTOS - https://youtu.be/JIr7Xm_riRs​ Introduction to RTOS Part 3 - Task Scheduling - https://youtu.be/95yUbClyf3E​ Introduction to RTOS Part 4 - Memory Management - https://youtu.be/Qske3yZRW5I​ Introduction to RTOS Part 5 - Queue - https://youtu.be/pHJ3lxOoWeI​ Introduction to RTOS Part 6 - Mutex - https://youtu.be/I55auRpbiTs​ Introduction to RTOS Part 7 - https://youtu.be/5JcMtbA9QEE​ Introduction to RTOS Part 8 - https://youtu.be/b1f1Iex0Tso Introduction to RTOS Part 9 - https://youtu.be/qsflCf6ahXU Introduction to RTOS Part 10 - https://youtu.be/hRsWi4HIENc Introduction to RTOS Part 11 - https://youtu.be/C2xKhxROmhA Introduction to RTOS Part 12 - https://youtu.be/LPSHUcH5aQc Related Project Links: https://www.digikey.com/en/maker/projects/introduction-to-rtos-solution-to-part-11-priority-inversion/abf4b8f7cd4a4c70bece35678d178321 Related Articles: https://www.digikey.com/en/maker/projects/introduction-to-rtos-solution-to-part-12-multicore-systems/369936f5671d4207a2c954c0637e7d50 Learn more: Maker.io - https://www.digikey.com/en/maker Digi-Key’s Blog – TheCircuit https://www.digikey.com/en/blog Connect with Digi-Key on Facebook https://www.facebook.com/digikey.electronics/ And follow us on Twitter https://twitter.com/digikey