Aula #3 – Depuração de Erros do ESP8266

Ferramenta de Decodificação de Stack Trace:

https://github.com/me-no-dev/EspExceptionDecoder

Código de simulação de erro:

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println("Let's provoke the s/w wdt firing...");
  //
  // provoke an OOM, will be recorded as the last occured one
  char* out_of_memory_failure = (char*)malloc(1000000);
  //
  // wait for s/w wdt in infinite loop below
  while(true);
  //
  Serial.println("This line will not ever print out");
}

void loop(){}

Referência:

https://arduino-esp8266.readthedocs.io/en/latest/faq/a02-my-esp-crashes.html

Aula #2 – Portas de Entrada/Saída do ESP8266

Nesta aula aprenderemos tudo sobre portas de entrada/saída do ESP8266, também conhecidas pela sigla GPIO.

Links da Aula:

Tópicos da Aula:

  • O que é a IDE?
  • Instalando IDE do Arduino
  • Configuração da IDE do Arduino
  • Estrutura de Arquivos da IDE do Arduino
  • E/S Digital do ESP8266
  • Restrições de Corrente e Tensão
  • Restrições de Uso dos Pinos
  • Modos de bootloader
  • PWM
  • Entrada Analógica
  • Porta Serial
  • I2C
  • SPI
  • Tabela de GPIO

Configurando a Memória Flash do ESP8266 no Arduino IDE

Hoje vamos aprender como configurar corretamente o tamanho da memória Flash do ESP8266.

Bati muita cabeça aqui tentando fazer uma atualização do firmware do ESP8266 por WiFi, conhecida por OTA (Over The Air), que eu ensino nesse outro post aqui.

Mas sofri muito antes de conseguir efetuar a Atualização OTA por uma configuração errada no tamanho da memória Flash do meu módulo ESP8266.

Uma regra básica para a Atualização OTA funcionar é que o código sendo atualizado não pode ser maior que a metade do tamanho da memória Flash. Isso acontece pois é uma auto-atualização, de forma que o arquivo BIN é gravado no espaço vazio da memória Flash para depois então substituir o código atual sendo executado. Por isso precisa existir um espaço igual ou maior que o código sendo atualizado.

Meu módulo ESP8266 ESP01 estava configurado errado como tendo memória Flash de 512KB, mas o arquivo do código compilado e resultante BIN estava com mais que 256KB, portanto a Atualização OTA não estava sendo possível.

Descobri então que existe um Exemplo pronto que verifica isso pra gente. Basta seguir os passos a seguir.

Passo 1 – Abrir o Exemplo chamado CheckFlashConfig.ino, conforme imagem abaixo.

(clique na imagem para ampliar)

Passo 2 – Verifique que o código faz uso de funções nativas do ESP8266 para o tamanho da memória Flash configurada no Arduino IDE e o tamanho real do chip.

uint32_t realSize = ESP.getFlashChipRealSize();
uint32_t ideSize = ESP.getFlashChipSize();
FlashMode_t ideMode = ESP.getFlashChipMode();

Depois, através de um “if” na programação compara o valor real do configurado e avisa se está certo ou errado!

if (ideSize != realSize) {
  Serial.println("Flash Chip configuration wrong!\n");
} else {
  Serial.println("Flash Chip configuration ok.\n");
}

Passo 3 – Se estiver certo, vai aparecer a mensagem da imagem abaixo no Monitor da Serial ao executar o código. Repare que os tamanhos da memória real e configurada no IDE são iguais.

Passo 4 – Mas se aparecer a mensagem de erro “Flash Chip configuration wrong”, então vamos precisar configurar o tamanho correto no menu “Ferramentas” conforme mostra a imagem abaixo.

(clique na imagem para ampliar)

Mais Informações

No próximo artigo vou ensinar o que é o parâmetro SPIFFS da configuração da memória Flash.

Atualização do firmware do ESP8266 por WiFi

Introdução

Também conhecido como OTA, a auto atualização do firmware via WiFi é uma técnica utilizada para subir um novo programa no ESP8266 sem precisar conectar ele novamente na USB do computador. Ou seja, atualizamos o sketch do módulo via rede WiFi.

De forma resumida, nós compilamos o novo código, pegamos o arquivo *.bin e fazemos upload em um formulário como o exemplo abaixo:

Quando clicamos no botão “Enviar” todo o processo de atualização é feito automaticamente pelo ESP8266 sem precisarmos nos preocupar em tirar ele de onde ele estiver instalado e conectá-lo no computador. Tudo é feito via WiFi, de forma transparente!

Requisitos Básicos

O requisito mais importante é que o novo código a ser atualizado no ESP8266 seja menor que a metade do tamanho total da memória Flash. Isso porque o arquivo carregado por upload precisa primeiro ser gravado em algum lugar e depois atualizado.

Caso deseje saber como descobrir o tamanho da memória Flash do seu ESP8266, leia esse outro artigo aqui.

Instruções para implementar a Auto atualização

Primeiro faça o download do código de exemplo na coluna da direita dessa página.

Repare que temos uma função que monta o HTML do formulário de upload chamada updateWifiIni():

// Função que monta o formulário de upload do arquivo de update
void updateWifiIni() 
{
  String html = "<html><head><title>Update Firmware</title>";
  html += "<style>body { background-color: #cccccc; font-family: Arial, ";
  html += " Helvetica, Sans-Serif; Color: #000088; }</style>";
  html += "</head><body>";
  html += "<h1>Update Firmware</h1>";
  html += "<form method=POST action='/update' enctype='multipart/form-data'>";
  html += "<p><input type='file' name='update'></p>";
  html += "<p><input name=button1 type=submit value=Enviar /></p></form>";
  html += "</body></html>";

  server.sendHeader("Connection", "close");
  server.sendHeader("Access-Control-Allow-Origin", "*");
  server.send(200, "text/html", html);
}

Esse formulário é simples e contém apenas um campo de upload de arquivo e um botão “Enviar”.

Na sequência temos o código que monta uma página de resposta que apenas apresenta um HTML que informa ao usuário se o processo ocorreu com sucesso ou falhou.

// Função que recebe o post do formulário que carrega o arquivo de upload
void updateWifiFim() 
{
  String html = "<html><head><title>Update Firmware</title>";
  html += "<style>body { background-color: #cccccc; font-family: Arial, ";
  html += " Helvetica, Sans-Serif; Color: #000088; }</style>";
  html += "</head><body>";
  html += "<h1>Update Firmware</h1>";
  
  if (Update.hasError())
    html += "<p>Erro ao carregar firmware!</p>";
  else
    html += "<p>Firmware carregado com sucesso!</p>";
    
  html += "<form method=GET>";
  html += "<p><input name=button2 type=submit value=Voltar /></p></form>";
  html += "</body></html>";

  server.sendHeader("Connection", "close");
  server.sendHeader("Access-Control-Allow-Origin", "*");
  server.send(200, "text/html", html);
  ESP.restart();
}

Esta função faz uso do método Update.hasError() para saber se o processo teve algum erro e exibe uma mensagem de acordo com o resultado.

A última instrução reinicia o ESP8266 através do comando ESP.restart().

Já a parte de código abaixo é a responsável por receber o arquivo do novo firmware, verificar se tem espaço para gravar o arquivo e lida com todo o processo de atualização.

// Função que lida com o upload e a atualização do arquivo recebido
void funcUpdate()
{
  HTTPUpload& upload = server.upload();
  // Se o arquivo iniciou o upload verifica se tem espaço e mostra o nome do 
  // arquivo na serial
  if(upload.status == UPLOAD_FILE_START)
  {
    Serial.setDebugOutput(true);
    Serial.printf("Update: %s\n", upload.filename.c_str());
    uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
    // Verifica se deu erro de espaço
    if(!Update.begin(maxSketchSpace))
    {
      Update.printError(Serial);
    }
  } 
  // Se o download estiver em andamento, grava os trecho do arquivo 
  else if(upload.status == UPLOAD_FILE_WRITE)
  {
    if(Update.write(upload.buf, upload.currentSize) != upload.currentSize)
    {
      Update.printError(Serial);
    }
  } 
  // Caso o upload terminou, atualiza e reinicia o ESP
  else if(upload.status == UPLOAD_FILE_END)
  {
    if(Update.end(true))
    { //true to set the size to the current progress
      Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
    }
    else 
    {
      Update.printError(Serial);
    }
    Serial.setDebugOutput(false);
  }
  yield();
}

Veja que esse código é separado por 3 partes de um if, sendo o primeiro que verifica que o processo de upload começou, validando o status do processo tem o valor de UPLOAD_FILE_START. Nessa parte o ESP verifica se existe espaço para acomodar o novo sketch, e também imprime na Serial o nome do arquivo sendo feito upload.

O segundo if verifica se o o status é UPLOAD_FILE_WRITE, ou seja, se os trechos do arquivo estão em processo de gravação.

Por fim, o último if verifica se o processo de upload terminou comparando o status do processo com UPLOAD_FILE_END.

Nessa etapa chamamos a função Update.end(true) para fazer o processo de atualização do arquivo que acabou de ser enviado.

Se tudo der certo o ESP8266 reinicia, senão apresenta um erro na Serial.

O mecanismo que configura a todo esse processo é feito no setup() do código, quando definimos o handle(), assim:

server.on("/update", HTTP_POST, updateWifiFim, funcUpdate);

Sendo que o caminho onde será feito o upload é o “/update” e o método é HTTP_POST, a função que vai lidar com o request é a updateWifiFim e a função que vai lidar com o upload é a funcUpdate.

Pronto, só isso é suficiente para atualizarmos o nosso programa via WiFi!

Como usar

Antes de mais nada configure o SSID e a senha da sua rede nas linhas abaixo do código:

const char* ssid = "XXXX";
const char* password = "YYYY";

Primeiro conecte o ESP8266 no computador e suba o programa pela primeira vez. Dessa vez tem que ser pelo computador. As vezes seguintes que serão pelo WiFi.

Se tiver dúvidas siga os vídeos indicados ao lado, na barra a direita.

Depois que subiu o programa, abra o monitor da serial e descubra o IP do ESP8266.

(clique na imagem para ampliar)

Acesse o IP adicionando o caminho “/update” no final, assim:

http://192.168.15.17/update

Então a página com o formulário de upload vai aparecer:

Nesse momento vamos voltar para a IDE do Arduino e alterar o programa para subir uma versão diferente via WiFi.

Mude a linha abaixo de:

server.send(200, "text/plain", "hello from esp8266!");

para:

server.send(200, "text/html", "<a href=update>OTA update</a>");

Agora vamos configurar uma opção para ligar as mensagens de saída durante a compilação. Acesse o menu Arquivo > Preferências e marque a opção indicada na imagem abaixo:

(clique na imagem para ampliar)

Pode compilar o programa (clicando no menu Sketch > Verificar/Compilar) e vamos verificar nas mensagens de saída para achar o diretório onde o arquivo *.bin é gravado. Veja a imagem abaixo:

(clique na imagem para ampliar)

Agora que você descobriu onde o arquivo foi gravado, volte no formulário de upload, escolha o arquivo *.bin e clique em “Enviar”.

Pronto! Todo o resto do processo o próprio ESP8266 faz sozinho.

Acesse a página inicial para ver a mudança do sketch:

(clique na imagem para ampliar)

Mais Informações

Veja o documento original (em inglês) que inspirou este meu post, clicando aqui.