- Ventajas del procesador multinúcleo
- ESP32 y FreeRTOS
- Encontrar el ID del núcleo de ESP32
- Programación ESP32 de doble núcleo
Los módulos ESP son populares por sus funcionalidades Wi-Fi como ESP8266, ESP-12E, etc. Todos estos son potentes módulos de microcontrolador con funcionalidades Wi-Fi. Hay un módulo ESP más que es más potente y versátil que los módulos ESP anteriores: su nombre es ESP32. Tiene conectividad Bluetooth y Wi-Fi y ya explicamos las capacidades BLE de ESP32 y usamos ESP32 en muchos proyectos de IoT. Pero muy pocas personas saben que ESP32 es un microcontrolador de doble núcleo.
ESP32 tiene dos microprocesadores Tensilica Xtensa LX6 de 32 bits, lo que lo convierte en un potente microcontrolador de doble núcleo (core0 y core1). Está disponible en dos variantes de un solo núcleo y de doble núcleo. Pero la variante de doble núcleo es más popular porque no hay una diferencia de precio significativa.
ESP32 se puede programar usando Arduino IDE, Espressif IDF, Lua RTOS, etc. Mientras se programa con Arduino IDE, el código solo se ejecuta en Core1 porque Core0 ya está programado para comunicación RF. Pero aquí está este tutorial, le mostraremos cómo usar ambos núcleos de ESP32 para realizar dos operaciones simultáneamente. Aquí, la primera tarea será hacer parpadear el LED integrado y la segunda tarea será buscar los datos de temperatura del sensor DHT11.
Primero veamos las ventajas de un procesador de múltiples núcleos sobre un solo núcleo.
Ventajas del procesador multinúcleo
- Los procesadores de múltiples núcleos son útiles cuando hay más de 2 procesos para trabajar simultáneamente.
- A medida que el trabajo se distribuye entre diferentes núcleos, su velocidad aumenta y se pueden terminar múltiples procesos al mismo tiempo.
- El consumo de energía se puede reducir porque cuando cualquier núcleo está en modo inactivo, se puede usar para apagar los periféricos que no están en uso en ese momento.
- Los procesadores de doble núcleo tienen que cambiar entre diferentes subprocesos con menos frecuencia que los procesadores de un solo núcleo porque pueden manejar dos a la vez en lugar de uno a la vez.
ESP32 y FreeRTOS
La placa ESP32 ya tiene instalado el firmware FreeRTOS. FreeRTOS es un sistema operativo en tiempo real de código abierto que es muy útil en la multitarea. RTOS ayuda a administrar los recursos y maximizar el rendimiento del sistema. FreeRTOS tiene muchas funciones de API para diferentes propósitos y usando estas API, podemos crear tareas y hacer que se ejecuten en diferentes núcleos.
Puede encontrar la documentación completa de las API de FreeRTOS aquí. Intentaremos usar algunas API en nuestro código para crear una aplicación multitarea que se ejecutará en ambos núcleos.
Encontrar el ID del núcleo de ESP32
Aquí usaremos Arduino IDE para cargar el código en ESP32. Para conocer el ID de núcleo en el que se ejecuta el código, hay una función de API
xPortGetCoreID ()
Esta función se puede llamar desde la función void setup () y void loop () para conocer el ID del núcleo en el que se ejecutan estas funciones.
Puede probar esta API cargando el siguiente boceto:
configuración vacía () { Serial.begin (115200); Serial.print ("función setup () ejecutándose en el núcleo:"); Serial.println (xPortGetCoreID ()); } void loop () { Serial.print ("función loop () ejecutándose en el núcleo:"); Serial.println (xPortGetCoreID ()); }
Después de cargar el boceto anterior, abra el monitor serial y encontrará que ambas funciones se están ejecutando en core1 como se muestra a continuación.
De las observaciones anteriores, se puede concluir que el boceto predeterminado de Arduino siempre se ejecuta en core1.
Programación ESP32 de doble núcleo
Arduino IDE es compatible con FreeRTOS para ESP32 y las API de FreeRTOS nos permiten crear tareas que se pueden ejecutar de forma independiente en ambos núcleos. La tarea es la pieza de código que realiza alguna operación en la placa como led parpadeante, envío de temperatura, etc.
La siguiente función se utiliza para crear tareas que se pueden ejecutar en ambos núcleos. En esta función, tenemos que dar algunos argumentos como prioridad, ID de núcleo, etc.
Ahora, siga los pasos a continuación para crear tareas y funciones de tareas.
1. Primero, cree tareas en la función de configuración anulada . Aquí crearemos dos tareas, una para que el LED parpadee después de cada 0,5 segundos y otra tarea es obtener la lectura de temperatura después de cada 2 segundos.
La función xTaskCreatePinnedToCore () toma 7 argumentos:
- Nombre de la función para implementar la tarea (tarea1)
- Cualquier nombre que se le dé a la tarea ("tarea1", etc.)
- Tamaño de pila asignado a la tarea en palabras (1 palabra = 2bytes)
- Parámetro de entrada de tarea (puede ser NULO)
- Prioridad de la tarea (0 es la prioridad más baja)
- Identificador de tarea (puede ser NULO)
- Identificación del núcleo donde se ejecutará la tarea (0 o 1)
Ahora, cree Task1 para hacer parpadear el led dando todos los argumentos en la función xTaskCreatePinnedToCore ().
xTaskCreatePinnedToCore (Task1code, "Task1", 10000, NULL, 1, NULL, 0);
Del mismo modo, crear Task2 para Task2 y hacer Identificación del núcleo 1 en el 7 º argumento.
xTaskCreatePinnedToCore (Task2code, "Task2", 10000, NULL, 1, NULL, 1);
Puede cambiar la prioridad y el tamaño de la pila según la complejidad de la tarea.
2. Ahora, implementaremos la función Task1code y Task2code . Estas funciones contienen el código para la tarea requerida. En nuestro caso, la primera tarea hará parpadear el led y otra tarea buscará la temperatura. Así que cree dos funciones separadas para cada tarea fuera de la función de configuración de vacío.
La función Task1code para parpadear el LED integrado después de 0,5 segundos se implementa como se muestra a continuación.
Void Task1code (parámetro void *) { Serial.print ("Task1 ejecutándose en el núcleo"); Serial.println (xPortGetCoreID ()); for (;;) {// bucle infinito digitalWrite (led, HIGH); retraso (500); digitalWrite (LED, LOW); retardo (500); } }
De manera similar, implemente la función Task2code para obtener la temperatura.
void Task2code (void * pvParameters) { Serial.print ("Task2 ejecutándose en el núcleo"); Serial.println (xPortGetCoreID ()); para (;;) { float t = dht.readTemperature (); Serial.print ("Temperatura:"); Serial.print (t); retraso (2000); } }
3. Aquí la función de bucle vacío permanecerá vacía. Como ya sabemos, la función de bucle y configuración se ejecuta en core1, por lo que también puede implementar la tarea core1 en la función de bucle vacío .
Ahora la parte de codificación ha terminado, así que simplemente cargue el código usando Arduino IDE eligiendo la placa ESP32 en el menú Herramientas. Asegúrese de haber conectado el sensor DHT11 al pin D13 de ESP32.
Ahora los resultados se pueden monitorear en Serial Monitor o Arduino IDE como se muestra a continuación:
Se pueden construir aplicaciones complejas como el sistema en tiempo real ejecutando múltiples tareas simultáneamente utilizando núcleos duales de ESP32.
A continuación se proporciona el código completo junto con un video de demostración.