Multiprocessamento ESP32 como usar corretamente

O multiprocessamento do ESP32 é um ponto de vantagem em relação a outros microcontroladores, porém nem todo ESP32 tem mais de um núcleo. Neste post você aprenderá qual modelo escolher e como usar o segundo core sem ter dor de cabeça.

Multiprocessamento ESP32 aonde aplicar?

Certamente você em algum momento teve a necessidade de usar mais de um microcontrolador em paralelo ao mesmo circuito do seu projeto, porém o ESP32 já tem um “segundo” ESP dentro dele, no qual você poderá usar como se fosse de fato, outro ESP. No entanto, nem todo ESP32 tem portabilidade para isso, então é necessário escolher um modelo.

Qual modelo de ESP32 escolher?

A principio basta só fazer o código e fazer o upload para o ESP32, mas a Espressif disponibiliza inúmeros modelos de ESP32, para escolher, basta prestar atenção na ultima letra, se tiver um ‘D‘ ou ‘U‘ é dual core, caso tenha um ‘S‘ é single core.

Identificação da quantidade de núcleos do ESP32 através do sufixo
Fonte: Datasheet do chip ESP32

Exemplo de identificação em placas ESP32 Wrover

Como a identificação acima tratasse do chip, possa ser que haja certa dúvida com as placas wrover, mas é basicamente a mesma coisa, a única atenção necessária é para as placas que não possuem sufixo de identificação, porém pelo esquemático do datasheet pode ser subtendido que na ausência do sufixo, o chip será dual core.

Diagrma esquemático da placa Wrover do ESP32 que pode indicar que as placas que não possuem sufixo, podem ser dual core, capaz de realizar multiprocessamento
Fonte: Datasheet da placa ESP32 Wrover

Por causa de um teste de bancada, foi confirmado que as placas Wrover que não possuem sufixo, são dual core também.

Troca de core do ESP32 na IDE Arduino

A própria IDE do Arduino já disponibiliza uma função que permite definir qual núcleo vai rodar o firmware, por padrão é o núcleo 1 mas pode trocar para o núcleo 0 e visse versa.

Definição qual núcleo de processamento o código do arduino IDE vai rodar no ESP32

Exemplo de uso do Dual Core do ESP32

O exemplo para o uso de dual core com ESP32 é bem simples que da até para ser feito com a biblioteca Waiting Time mas o que vai diferenciar é que um LED piscará através do core0 e outro pelo core1.

Diagrama esquemático

Como visto anteriormente, cada LED vai piscar por meio de um core diferente, mas ambos tem acesso ao mesmos periféricos, ou seja, o GPIO12 por exemplo, pode ser acessado via core0 e core1 ao mesmo tempo.

Diagrama esquemático de exemplo para multiprocessamento com esp32

Código exemplo para multiprocessamento ESP32

O código é também é simples mas é necessário atenção para que não ocorra problemas com o uso do segundo núcleo. Primeiramente é necessário validar que teu ESP32 de fato tem dois núcleos, feito isso verifique qual núcleo seu código principal está rodando, por padrão é o core1.

#define led_core1_pin 13
#define led_core0_pin 2

TaskHandle_t Thread;                                                 // Define Thread como objeto da classe TaskHandle_t 

void setup() {

  pinMode(led_core1_pin, OUTPUT);
  pinMode(led_core0_pin, OUTPUT);

  xTaskCreatePinnedToCore(core0,                                     // Método em que o core 0 vai rodar
                          "segundo núcleo",                          // Identificador do processo (aviso para o usuário)
                          10000,                                     // Tamanho máximo de memória dedicada ao núcleo
                          NULL,                                      // Parametro que não achei a função correta dele, mas defina como null
                          1,                                         // Prioridade
                          &Thread,                                   // Linka objeto Thread ao método xTaskCreatePinnedToCore
                          0);                                        // Core que será usado  
  disableCore0WDT();                                                 // Desabilita o WDT do core0
}

void loop() {
  digitalWrite(led_core1_pin, 1);
  delay(1000);
  digitalWrite(led_core1_pin, 0);
  delay(1000);
}

void core0(void * pvParameters){
  while (true){
    digitalWrite(led_core0_pin, 1);
    delay(500);
    digitalWrite(led_core0_pin, 0);
    delay(500);
  }
}

Observações sobre o uso do segundo núcleo

A principio, o que mais da problema no uso de dois núcleo no ESP32 é o Watch Dog Timer (WDT), então caso não seja desabilitado, haverá um seguinte erro;

TasE (10179) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (10179) task_wdt: - IDLE0 (CPU 0)
E (10179) task_wdt: Tasks currently running:
E (10179) task_wdt: CPU 0: Task1
E (10179) task_wdt: CPU 1: loopTask

A melhor maneira que encontrei através do blog da Crescer Engenharia, foi o uso do seguinte comando logo após da ativação do outro core.

disableCore0WDT(); // se estiver usando o core0
disableCore1WDT(); // se estiver usando o core1

Outro ponto muito importante é o método em que o outro núcleo vai rodar, pois ele deve conter dentro do parênteses um ponteiro ‘void * pvParameters‘, caso contrário a chamada de método não funcionará. Além disso, coloque um loop infinito dentro do método, para que a tarefa fique se repetindo.

void exemple(void * pvParameters){
  while(true){

  }
}

Funcionamento multiprocessamento no ESP32

Perceba que no vídeo abaixo os LEDs estão piscando em tempos diferentes, pois cada um estar tendo processamento independente.

Caso você tenha apenas um núcleo de processamento em seu ESP32 e precisa realizar um processamento sem delay, sugiro lê esse post Waiting Time.