Implement Phase 2 of i18n spec: - Extract UI interface strings to messages/pt.json across 15 namespaces - Extract canonical data files to data/pt/ (series, frameworks, conexoes) - Create lib/data/pt/ modules (glossario, diagnostico, componentes, topicos) - Implement lib/data/index.js async data loaders by locale - Add automated check:i18n script to validate key parity and enforce no-book rules Co-Authored-By: Antigravity <noreply@google.com>
744 lines
39 KiB
JavaScript
744 lines
39 KiB
JavaScript
/**
|
|
* Base de dados estruturada para o Guia de Diagnóstico, Erros Comuns e Resolução de Problemas no ESP32.
|
|
* Abrange 6 categorias técnicas com causas raízes, comparativos de boas práticas vs gambiarras e exemplos de código
|
|
* em Arduino C++, ESP-IDF (C) e MicroPython.
|
|
*/
|
|
|
|
export const categoriasDiagnostico = [
|
|
{
|
|
id: "alimentacao",
|
|
nome: "Alimentação & Hardware",
|
|
icone: "Zap",
|
|
cor: "amber",
|
|
descricao: "Quedas de tensão por picos de RF Wi-Fi/BLE, strapping pins conflitantes, ruído eletromagnético e problemas de LDO.",
|
|
},
|
|
{
|
|
id: "cpu-panics",
|
|
nome: "Pânicos de CPU & Guru Meditation",
|
|
icone: "Cpu",
|
|
cor: "red",
|
|
descricao: "Ponteiros nulos, violações de memória (Load/StoreProhibited), instruções ilegais e cache panics em ISR.",
|
|
},
|
|
{
|
|
id: "freertos",
|
|
nome: "FreeRTOS & Multitarefa",
|
|
icone: "Layers",
|
|
cor: "purple",
|
|
descricao: "Task Watchdog (TWDT), Interrupt Watchdog (IWDT), estouro de pilha (Stack Overflow) e bloqueios de escalonador.",
|
|
},
|
|
{
|
|
id: "memoria",
|
|
nome: "Memória, Heap & PSRAM",
|
|
icone: "Activity",
|
|
cor: "blue",
|
|
descricao: "Fragmentação de Heap, vazamento de memória (Memory Leaks), alocações para DMA e limitações de PSRAM.",
|
|
},
|
|
{
|
|
id: "boot-flash",
|
|
nome: "Bootloader & Gravação",
|
|
icone: "Terminal",
|
|
cor: "emerald",
|
|
descricao: "Falha de comunicação serial (DTR/RTS), erros de leitura SPI Flash, incompatibilidade de clock e partições.",
|
|
},
|
|
{
|
|
id: "conectividade",
|
|
nome: "Conectividade & Protocolos",
|
|
icone: "Wifi",
|
|
cor: "cyan",
|
|
descricao: "Wi-Fi Beacon Timeout, falhas de handshake TLS/HTTPS por falta de relógio SNTP e instabilidade de sinal.",
|
|
},
|
|
];
|
|
|
|
export const sintomasRapidos = [
|
|
{ id: "bootloop", rotulo: "🔄 Reiniciando em loop (Bootloop)", categoria: "todos" },
|
|
{ id: "wifi-crash", rotulo: "📶 Trava ao ligar Wi-Fi/BLE", categoria: "alimentacao" },
|
|
{ id: "upload-fail", rotulo: "🔌 Falha ao gravar código (Upload)", categoria: "boot-flash" },
|
|
{ id: "random-freeze", rotulo: "⏱️ Trava após minutos/horas", categoria: "memoria" },
|
|
{ id: "null-pointer", rotulo: "💥 Guru Meditation (Crash)", categoria: "cpu-panics" },
|
|
{ id: "wdt-reset", rotulo: "🐕 Watchdog Triggered", categoria: "freertos" },
|
|
{ id: "tls-fail", rotulo: "🔒 Falha em HTTPS / SSL", categoria: "conectividade" },
|
|
];
|
|
|
|
export const errosCatalogo = [
|
|
{
|
|
id: "brownout-reset",
|
|
titulo: "Brownout Detector Reset (Queda de Tensão)",
|
|
categoria: "alimentacao",
|
|
sintomas: ["bootloop", "wifi-crash"],
|
|
gravidade: "Alta",
|
|
logSerial: "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)",
|
|
resumo: "A tensão de alimentação do ESP32 caiu abaixo do limiar operacional seguro (aproximadamente 2.8V ~ 2.43V).",
|
|
causaRaiz:
|
|
"Quando o rádio Wi-Fi ou BLE é ligado, o estágio de potência (PA) consome pulsos de corrente muito rápidos que podem superar 500mA em menos de 1 milissegundo. Se a fonte de alimentação, os cabos USB longos/finos, os trilhos de protoboard ou o regulador LDO não fornecerem corrente instantânea com baixa impedância, a tensão no pino 3V3 do chip afunda momentaneamente, disparando o circuito comparador interno de Brownout para evitar corrupção de memória Flash e estados indeterminados.",
|
|
gambiarra: {
|
|
titulo: "Desativar o Brownout por software",
|
|
descricao: "Chamar WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0) para silenciar o erro no código.",
|
|
consequencia: "Extremamente perigoso: o ESP32 continuará executando instruções sob subtensão, corrompendo a memória Flash SPI, travando registradores e causando comportamento imprevisível em campo sem aviso.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Dimensionamento correto de hardware e desacoplamento",
|
|
passos: [
|
|
"Adicione um capacitor de tântalo ou cerâmico de 10µF a 100µF de baixo ESR (Low-ESR) em paralelo com um cerâmico de 100nF o mais próximo possível dos pinos 3V3 e GND do ESP32.",
|
|
"Utilize reguladores LDO projetados para picos de no mínimo 600mA a 1A com excelente resposta a transitórios (ex: AP2112K, ME6211, TPS73733 ou XC6206 robusto). Evite clones de baixa qualidade do antigo AMS1117.",
|
|
"Evite alimentar o ESP32 via trilhos compridos de protoboard com cabos jumper finos quando o Wi-Fi estiver transmitindo em potência máxima.",
|
|
],
|
|
},
|
|
codigoArduino: `// NÃO desative o Brownout! Se precisar reduzir o pico em testes:
|
|
#include <WiFi.h>
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
|
|
// Opcional: Reduzir ligeiramente a potência máxima de transmissão do Wi-Fi
|
|
// de 20dBm para 17dBm diminui o pico de corrente em ~20%
|
|
WiFi.setTxPower(WIFI_POWER_17dBm);
|
|
WiFi.begin("SSID", "SENHA");
|
|
}`,
|
|
codigoEspIdf: `// Configuração no ESP-IDF:
|
|
#include "esp_wifi.h"
|
|
#include "esp_log.h"
|
|
|
|
void app_main(void) {
|
|
// No menuconfig: Component config -> ESP32-specific -> Hardware Brownout Reset (Mantenha sempre ATIVO)
|
|
// Para mitigar picos em ambientes com limite de potência:
|
|
esp_wifi_set_max_tx_power(68); // 68 = 17dBm (unidades de 0.25dBm)
|
|
}`,
|
|
codigoMicroPython: `# Conexão Wi-Fi segura no MicroPython com estabilização:
|
|
import network
|
|
import time
|
|
|
|
wlan = network.WLAN(network.STA_IF)
|
|
wlan.active(True)
|
|
|
|
# Aguarda estabilização da alimentação antes de iniciar transmissão
|
|
time.sleep_ms(200)
|
|
wlan.connect("SSID", "SENHA")
|
|
|
|
tentativas = 0
|
|
while not wlan.isconnected() and tentativas < 30:
|
|
time.sleep_ms(200)
|
|
tentativas += 1
|
|
|
|
if wlan.isconnected():
|
|
print("Wi-Fi Conectado! IP:", wlan.ifconfig()[0])
|
|
else:
|
|
print("[ERRO] Falha ao conectar Wi-Fi")`,
|
|
dicaPro: "Se estiver projetando sua própria PCB, coloque um plano de terra sólido sob o módulo e trilhas de alimentação com largura mínima de 0.5mm a 1mm para suportar os surtos de corrente sem queda resistiva (IR drop).",
|
|
},
|
|
{
|
|
id: "strapping-pins",
|
|
titulo: "Conflito de Strapping Pins no Boot",
|
|
categoria: "alimentacao",
|
|
sintomas: ["bootloop", "upload-fail"],
|
|
gravidade: "Crítica",
|
|
logSerial: "rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)\nflash read err, 1000\nwaiting for download",
|
|
resumo: "O ESP32 não inicializa o firmware da Flash ou entra acidentalmente em modo de download porque um pino de strapping foi forçado a um nível lógico incorreto no reset.",
|
|
causaRaiz:
|
|
"No momento exato em que o pino EN/CHIP_PU sobe (Power-On Reset), a CPU amostra o estado de pinos específicos (Strapping Pins) para configurar tensão de Flash (1.8V vs 3.3V), modo de boot (Download UART vs SPI Flash) e saída de clock. Se você conectar sensores, relés ou LEDs com pull-up/pull-down nesses pinos, o microcontrolador lerá um nível lógico inválido e travará o boot.",
|
|
gambiarra: {
|
|
titulo: "Colocar delays no código ou desconectar na mão toda vez que liga",
|
|
descricao: "Tentar tratar o problema via software no setup() ou depender de desconectar fios manualmente antes de cada reinicialização.",
|
|
consequencia: "Inútil: os Strapping Pins são lidos por hardware antes mesmo da CPU carregar qualquer linha do seu código ou do bootloader.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Mapeamento seguro de GPIOs e isolamento no reset",
|
|
passos: [
|
|
"ESP32 Clássico: Evite usar GPIO 0 (Boot), GPIO 2 (deve estar LOW ou flutuando no flash), GPIO 12 (define tensão de Flash: se puxado para HIGH no reset, queima/trava a flash de 3.3V) e GPIO 15 (silencia mensagens de log de boot se LOW).",
|
|
"ESP32-C3: Evite puxar GPIO 8 para LOW ou GPIO 9 para LOW no reset.",
|
|
"ESP32-S3: Atenção com GPIO 0, GPIO 45 (tensão VDD_SPI) e GPIO 46.",
|
|
"Se for estritamente necessário usar esses pinos para periféricos, utilize transistores ou buffers para isolá-los até que o sinal EN esteja totalmente estabilizado.",
|
|
],
|
|
},
|
|
codigoArduino: `// RECOMENDAÇÃO DE PINAGEM SEGURA (ESP32 Clássico):
|
|
// Pinos ideais para I2C / SPI / Sensores gerais:
|
|
// SDA: GPIO 21 | SCL: GPIO 22
|
|
// SPI: MOSI 23 | MISO 19 | SCK 18 | CS 5
|
|
|
|
// ATENÇÃO: GPIOs 34, 35, 36 (VP), 39 (VN) são APENAS ENTRADA (sem pull-up interno).
|
|
// Nunca tente usá-los como pinMode(..., OUTPUT); nem para I2C/SPI.`,
|
|
codigoEspIdf: `// No ESP-IDF, proteja a configuração de tensão de Flash via eFuse (CUIDADO: IRREVERSÍVEL):
|
|
// Se você usa ESP32 clássico e precisa liberar GPIO12, pode queimar o eFuse de 3.3V:
|
|
// espefuse.py --port /dev/ttyUSB0 set_flash_voltage 3.3V
|
|
// Isso desativa a amostragem de hardware no GPIO12 para sempre.`,
|
|
codigoMicroPython: `# Configuração correta de pinos no MicroPython:
|
|
from machine import Pin
|
|
|
|
# ✅ Pinos seguros para saídas e botões com pull-up interno:
|
|
led = Pin(2, Pin.OUT) # GPIO 2
|
|
botao = Pin(4, Pin.IN, Pin.PULL_UP) # GPIO 4 (seguro)
|
|
|
|
# ⚠️ Pinos 34, 35, 36, 39 são APENAS ENTRADA e não têm pull-up interno:
|
|
sensor_analogico = Pin(36, Pin.IN) # Correto (requer resistor externo se for botão)`,
|
|
dicaPro: "Lembre-se sempre: pinos 'Input-Only' (GPI 34 a 39 no ESP32 clássico) não possuem circuitos de pull-up/pull-down de silício nem transistores de saída. Sensores analógicos ou botões neles exigem resistores de pull-up externos.",
|
|
},
|
|
{
|
|
id: "guru-load-prohibited",
|
|
titulo: "Guru Meditation: LoadProhibited / StoreProhibited",
|
|
categoria: "cpu-panics",
|
|
sintomas: ["bootloop", "null-pointer"],
|
|
gravidade: "Crítica",
|
|
logSerial: "Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.\nCore 0 register dump:\nPC : 0x400d14bc PS : 0x00060830 A0 : 0x800d1512 A1 : 0x3ffb1f20 \nEXCVADDR: 0x00000000",
|
|
resumo: "A CPU tentou ler (Load) ou escrever (Store) em um endereço de memória inacessível ou inválido, tipicamente o endereço nulo 0x00000000.",
|
|
causaRaiz:
|
|
"Essa é a clássica desreferência de ponteiro nulo (Null Pointer Dereference) ou uso de ponteiro solto (Dangling Pointer). O registrador EXCVADDR indica o endereço que causou a falha: se EXCVADDR for 0x00000000 ou muito próximo de zero (ex: 0x00000008, que é um offset de struct), significa que você tentou acessar membros de um objeto/ponteiro que não foi inicializado ou cujo malloc/criação falhou.",
|
|
gambiarra: {
|
|
titulo: "Adicionar delays aleatórios ou reiniciar no loop sem tratar",
|
|
descricao: "Achar que é problema de temporização e encher o código de delay() ou mascarar o reinício automático sem investigar a causa.",
|
|
consequencia: "O sistema continuará quebrando aleatoriamente em produção quando a condição de ponteiro nulo se repetir.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Validação defensiva e Decodificação de Backtrace",
|
|
passos: [
|
|
"Verifique sempre se retornos de funções de alocação ou busca (malloc, WiFi.client(), JSON parsing, xQueueReceive) não retornaram NULL antes de acessar seus campos.",
|
|
"Instale o 'Espressif Exception Decoder' na sua IDE (Arduino IDE / PlatformIO) ou use o comando 'xtensa-esp32-elf-addr2line -pfia -e firmware.elf 0x400d14bc' para descobrir exatamente a linha do seu código .c/.cpp onde o crash aconteceu.",
|
|
"No ESP-IDF, execute 'idf.py monitor' que decodifica o backtrace de pilha automaticamente em tempo real.",
|
|
],
|
|
},
|
|
codigoArduino: `// PROGRAMAÇÃO DEFENSIVA:
|
|
struct SensorData {
|
|
float temperatura;
|
|
float umidade;
|
|
};
|
|
|
|
void processarSensor(SensorData* sensor) {
|
|
// Verificação obrigatória contra LoadProhibited:
|
|
if (sensor == nullptr) {
|
|
Serial.println("[ERRO] Ponteiro de sensor nulo!");
|
|
return;
|
|
}
|
|
|
|
Serial.printf("Temp: %.1f C\\n", sensor->temperatura);
|
|
}`,
|
|
codigoEspIdf: `// No ESP-IDF, use ESP_ERROR_CHECK ou assertivas explícitas:
|
|
#include "esp_log.h"
|
|
#include "esp_check.h"
|
|
|
|
static const char* TAG = "SENSOR";
|
|
|
|
esp_err_t ler_dado(char* buffer, size_t max_len) {
|
|
ESP_RETURN_ON_FALSE(buffer != NULL, ESP_ERR_INVALID_ARG, TAG, "Buffer nulo fornecido!");
|
|
// Operação segura...
|
|
return ESP_OK;
|
|
}`,
|
|
codigoMicroPython: `# Prevenção contra NoneType e exceções de objeto no MicroPython:
|
|
import json
|
|
|
|
def processar_sensor(dados_raw):
|
|
# Proteção defensiva contra payload nulo:
|
|
if dados_raw is None:
|
|
print("[ERRO] Dados nulos recebidos!")
|
|
return None
|
|
|
|
try:
|
|
obj = json.loads(dados_raw)
|
|
# Uso seguro de .get() com valor padrão para evitar KeyError
|
|
temperatura = obj.get("temp", 0.0)
|
|
return temperatura
|
|
except (ValueError, AttributeError) as e:
|
|
print("Erro ao processar objeto:", e)
|
|
return None`,
|
|
dicaPro: "Se EXCVADDR for algo como 0x3fxxxxxx ou 0x40xxxxxx mas seu código falha, você pode estar acessando um array fora do limite (buffer overflow) que sobrescreveu ponteiros na memória.",
|
|
},
|
|
{
|
|
id: "guru-iram-cache",
|
|
titulo: "Cache Error / InstructionFetchError em ISRs",
|
|
categoria: "cpu-panics",
|
|
sintomas: ["bootloop", "null-pointer"],
|
|
gravidade: "Alta",
|
|
logSerial: "Guru Meditation Error: Core 0 panic'ed (Cache disabled but cached memory region accessed)\nGuru Meditation Error: Core 0 panic'ed (InstructionFetchError)",
|
|
resumo: "Uma rotina de interrupção (ISR) tentou executar código ou ler dados da Flash SPI enquanto a Flash estava desativada para uma operação de escrita/leitura.",
|
|
causaRaiz:
|
|
"Por padrão, o código do ESP32 fica armazenado na memória Flash externa e é carregado sob demanda para a CPU através da memória Cache interna. Quando o ESP32 grava dados na Flash (como em gravações NVS, LittleFS, SPIFFS ou atualização OTA), o controlador desativa o Cache de instruções temporariamente. Se uma interrupção de hardware (timer, GPIO, etc.) disparar nesse instante e a função ISR estiver na Flash, a CPU não consegue buscar a próxima instrução e entra em pânico imediato.",
|
|
gambiarra: {
|
|
titulo: "Desativar interrupções antes de gravar na Flash",
|
|
descricao: "Tentar envolver operações de gravação de arquivos em blocos de noInterrupts() indiscriminadamente.",
|
|
consequencia: "Gera perda de pulsos de sensores de alta velocidade, instabilidade nos timers do sistema e potenciais estouros de Watchdog.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Alocar ISRs e constantes em IRAM / DRAM",
|
|
passos: [
|
|
"Decore TODA função de callback de interrupção com o atributo IRAM_ATTR (ou IRAM_ATTR static void...).",
|
|
"Garanta que variáveis ou strings acessadas dentro da ISR também residam em DRAM (evite usar strings literais diretas dentro da ISR sem a tag DRAM_ATTR no ESP-IDF).",
|
|
"Nunca chame funções pesadas de bibliotecas externas (como Serial.print ou cálculos de float pesados) dentro de uma ISR.",
|
|
],
|
|
},
|
|
codigoArduino: `// ISR declarada corretamente na IRAM:
|
|
volatile uint32_t contadorPulsos = 0;
|
|
|
|
void IRAM_ATTR tratarInterrupcaoGPIO() {
|
|
contadorPulsos++;
|
|
}
|
|
|
|
void setup() {
|
|
pinMode(4, INPUT_PULLUP);
|
|
attachInterrupt(digitalPinToInterrupt(4), tratarInterrupcaoGPIO, FALLING);
|
|
}`,
|
|
codigoEspIdf: `// No ESP-IDF:
|
|
#include "esp_attr.h"
|
|
#include "driver/gpio.h"
|
|
|
|
static volatile uint32_t pulsos = 0;
|
|
|
|
// Função colocada explicitamente na memória interna IRAM:
|
|
static void IRAM_ATTR gpio_isr_handler(void* arg) {
|
|
pulsos++;
|
|
}
|
|
|
|
void app_main(void) {
|
|
gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
|
|
gpio_isr_handler_add(GPIO_NUM_4, gpio_isr_handler, NULL);
|
|
}`,
|
|
codigoMicroPython: `# Tratamento seguro de interrupções (ISR) no MicroPython:
|
|
import micropython
|
|
from machine import Pin
|
|
|
|
# Aloca buffer de emergência para depurar exceções dentro de ISRs:
|
|
micropython.alloc_emergency_exception_buf(100)
|
|
|
|
contador_pulsos = 0
|
|
|
|
# Callback de interrupção: NÃO aloque memória (sem strings, sem floats novos)
|
|
def tratar_pulso(pin):
|
|
global contador_pulsos
|
|
contador_pulsos += 1
|
|
|
|
sensor = Pin(4, Pin.IN, Pin.PULL_UP)
|
|
sensor.irq(trigger=Pin.IRQ_FALLING, handler=tratar_pulso)`,
|
|
dicaPro: "Se você passar ESP_INTR_FLAG_IRAM ao registrar a interrupção no ESP-IDF, qualquer função chamada por essa interrupção (inclusive funções do FreeRTOS) DEVE suportar IRAM (ex: xQueueSendFromISR).",
|
|
},
|
|
{
|
|
id: "freertos-twdt",
|
|
titulo: "Task Watchdog Timer (TWDT) Timeout",
|
|
categoria: "freertos",
|
|
sintomas: ["bootloop", "wdt-reset"],
|
|
gravidade: "Crítica",
|
|
logSerial: "E (10532) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:\nE (10532) task_wdt: - IDLE0 (CPU 0)\nTask watchdog got triggered. System will be reset.",
|
|
resumo: "Uma tarefa de alta prioridade entrou em um loop bloqueante e não cedeu tempo de CPU, impedindo que a tarefa IDLE alimente o cão de guarda.",
|
|
causaRaiz:
|
|
"O FreeRTOS no ESP32 executa uma tarefa essencial de prioridade 0 chamada IDLE em cada núcleo de CPU. O Task Watchdog monitora se a tarefa IDLE consegue rodar periodicamente (por padrão, a cada 5 segundos). Se você criar uma tarefa com prioridade >= 1 que contenha um loop while(1) sem nenhuma chamada bloqueante (vTaskDelay, leitura de fila, semáforo), a CPU fica 100% ocupada e o Watchdog dispara um reset de emergência.",
|
|
gambiarra: {
|
|
titulo: "Desabilitar o Task Watchdog no menuconfig ou aumentar para 60s",
|
|
descricao: "Desligar o TWDT para o código parar de reiniciar.",
|
|
consequencia: "Se o seu código travar em um loop infinito ou deadlock, o microcontrolador ficará congelado para sempre, exigindo que alguém vá até o local desligar da tomada.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Arquitetura orientada a eventos e concessão de CPU (Yield)",
|
|
passos: [
|
|
"Nunca utilize loops de espera ativa vazios while(!condicao); em tarefas FreeRTOS.",
|
|
"Sempre insira vTaskDelay(pdMS_TO_TICKS(10)) ou espere por um evento através de xQueueReceive(), ulTaskNotifyTake() ou xSemaphoreTake() com timeout.",
|
|
"Se for necessário executar um processamento matemático contínuo e pesado, alimente o Watchdog explicitamente com esp_task_wdt_reset().",
|
|
],
|
|
},
|
|
codigoArduino: `// FORMA CORRETA NO ARDUINO COM FREERTOS:
|
|
void minhaTarefa(void *pvParameters) {
|
|
for (;;) {
|
|
// Executa a leitura do sensor
|
|
float valor = analogRead(36);
|
|
|
|
// LIBERA a CPU para o FreeRTOS e a tarefa IDLE:
|
|
vTaskDelay(pdMS_TO_TICKS(100)); // Aguarda 100ms de forma não-bloqueante
|
|
}
|
|
}`,
|
|
codigoEspIdf: `// ESP-IDF com Task Watchdog:
|
|
#include "esp_task_wdt.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
|
|
void tarefa_processamento(void *pvParameters) {
|
|
// Opcional: Inscrever a própria tarefa no TWDT
|
|
esp_task_wdt_add(NULL);
|
|
|
|
while (1) {
|
|
// Processamento...
|
|
|
|
// Alimenta o Watchdog se o bloco for longo:
|
|
esp_task_wdt_reset();
|
|
vTaskDelay(pdMS_TO_TICKS(50));
|
|
}
|
|
}`,
|
|
codigoMicroPython: `# Watchdog e laços não-bloqueantes com uasyncio no MicroPython:
|
|
from machine import WDT
|
|
import uasyncio as asyncio
|
|
|
|
# Inicializa o Watchdog de hardware com timeout de 5 segundos
|
|
wdt = WDT(timeout=5000)
|
|
|
|
async def tarefa_sensor():
|
|
while True:
|
|
# Alimenta o cão de guarda a cada ciclo saudável:
|
|
wdt.feed()
|
|
|
|
# Cede controle para o escalonador cooperativo:
|
|
await asyncio.sleep_ms(100)
|
|
|
|
async def main():
|
|
asyncio.create_task(tarefa_sensor())
|
|
while True:
|
|
await asyncio.sleep(1)
|
|
|
|
asyncio.run(main())`,
|
|
dicaPro: "No Arduino, a função delay(ms) na verdade chama internamente o vTaskDelay do FreeRTOS. Porém, loops que usam delayMicroseconds() ou operações puras de CPU não cedem tempo e podem disparar o TWDT se durarem mais de alguns segundos.",
|
|
},
|
|
{
|
|
id: "freertos-stack-overflow",
|
|
titulo: "Stack Overflow (Estouro de Pilha da Tarefa)",
|
|
categoria: "freertos",
|
|
sintomas: ["bootloop", "null-pointer"],
|
|
gravidade: "Crítica",
|
|
logSerial: "Guru Meditation Error: Core 1 panic'ed (Unhandled debug exception).\nDebug exception reason: Stack canary watchpoint triggered (minha_tarefa)",
|
|
resumo: "A tarefa consumiu mais memória de pilha (Stack) do que a quantidade alocada em sua criação, corrompendo o canário de proteção do RTOS.",
|
|
causaRaiz:
|
|
"Cada tarefa no FreeRTOS recebe um bloco fixo de memória contígua para suas variáveis locais, argumentos de funções e endereços de retorno de chamadas. Se você declarar arrays grandes (ex: char buffer[2048];), instanciar buffers JSON pesados (ex: DynamicJsonDocument doc(4096);), ou fizer chamadas recursivas profundas dentro de uma tarefa configurada com stack padrão de 2048 bytes, a pilha ultrapassa o limite e sobrescreve áreas críticas do sistema.",
|
|
gambiarra: {
|
|
titulo: "Colocar 64KB de stack em todas as tarefas sem critério",
|
|
descricao: "Alocar stacks gigantescas para não se preocupar com estouro.",
|
|
consequencia: "A memória interna SRAM do ESP32 (cerca de 320KB úteis) se esgotará rapidamente, causando falhas de inicialização do Wi-Fi e alocação de heap.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Dimensionamento consciente e monitoramento com HighWaterMark",
|
|
passos: [
|
|
"Meça o consumo real da pilha usando a função uxTaskGetStackHighWaterMark(). Ela retorna o menor número de bytes/words livres restantes que a pilha teve desde o boot.",
|
|
"Mova buffers volumosos da pilha para a Heap dinâmica (usando malloc/free temporário) ou declare-os como static fora do escopo da função se forem reutilizados.",
|
|
"Tarefas que utilizam conexões seguras TLS/HTTPS ou MQTT com SSL exigem no mínimo 6KB a 8KB de stack devido à complexidade das rotinas criptográficas do MbedTLS.",
|
|
],
|
|
},
|
|
codigoArduino: `// MONITORANDO O STACK NO ARDUINO:
|
|
void tarefaSensor(void *pvParameters) {
|
|
for (;;) {
|
|
// Código da tarefa...
|
|
|
|
// Verifica o espaço livre mínimo da pilha (em Words no FreeRTOS clássico / Bytes no ESP32)
|
|
UBaseType_t espacoLivre = uxTaskGetStackHighWaterMark(NULL);
|
|
Serial.printf("[STACK] Espaço livre mínimo: %d bytes\\n", (int)espacoLivre);
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(5000));
|
|
}
|
|
}
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
// Aloca 4096 bytes (4KB) de forma equilibrada:
|
|
xTaskCreatePinnedToCore(tarefaSensor, "tarefaSensor", 4096, NULL, 1, NULL, 1);
|
|
}`,
|
|
codigoEspIdf: `// Habilite a checagem dupla de Stack no menuconfig:
|
|
// Component config -> FreeRTOS -> Set a end of stack check -> Option 2 (Check by Stack Canary)
|
|
// Isso detecta o estouro ANTES que dados sejam corrompidos em tempo de execução.`,
|
|
codigoMicroPython: `# Monitoramento de memória e pilha no MicroPython:
|
|
import gc
|
|
import micropython
|
|
|
|
# Exibe estatísticas de memória RAM e pilha da VM do Python:
|
|
micropython.mem_info()
|
|
|
|
# Executa garbage collector para liberar blocos órfãos:
|
|
gc.collect()
|
|
print("Memória Heap Livre:", gc.mem_free(), "bytes")
|
|
print("Memória Heap Alocada:", gc.mem_alloc(), "bytes")`,
|
|
dicaPro: "Se a sua função precisa processar um JSON ou pacote HTTP esporadicamente, aloque o buffer no Heap apenas durante o processamento e libere-o logo em seguida, em vez de inflar o Stack permanente da tarefa.",
|
|
},
|
|
{
|
|
id: "memoria-fragmentacao-heap",
|
|
titulo: "Fragmentação de Heap e Memory Leaks",
|
|
categoria: "memoria",
|
|
sintomas: ["random-freeze", "tls-fail"],
|
|
gravidade: "Alta",
|
|
logSerial: "E (45892) mbedtls: mbedtls_ssl_setup returned -0x7f00\nE (45892) esp-tls: create_ssl_handle failed\nE (45893) HTTP_CLIENT: Connection failed, out of memory",
|
|
resumo: "O microcontrolador falha ao alocar memória mesmo reportando uma quantidade total de memória livre aparentemente alta.",
|
|
causaRaiz:
|
|
"A memória Heap fica fragmentada quando ocorrem milhares de alocações e desalocações de tamanhos variados ao longo do tempo (muito comum ao usar objetos String do Arduino com concatenação contínua de texto em loops). O heap se divide em pequenos blocos livres separados por blocos ocupados. Quando o driver de Wi-Fi ou a biblioteca TLS precisa de um único bloco contíguo de 40KB para o buffer de criptografia SSL, o malloc falha mesmo que existam 100KB de memória livre total dispersa.",
|
|
gambiarra: {
|
|
titulo: "Reiniciar o ESP32 periodicamente com ESP.restart() a cada X horas",
|
|
descricao: "Agendar um reboot diário para limpar a memória fragmentada.",
|
|
consequencia: "Apenas camufla o defeito: em condições de pico de requisições o dispositivo cairá muito antes do reboot programado.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Evitar strings dinâmicas e utilizar buffers estáticos pré-alocados",
|
|
passos: [
|
|
"No Arduino, evite a classe String. Utilize buffers de caracteres em estilo C (char buffer[128];) com funções seguras como snprintf().",
|
|
"Monitore a fragmentação acompanhando a relação entre a memória livre total (heap_caps_get_free_size) e o maior bloco contíguo livre (heap_caps_get_largest_free_block).",
|
|
"Em firmwares complexos no ESP-IDF, ative o Heap Memory Tracing (CONFIG_HEAP_TRACING) para listar exatamente quais arquivos e linhas esqueceram de chamar free().",
|
|
],
|
|
},
|
|
codigoArduino: `// COMPARAÇÃO:
|
|
// ❌ EVITE (Gera fragmentação severa de Heap):
|
|
// String json = "{\\"temp\\":";
|
|
// json += String(temperatura) + "}";
|
|
|
|
// ✅ CORRETO (Sem alocação dinâmica no Heap):
|
|
char payload[64];
|
|
snprintf(payload, sizeof(payload), "{\\"temp\\":%.2f,\\"umid\\":%.2f}", temperatura, umidade);
|
|
|
|
// Monitoramento:
|
|
Serial.printf("Heap Livre: %u | Maior Bloco: %u\\n",
|
|
ESP.getFreeHeap(),
|
|
ESP.getMaxAllocHeap());`,
|
|
codigoEspIdf: `// Monitoramento de Heap no ESP-IDF:
|
|
#include "esp_heap_caps.h"
|
|
#include "esp_log.h"
|
|
|
|
void inspecionar_memoria(void) {
|
|
size_t livre_total = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
|
size_t maior_bloco = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
|
|
|
|
ESP_LOGI("HEAP", "Total livre: %d bytes | Maior bloco continuo: %d bytes", livre_total, maior_bloco);
|
|
}`,
|
|
codigoMicroPython: `# Prevenção de fragmentação de Heap no MicroPython:
|
|
import gc
|
|
|
|
# 1. Habilita coleta automática
|
|
gc.enable()
|
|
|
|
# 2. Pré-aloque bytearrays para reaproveitamento em vez de criar novas strings:
|
|
buffer_leitura = bytearray(256)
|
|
|
|
def ler_sensor_sem_alocacao(stream):
|
|
# Lê reutilizando o mesmo espaço em memória (Zero-Allocation):
|
|
bytes_lidos = stream.readinto(buffer_leitura)
|
|
return buffer_leitura[:bytes_lidos]
|
|
|
|
# 3. Dispare o GC antes de abrir conexões pesadas (como HTTPS / TLS):
|
|
gc.collect()
|
|
print(f"Heap Livre: {gc.mem_free()} B | Alocado: {gc.mem_alloc()} B")`,
|
|
dicaPro: "Se o maior bloco contíguo livre for menor que 35KB ~ 40KB, conexões HTTPS/TLS modernas falharão durante o handshake de certificados.",
|
|
},
|
|
{
|
|
id: "memoria-dma-psram",
|
|
titulo: "Falha de Alocação DMA em Memória Externa (PSRAM)",
|
|
categoria: "memoria",
|
|
sintomas: ["bootloop", "random-freeze"],
|
|
gravidade: "Alta",
|
|
logSerial: "E (1204) spi_master: spi_bus_initialize: DMA channel not compatible with external RAM buffer\nESP_ERROR_CHECK failed: esp_err_t 0x102 (ESP_ERR_INVALID_ARG)",
|
|
resumo: "O firmware tentou passar um buffer alocado em PSRAM externa para um periférico com DMA (SPI, I2S, LCD, SDMMC) que só tem acesso à SRAM interna.",
|
|
causaRaiz:
|
|
"Nos chips da família ESP32 (especialmente ESP32 clássico, ESP32-S2 e ESP32-S3 com barramento padrão), o controlador de DMA dos periféricos não possui barramento físico com acesso direto à memória PSRAM externa conectada via SPI/QSPI. O DMA exige que os buffers de transmissão e recepção estejam obrigatoriamente localizados na SRAM interna do chip.",
|
|
gambiarra: {
|
|
titulo: "Desativar o DMA nos periféricos",
|
|
descricao: "Configurar o barramento SPI/I2S para operar em modo por polling sem DMA.",
|
|
consequencia: "A taxa de transferência cai drasticamente e a CPU fica 100% ocupada durante o envio de frames para displays ou streaming de áudio.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Alocação explícita com MALLOC_CAP_DMA e MALLOC_CAP_INTERNAL",
|
|
passos: [
|
|
"Sempre aloque buffers dedicados a DMA utilizando a função heap_caps_malloc(tamanho, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL).",
|
|
"Mantenha dados pesados não-DMA (como imagens decodificadas, modelos de machine learning e áudio em repouso) na PSRAM, e copie blocos menores para buffers de DMA internos sob demanda (ping-pong buffering).",
|
|
],
|
|
},
|
|
codigoArduino: `// Alocando buffer para DMA no Arduino ESP32:
|
|
#include <esp_heap_caps.h>
|
|
|
|
uint8_t* dmaBuffer = nullptr;
|
|
|
|
void setup() {
|
|
size_t tamanho = 4096;
|
|
// Garante que o buffer reside na SRAM interna compatível com DMA:
|
|
dmaBuffer = (uint8_t*) heap_caps_malloc(tamanho, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
|
|
|
if (dmaBuffer == nullptr) {
|
|
Serial.println("[ERRO] Falha ao alocar buffer DMA na memória interna!");
|
|
}
|
|
}`,
|
|
codigoEspIdf: `// ESP-IDF:
|
|
#include "esp_heap_caps.h"
|
|
|
|
uint8_t* alocar_buffer_spi(size_t len) {
|
|
return (uint8_t*) heap_caps_aligned_alloc(4, len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
|
|
}`,
|
|
codigoMicroPython: `# No MicroPython, verifique a memória PSRAM disponível:
|
|
import gc
|
|
import esp32
|
|
|
|
# Se o firmware foi compilado com suporte a SPIRAM (ex: firmwares com 'SPIRAM'):
|
|
print("Memória total acessível no MicroPython:", gc.mem_free() + gc.mem_alloc(), "bytes")
|
|
|
|
# Para operações rápidas com periféricos, use bytearrays contíguos:
|
|
buffer_spi = bytearray(1024)`,
|
|
dicaPro: "No ESP32-P4, a arquitetura avançada de barramento AXI permite DMA em certas regiões externas, mas para toda a linha ESP32/S2/S3/C3 a regra da SRAM interna é estrita.",
|
|
},
|
|
{
|
|
id: "boot-failed-connect",
|
|
titulo: "Failed to connect to ESP32: Timed out waiting for packet header",
|
|
categoria: "boot-flash",
|
|
sintomas: ["upload-fail"],
|
|
gravidade: "Média",
|
|
logSerial: "A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header\nesptool.py v4.6\nConnecting...................",
|
|
resumo: "A ferramenta de gravação (esptool / Arduino IDE / PlatformIO) não conseguiu colocar o microcontrolador no modo de bootloader UART.",
|
|
causaRaiz:
|
|
"Para iniciar a gravação do firmware, o chip de conversão USB-Serial (CH340, CP2102, FTDI) utiliza as linhas DTR e RTS para puxar o pino GPIO 0 para LOW enquanto pulsa o pino EN/RST para LOW e depois HIGH. Em muitas placas de desenvolvimento populares, o circuito de temporização RC (resistor-capacitor) do pino EN não possui capacitância suficiente para segurar o reset durante a transição do sinal DTR.",
|
|
gambiarra: {
|
|
titulo: "Ficar segurando o botão BOOT com o dedo a cada upload",
|
|
descricao: "Pressionar o botão físico BOOT/GPIO0 toda vez que o compilador terminar de gerar o binário.",
|
|
consequencia: "Inconveniente para desenvolvimento ágil e impossível em placas seladas ou embutidas dentro de gabinetes.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Capacitor de 10µF no pino EN ou verificação do cabo de dados",
|
|
passos: [
|
|
"Conecte um capacitor eletrolítico ou cerâmico de 10µF (ou 1µF a 10µF) entre o pino EN (RST) e o GND da placa. Isso estabiliza a rampa de reset automático.",
|
|
"Verifique se o cabo USB possui linhas de dados (D+ e D-) ativas. Muitos cabos de carregador de celular baratos possuem apenas os fios de alimentação VBUS e GND.",
|
|
"No Linux, certifique-se de que seu usuário pertence ao grupo 'dialout' (sudo usermod -a -G dialout $USER) e que o serviço 'brltty' não está sequestrando a porta serial.",
|
|
],
|
|
},
|
|
codigoArduino: `// Dica de Linha de Comando para testar a comunicação serial com o esptool:
|
|
// python -m esptool --port /dev/ttyUSB0 chip_id
|
|
// Se retornar o MAC e o modelo do chip, a comunicação física está perfeita.`,
|
|
codigoEspIdf: `// No ESP-IDF:
|
|
// idf.py -p /dev/ttyUSB0 -b 460800 flash
|
|
// Se o upload falhar em altas velocidades, reduza a taxa de baud rate para 115200:
|
|
// idf.py -p /dev/ttyUSB0 -b 115200 flash`,
|
|
codigoMicroPython: `# Gravação do firmware MicroPython oficial no ESP32 via terminal:
|
|
# 1. Apague a memória Flash:
|
|
# esptool.py --port /dev/ttyUSB0 erase_flash
|
|
|
|
# 2. Grave o binário com taxa de baud segura:
|
|
# esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 ESP32_GENERIC-*.bin`,
|
|
dicaPro: "Se estiver usando módulos ESP32-S3 ou C3 com USB nativo (Direct USB-JTAG), certifique-se de que a porta correta selecionada é a porta CDC/JTAG e não a UART legada.",
|
|
},
|
|
{
|
|
id: "tls-sntp-clock-fail",
|
|
titulo: "Falha de Handshake TLS/HTTPS por Relógio Desincronizado",
|
|
categoria: "conectividade",
|
|
sintomas: ["tls-fail", "random-freeze"],
|
|
gravidade: "Alta",
|
|
logSerial: "E (15420) esp-tls-mbedtls: mbedtls_ssl_handshake returned -0x2700\nE (15420) esp-tls: Failed to verify peer certificate!\nE (15421) esp-tls: Verification info: The certificate is not yet valid (or has expired)",
|
|
resumo: "Conexões seguras HTTPS, AWS IoT, MQTT com TLS ou APIs Web falham porque o relógio interno do ESP32 está na data padrão de 01/01/1970.",
|
|
causaRaiz:
|
|
"Certificados de segurança digitais (X.509 SSL/TLS) possuem um período estrito de validade (Not Before e Not After). Como o ESP32 não possui uma bateria de RTC externa por padrão, ao ligar seu relógio interno sempre inicia na época Unix zero (1970). Quando o cliente MbedTLS valida a data do certificado do servidor, considera que o certificado 'ainda não é válido' (pois 2026 é no futuro em relação a 1970) e aborta a conexão criptografada imediatamente com o erro -0x2700 (MBEDTLS_ERR_X509_CERT_VERIFY_FAILED).",
|
|
gambiarra: {
|
|
titulo: "Desativar a validação de certificados SSL (Insecure / No-Verify)",
|
|
descricao: "Usar client.setInsecure() no Arduino ou desabilitar checagem de CA no ESP-IDF.",
|
|
consequencia: "Abre brecha gravíssima de segurança: seu dispositivo fica vulnerável a ataques de Man-in-the-Middle (MitM), permitindo que invasores interceptem senhas e firmwares.",
|
|
},
|
|
solucaoEngenharia: {
|
|
titulo: "Sincronização obrigatória de data e hora via SNTP antes de conexões TLS",
|
|
passos: [
|
|
"Logo após obter IP no Wi-Fi, inicie o cliente SNTP apontando para servidores confiáveis (ex: pool.ntp.br, time.google.com).",
|
|
"Aguarde o status do relógio atingir o estado sincronizado antes de iniciar a primeira conexão HTTPS/MQTT.",
|
|
"Configure o fuso horário (Timezone) correto para formatar logs com horários precisos.",
|
|
],
|
|
},
|
|
codigoArduino: `// SINCRONIZAÇÃO SNTP ANTES DO HTTPS NO ARDUINO:
|
|
#include <WiFi.h>
|
|
#include <time.h>
|
|
|
|
void sincronizarRelogio() {
|
|
// Configura servidores NTP (NTP Brasil e Google)
|
|
configTime(-3 * 3600, 0, "a.st1.ntp.br", "time.google.com");
|
|
|
|
Serial.print("Aguardando sincronizacao de horario");
|
|
time_t now = time(nullptr);
|
|
// Ano 2020 em Unix time é 1577836800. Se for menor, ainda está em 1970:
|
|
while (now < 1577836800) {
|
|
delay(500);
|
|
Serial.print(".");
|
|
now = time(nullptr);
|
|
}
|
|
Serial.println("\\n[OK] Horario sincronizado! Conexoes TLS liberadas.");
|
|
}`,
|
|
codigoEspIdf: `// SNTP no ESP-IDF:
|
|
#include "esp_sntp.h"
|
|
#include "esp_log.h"
|
|
|
|
void inicializar_sntp(void) {
|
|
ESP_LOGI("SNTP", "Iniciando cliente SNTP...");
|
|
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
|
esp_sntp_setservername(0, "pool.ntp.br");
|
|
esp_sntp_init();
|
|
|
|
// Aguarda sincronização do relógio...
|
|
}`,
|
|
codigoMicroPython: `# Sincronização SNTP e requisições HTTPS no MicroPython:
|
|
import ntptime
|
|
import time
|
|
import urequests
|
|
|
|
def sincronizar_e_requisitar():
|
|
try:
|
|
print("Sincronizando relógio via NTP...")
|
|
ntptime.host = "pool.ntp.br"
|
|
ntptime.settime() # Atualiza o RTC interno do ESP32 via NTP
|
|
print("Hora sincronizada UTC:", time.localtime())
|
|
|
|
# Agora o handshake TLS validará o certificado sem o erro -0x2700:
|
|
resposta = urequests.get("https://api.github.com")
|
|
print("Resposta HTTPS:", resposta.status_code)
|
|
resposta.close()
|
|
except Exception as e:
|
|
print("[ERRO TLS/NTP]:", e)`,
|
|
dicaPro: "Se seu projeto opera em ambientes sem acesso à internet externa (rede local isolada), configure um servidor NTP local no roteador ou adicione um módulo RTC físico como o DS3231 via I2C.",
|
|
},
|
|
];
|
|
|
|
export const regrasDecodificadorLog = [
|
|
{
|
|
padrao: /Brownout detector was triggered/i,
|
|
titulo: "Brownout Detector (Subtensão Crítica)",
|
|
tipo: "Alimentação / Hardware",
|
|
explicacao:
|
|
"A tensão no pino 3V3 do ESP32 caiu abaixo do nível seguro (geralmente por pico de corrente do rádio Wi-Fi/BLE ou fonte subdimensionada).",
|
|
acaoRecomendada:
|
|
"Adicione capacitor de 10µF a 100µF Low-ESR no VCC, use fonte estável e verifique o regulador LDO.",
|
|
},
|
|
{
|
|
padrao: /LoadProhibited|StoreProhibited/i,
|
|
titulo: "Guru Meditation: Load/StoreProhibited (Ponteiro Nulo ou Inválido)",
|
|
tipo: "CPU Panic / Exceção",
|
|
explicacao:
|
|
"Tentativa de ler ou gravar em um endereço inválido na memória (quase sempre desreferência de ponteiro NULL ou array fora de limite).",
|
|
acaoRecomendada:
|
|
"Decodifique o Backtrace com o Exception Decoder ou 'addr2line' para identificar a linha exata. Adicione checagens defensivas `if (ptr != NULL)`.",
|
|
},
|
|
{
|
|
padrao: /Cache disabled but cached memory region accessed|InstructionFetchError/i,
|
|
titulo: "Cache Error em Interrupção (ISR fora da IRAM)",
|
|
tipo: "CPU Panic / Flash",
|
|
explicacao:
|
|
"Uma rotina de interrupção (ISR) tentou rodar a partir da memória Flash enquanto ela estava ocupada gravando dados (NVS, LittleFS ou OTA).",
|
|
acaoRecomendada:
|
|
"Adicione o atributo `IRAM_ATTR` na função de interrupção e garanta que ela não acesse variáveis na Flash sem DRAM_ATTR.",
|
|
},
|
|
{
|
|
padrao: /Task watchdog got triggered/i,
|
|
titulo: "Task Watchdog Timer (TWDT) Timeout",
|
|
tipo: "FreeRTOS / Multitarefa",
|
|
explicacao:
|
|
"Uma tarefa de prioridade alta monopolizou a CPU sem ceder tempo (sem vTaskDelay ou bloqueio), impedindo o watchdog da tarefa IDLE.",
|
|
acaoRecomendada:
|
|
"Adicione `vTaskDelay(pdMS_TO_TICKS(10))` em loops longos ou use filas/semáforos em vez de loops `while(1)` contínuos.",
|
|
},
|
|
{
|
|
padrao: /Stack canary watchpoint triggered/i,
|
|
titulo: "Stack Overflow (Estouro de Pilha da Tarefa)",
|
|
tipo: "FreeRTOS / Memória",
|
|
explicacao:
|
|
"A tarefa excedeu a quantidade de memória de pilha (Stack) alocada na sua criação, corrompendo o canário de proteção.",
|
|
acaoRecomendada:
|
|
"Aumente o tamanho da pilha no `xTaskCreate` (ex: de 2048 para 4096 bytes) e mova arrays grandes para o Heap ou variáveis estáticas.",
|
|
},
|
|
{
|
|
padrao: /Timed out waiting for packet header|Failed to connect to ESP32/i,
|
|
titulo: "Falha de Conexão UART / Upload",
|
|
tipo: "Bootloader / Conexão",
|
|
explicacao:
|
|
"O computador não conseguiu colocar o ESP32 em modo de gravação via DTR/RTS ou o cabo USB não possui linhas de dados.",
|
|
acaoRecomendada:
|
|
"Coloque um capacitor de 10µF entre o pino EN e o GND, troque o cabo USB por um com fios de dados e teste segurar o botão BOOT durante a conexão.",
|
|
},
|
|
{
|
|
padrao: /The certificate is not yet valid|-0x2700/i,
|
|
titulo: "Falha de Certificado SSL/TLS (Relógio em 1970)",
|
|
tipo: "Conectividade / TLS",
|
|
explicacao:
|
|
"O ESP32 tentou autenticar um certificado HTTPS/TLS com a data zerada na época Unix (01/01/1970).",
|
|
acaoRecomendada:
|
|
"Sincronize o horário via SNTP (`configTime` no Arduino ou `ntptime.settime()` no MicroPython) antes de iniciar requisições HTTPS seguras.",
|
|
},
|
|
{
|
|
padrao: /rst:0x1 \(POWERON_RESET\),boot:0x[0-9a-fA-F]+/i,
|
|
titulo: "Reset por Power-On / Strapping Pins",
|
|
tipo: "Hardware / Boot",
|
|
explicacao:
|
|
"O microcontrolador reiniciou e reportou o registrador de strapping pins. Se travar após isso, um pino de boot pode estar em nível lógico incorreto.",
|
|
acaoRecomendada:
|
|
"Verifique se GPIOs como 0, 2, 12, 15 (ESP32) ou 8, 9 (C3) estão conectados a resistores ou periféricos que forçam níveis inadequados no boot.",
|
|
},
|
|
];
|