Neste artigo, faremos 2 Leds piscarem simultaneamente com delay, evidenciando o dual core, com o objetivo de fazer um registrador de energia contínuo, tendo 1 core para registrar e calcular a potência, e o segundo core gerenciando a publicação dos dados.
Entenda mais do funcionamento do Dual Core: https://randomnerdtutorials.com/esp32-dual-core-arduino-ide/
Vimos no artigo acima que o ESP32 vem com 2 microprocessadores Xtensa 32-bit LX6. Normalmente os exemplos na IDE do Arduino consideram 1 processador somente, sendo assim executa 1 atividade por vez, e nós queremos executar atividades em paralelo.
SOFTWARE:
Então rodando o código abaixo:
Na primeira aba temos:
Nas linhas 1 e 2 a criação das duas tasks (atividades), e nas linhas 5 e 6 a escolha das saídas que acionarão os Leds, terminando a declaração fora das funções.
Dentro da função Setup() nós vamos escolher o Core (processador) que rodará cada Task. Sendo possível o core 0 ou o core 1.
Não rodaremos nada na função loop(). Sabendo que, quando tem código no loop(), este roda no Core 1 normalmente.
Na segunda aba temos:
Onde Piscaremos o led do pino 17 do ESP.
E na terceira aba, piscaremos o Led do pino 16:
Em uma aplicação normal, chamaríamos as funções “Task1Code” e “Task2Code” dentro do “loop” e 1 Led ascenderia após o outro, mas como podemos evidenciar no vídeo abaixo, o Leds estão piscando simultaneamente, mostrando que as 2 atividades estão acontecendo ao mesmo tempo.
HARDWARE:
Para rodar o exemplo, serão necessários os seguintes materiais:
1 – ESP32 ou uma CPB32
2 – Resistores de 1KOhm
2 – Leds
1 – Placa de prototipagem (protoboard)
4 – Jumpers MM
IMPORTANTE AO FAZER MÁQUINA:
Um ponto importe que nós comentamos sempre aqui na Crescer é que “uma coisa é rodar exemplo, e outra é fazer máquina”.
Vamos dividir ainda neste blog, algo que constatamos ao implementar o medidor de energia, mas como está relacionado ao Dual Core, focaremos neste blog.
Já testando a lógica para medir e calcular a potência, uma premissa é rodar o mais rápido possível e sem interrupção, por isto 1 Core somente para tal atividade.
Sem saber qual Core escolher, coloquei aleatoriamente no Core 0 e no Core 1, deixei a lógica de piscar o led (futura lógica de envio de dados).
Com isto, o Core 0 estava resetando a cada 5 segundos e coloquei um delay de 1ms e parou de resetar. Pensei então que pode ser algumas Tasks que estão rodando no Core 0 em baixo nível, já que a ESP32 que usamos tem memória flash externa por exemplo, e este acesso pode ser gerenciado pelo Core 0 e não está sendo mostrado para nós que usamos a IDE do Arduino para programá-lo. (CONTINUE A LEITURA, POIS ESTA AÇÃO MELHOROU, MAS NÃO RESOLVEU DEFINITIVAMENTE O PROBLEMA)
Ao colocar a lógica rápida no Core 1, parou de resetar, então vou organizar o projeto em, Core 0 fazendo a conexão e publicação na nuvem. Deixando o Core 1 para medir e calcular a potência.
Quando começamos a inserir a lógica de publicação no google sheets e rodando a CPB32 por mais tempo, percebemos que após 20 min (e variando a cada falha), ocorria a seguinte falha:
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
E a partir daí começamos a entrar em uma série de fóruns internacionais para tentar resolver e vou começar a listar para vocês as ações que tomamos até chegar na última que nos deixou a aplicação rodando por dias ininterruptamente
Trabalhamos um bom tempo com as seguintes funções:
Delay( 10 ); // pausa de 10 milesegundos
VTaskDelay( 10 ); // outra maneira de pausar recomendada em muitos fóruns
Yield( ); // seria uma função para verificar se tem algo precisando ser executado
vTaskDelete(NULL); // esta função dentro do loop()
Pare se ter uma ideia, nós considerarmos colocar as funções acima dentro dos 3 loopings, Loop(), Task1code() e Task2code().
Com As combinações mais variadas possíveis e o melhor resultado foi de 110 minitos sem a falha.
Para criar uma aplicação, dependendo do caso, não seria um problema, pois o ESP32 retorna a funcionar. Mas não é uma boa prática ter em projetos, este tipo de ocorrência frequente, então continuamos a pesquisar.
O resultado acima foi obtido com:
Aba 1 do software:
Aba 2 do software:
Aba 3 do software:
Este contexto não me deixou satisfeito, então encontramos já no final da pesquisa uma forma de desabilitar o Watchdog no Core 0. Na mensagem de falha, pode-se verificar que, nestes momentos ocorre uma segurança de Watchdog no Core 0, então inserimos o seguinte código no loop:
E retirei o yield() e vTaskDelay dos outros 2 loops.
Tendo a aplicação rodando 2 dias sem dar falha, e na performance máxima que cada código disponibiliza, pois não tem qualquer tipo de delay agora.
Caso no futuro o Core 0 comece a travar e precise habilitar o Watchdog, poderemos criar uma variável que altere o valor no loop do Core 0, e se o Core 1 detectar que o Core 0 parou, poderemos habilitar o Watchdog ou mesmo resetar o ESP32.
Agora é aplicar nos projetos e evoluir...
E aí o que achou deste material? Tens algum projeto em mente onde 2 códigos rodando simultaneamente dariam mais performance para sua aplicação?
Avalie-nos no google para que possamos alcançar e auxiliar cada vez mais pessoas a fazerem seus projetos e produtos! Contamos com você!
Comments