Introducción
Cuando hablamos de doble núcleo, significa que hay dos núcleos idénticos e independientes en el mismo circuito integrado o chip, que trabajan a la misma velocidad aunque cada uno puede ajustarse según la carga y el controlador que lo gobierna.
El controlador lógico programable ESP32 incluye 2 microprocesadores Xtensa LX6 de 32 bits, que permiten opciones multiproceso y un mayor rendimiento. Tienen capacidad para cada procesador interno, pero también la memoria principal del sistema para cargar sus propios procesos. En este blog, verás cómo trabajar con la opción de doble núcleo de los controladores PLC ESP32 con los requisitos y factores a tener en cuenta.
Enlaces relacionados
Cómo trabajar con ESP32 de doble núcleo
Para trabajar con el ESP32 de doble núcleo, actualiza los paquetes Industrial Shields ESP32 en Arduino IDE a la última versión (v1.1.0 o más reciente) antes de trabajar con los PLCs basados en ESP32. Una vez que la configuración se hace, serás capaz de crear una segunda función de bucle llamado loop1.
void setup() {
// TODO
}
void loop() {
// Default core tasks
}
void loop1() {
// Secondary core tasks
}
Todas las tareas programadas en la función de loop por defecto se ejecutarán utilizando el primer núcleo, mientras que las del loop1 trabajarán en el segundo núcleo.
Como puedes ver, trabajar con el doble núcleo utilizando nuestras tarjetas Industrial Shields es muy fácil. Sin embargo, hay que tener en cuenta algunos factores que pueden causar algunos problemas si no están bien implementados como recursos compartidos. Para evitar problemas, hemos implementado un sistema de semáforos, que deben ser utilizados cada vez que un núcleo quiera acceder a un recurso compartido con el otro núcleo, por ejemplo, una variable global, o un tipo de periférico (Serial, SPI , I2C, etc.)
Sistema de semáforos
Para controlar el recurso compartido, Industrial Shields ha implementado un sistema de semáforo en el que el primer núcleo que acceda al periférico lo bloqueará hasta que haya terminado su trabajo. La librería implementa 3 funciones:
take(uint32_t timeout = 0)
give()
isTaken()
La función take() bloqueará el semáforo mientras la función give() lo desbloquea. Si se pasa algún parámetro a la función take(), ésta bloqueará el semáforo hasta que sea liberado por give(). Sin embargo, si se especifica un tiempo determinado, bloqueará el recurso hasta que el tiempo haya transcurrido. Para saber si el semáforo está disponible, la función isTaken() devolverá True o False dependiendo de su estado.
Ejemplo
En el siguiente ejemplo, puedes ver cómo se utilizan estos semáforos con una variable compartida. El programa estará incrementando una variable utilizando ambos núcleos en tiempos diferentes. El núcleo por defecto estará incrementando la variable cada 1,5s mientras que el segundo lo hará cada segundo. Con la función xPortGetCoreID() podrás saber qué núcleo está incrementando la variable cada vez.
#include <Semaphore.h>
SemaphoreBinary semaphore;
uint32_t variable = 0;
////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200UL);
Serial.print("setup running on core ");
Serial.println(xPortGetCoreID());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
updateVariable(200);
printVariable();
delay(1500);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void loop1() {
updateVariable(100);
printVariable();
delay(1000);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void updateVariable(uint32_t timeout) {
semaphore.take();
delay(timeout);
++variable;
semaphore.give();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void printVariable() {
semaphore.take();
Serial.print("core ");
Serial.print(xPortGetCoreID());
Serial.print(" variable value: ");
Serial.println(variable);
semaphore.give();
}
Cómo utilizar el PLC industrial ESP32 de doble núcleo