Files
ESPDocs/lib/data/de/diagnostico.js
T
Lucas RayanandAntigravity 7fce46b9e1
CI / Lint e auditorias (push) Successful in 49s
CI / Trivy (dependências e segredos) (push) Successful in 11s
CI / Imagem Docker (linux/arm64) (push) Successful in 3m14s
feat(i18n): French and German localization (phase 5)
- Add full message catalogs and content for French (fr) and German (de)
- Implement ASCII canonical slugs for French and German routes
- Add language-specific search endpoints (/api/busca/fr, /api/busca/de)
- Configure strict 404 responses for /fr/livro and /de/livro
- Localize SEO, OpenGraph (fr_FR, de_DE), Twitter and JSON-LD schemas
- Add localized code example comments across 14 examples for fr and de
- Enable 'fr' and 'de' in ENABLED_LOCALES with root negotiation and redirect
- Extend test suite in check-i18n, smoke-imagem and verifica-vazamentos

Co-Authored-By: Antigravity <noreply@google.com>
2026-11-01 22:06:36 -03:00

725 lines
36 KiB
JavaScript

/**
* Strukturierte Datenbank für Fehlerdiagnose, häufige Fehler und Problembehebung auf ESP32.
* Umfasst 6 technische Kategorien mit Ursachenanalysen, Best Practices vs. Behelfslösungen und Codebeispielen
* in Arduino C++, ESP-IDF (C) und MicroPython.
*/
export const categoriasDiagnostico = [
{
id: "alimentacao",
nome: "Stromversorgung & Hardware",
icone: "Zap",
cor: "amber",
descricao: "Spannungseinbrüche durch Wi-Fi-/BLE-Sendeimpulse, fehlerhafte Pegel an Strapping-Pins, elektromagnetisches Rauschen und überlastete LDOs.",
},
{
id: "cpu-panics",
nome: "CPU-Panics & Guru Meditation",
icone: "Cpu",
cor: "red",
descricao: "Nullzeiger, Speicherzugriffsverletzungen (Load/StoreProhibited), ungültige Befehle und Cache-Panics in Interrupt-Routinen (ISRs).",
},
{
id: "freertos",
nome: "FreeRTOS & Multitasking",
icone: "Layers",
cor: "purple",
descricao: "Task Watchdog (TWDT), Interrupt Watchdog (IWDT), Stack-Überlauf (Stack Overflow) und Blockaden des RTOS-Schedulers.",
},
{
id: "memoria",
nome: "Speicher, Heap & PSRAM",
icone: "Activity",
cor: "blue",
descricao: "Heap-Fragmentierung, Speicherlecks (Memory Leaks), DMA-Speicherallokation und Zugriffsrestriktionen bei externem PSRAM.",
},
{
id: "boot-flash",
nome: "Bootloader & Flashen",
icone: "Terminal",
cor: "emerald",
descricao: "Serielle Verbindungsfehler (DTR/RTS), SPI-Flash-Lesefehler, Taktunstimmigkeiten und beschädigte Partitionstabellen.",
},
{
id: "conectividade",
nome: "Konnektivität & Protokolle",
icone: "Wifi",
cor: "cyan",
descricao: "Wi-Fi-Beacon-Timeouts, fehlgeschlagene TLS/HTTPS-Handshakes mangels synchronisierter SNTP-Uhrzeit und instabile Funkverbindungen.",
},
];
export const sintomasRapidos = [
{ id: "bootloop", rotulo: "🔄 Boot-Schleife (Crash Loop)", categoria: "todos" },
{ id: "wifi-crash", rotulo: "📶 Absturz bei Wi-Fi-/BLE-Aktivierung", categoria: "alimentacao" },
{ id: "upload-fail", rotulo: "🔌 Firmware-Upload fehlgeschlagen (Flash-Fehler)", categoria: "boot-flash" },
{ id: "random-freeze", rotulo: "⏱️ Friert nach Minuten oder Stunden ein", categoria: "memoria" },
{ id: "null-pointer", rotulo: "💥 Guru Meditation (CPU-Absturz)", categoria: "cpu-panics" },
{ id: "wdt-reset", rotulo: "🐕 Watchdog ausgelöst (TWDT-Reset)", categoria: "freertos" },
{ id: "tls-fail", rotulo: "🔒 HTTPS-/SSL-Verbindung schlägt fehl", categoria: "conectividade" },
];
export const errosCatalogo = [
{
id: "brownout-reset",
titulo: "Reset durch Brownout-Detektor (Spannungseinbruch)",
categoria: "alimentacao",
sintomas: ["bootloop", "wifi-crash"],
gravidade: "Hoch",
logSerial: "Brownout detector was triggered\n\nrst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)",
resumo: "Die ESP32-Versorgungsspannung fiel unter die sichere Betriebsgrenze (ca. 2.8V ~ 2.43V).",
causaRaiz:
"Bei der Initialisierung von Wi-Fi- oder BLE-Funkmodulen zieht der Leistungsverstärker (PA) kurzzeitige Stromspitzen von über 500 mA in weniger als einer Millisekunde. Können Stromquelle, lange/dünne USB-Kabel, Steckbrettschienen oder der LDO-Regler diesen Spitzenstrom nicht niederohmig liefern, bricht die 3.3V-Spannung kurzzeitig ein. Dies löst den internen Brownout-Komparator aus, um Flash-Korruption zu verhindern.",
gambiarra: {
titulo: "Brownout-Detektor per Software deaktivieren",
descricao: "Aufruf von WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0) zur Fehlerunterdrückung im Code.",
consequencia: "Extrem gefährlich: Der ESP32 führt Befehle bei Unterspannung weiter aus, was zur Korruption des SPI-Flash-Speichers, Blockaden von Peripherieregistern und unvorhersehbaren Feldausfällen führt.",
},
solucaoEngenharia: {
titulo: "Korrekte Hardware-Dimensionierung und Entkopplungskondensatoren",
passos: [
"Schalten Sie einen 10-µF- bis 100-µF-Low-ESR-Tantal- oder Keramikkondensator parallel zu einem 100-nF-Keramikkondensator so nah wie möglich an die 3V3- und GND-Pins des ESP32.",
"Verwenden Sie LDO-Regler mit mindestens 600 mA bis 1 A Spitzenstrom und hervorragendem Einschwingverhalten (z. B. AP2112K, ME6211, TPS73733). Vermeiden Sie minderwertige AMS1117-Klone.",
"Vermeiden Sie es, den ESP32 bei voller Wi-Fi-Sendeleistung über lange Steckbrettleitungen mit dünnen Jumper-Kabeln zu versorgen.",
],
},
codigoArduino: `// Do NOT disable the Brownout detector! If you need to reduce current peaks in bench testing:
#include <WiFi.h>
void setup() {
Serial.begin(115200);
// Optional: Slightly reducing maximum Wi-Fi TX power from 20dBm to 17dBm cuts current spikes by ~20%
WiFi.setTxPower(WIFI_POWER_17dBm);
WiFi.begin("SSID", "PASSWORD");
}`,
codigoEspIdf: `// ESP-IDF configuration:
#include "esp_wifi.h"
#include "esp_log.h"
void app_main(void) {
// In menuconfig: Component config -> ESP32-specific -> Hardware Brownout Reset (Keep ENABLED)
// To mitigate transient peaks in power-constrained designs:
esp_wifi_set_max_tx_power(68); // 68 = 17dBm (units of 0.25dBm)
}`,
codigoMicroPython: `# Safe Wi-Fi connection in MicroPython with supply stabilization:
import network
import time
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Wait for supply rails to settle before turning on transmitter
time.sleep_ms(200)
wlan.connect("SSID", "PASSWORD")
attempts = 0
while not wlan.isconnected() and attempts < 30:
time.sleep_ms(200)
attempts += 1
if wlan.isconnected():
print("Wi-Fi Connected! IP:", wlan.ifconfig()[0])
else:
print("[ERROR] Failed to connect Wi-Fi")`,
dicaPro: "Verlegen Sie bei eigenen Leiterplatten eine durchgehende Massefläche direkt unter dem Modul und führen Sie 3.3V-Leiterbahnen mit mindestens 0.5 mm bis 1 mm Breite aus, um ohmsche Spannungsabfälle bei HF-Sendeimpulsen zu verhindern.",
},
{
id: "strapping-pins",
titulo: "Konflikt an den Strapping-Pins beim Booten",
categoria: "alimentacao",
sintomas: ["bootloop", "upload-fail"],
gravidade: "Kritisch",
logSerial: "rst:0x1 (POWERON_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)\nflash read err, 1000\nwaiting for download",
resumo: "The ESP32 fails to boot firmware from Flash or enters download mode unintentionally because a strapping pin was pulled to an incorrect logic level during reset.",
causaRaiz:
"The instant EN/CHIP_PU rises (Power-On Reset), the CPU latches the electrical logic level on specific strapping pins to configure Flash voltage (1.8V vs 3.3V), boot mode (UART Download vs SPI Flash Boot), and clock output. Connecting external sensors, relays, or LEDs with pull-up/pull-down resistors to these pins forces invalid strapping states, halting the bootloader.",
gambiarra: {
titulo: "Adding delays in code or manually disconnecting cables at each boot",
descricao: "Attempting to fix the problem in setup() or manually unplugging wires before every reset.",
consequencia: "Useless: Strapping pins are sampled by silicon hardware before the CPU executes a single line of application code or the second-stage bootloader.",
},
solucaoEngenharia: {
titulo: "Safe GPIO allocation and reset isolation",
passos: [
"ESP32 (Classic): Avoid using GPIO 0 (Boot mode), GPIO 2 (must be LOW or floating during flashing), GPIO 12 (selects Flash voltage: pulling HIGH at reset burns/locks 3.3V flash), and GPIO 15 (suppresses boot log output if LOW).",
"ESP32-C3: Avoid pulling GPIO 8 LOW or GPIO 9 LOW during reset.",
"ESP32-S3: Watch GPIO 0, GPIO 45 (VDD_SPI voltage level), and GPIO 46.",
"If these pins must interface with peripherals, use transistors or digital bus switches to isolate them until the EN pin has completely risen and stabilized.",
],
},
codigoArduino: `// SAFE PINOUT RECOMMENDATIONS (ESP32 Classic):
// Preferred pins for I2C / SPI / General Sensors:
// SDA: GPIO 21 | SCL: GPIO 22
// SPI: MOSI 23 | MISO 19 | SCK 18 | CS 5
// WARNING: GPIOs 34, 35, 36 (VP), 39 (VN) are INPUT-ONLY (no internal pull-up/pull-down).
// Never configure them as pinMode(..., OUTPUT); nor for I2C/SPI buses.`,
codigoEspIdf: `// In ESP-IDF, lock Flash voltage via eFuse to free GPIO 12 (WARNING: IRREVERSIBLE):
// If using classic ESP32 and GPIO 12 is needed for peripherals:
// espefuse.py --port /dev/ttyUSB0 set_flash_voltage 3.3V
// This permanently disables hardware strapping sampling on GPIO 12.`,
codigoMicroPython: `# Safe pin setup in MicroPython:
from machine import Pin
# Safe pins for outputs and buttons with internal pull-up:
led = Pin(2, Pin.OUT) # GPIO 2
button = Pin(4, Pin.IN, Pin.PULL_UP) # GPIO 4 (safe)
# Pins 34, 35, 36, 39 are INPUT-ONLY with no internal pull-ups:
analog_sensor = Pin(36, Pin.IN) # Correct (requires external pull-up if used as a digital input)`,
dicaPro: "Remember: Input-only pins (GPI 34 to 39 on classic ESP32) have neither internal silicon pull-up/pull-down circuits nor output drivers. External resistors are mandatory.",
},
{
id: "guru-load-prohibited",
titulo: "Guru Meditation: LoadProhibited / StoreProhibited (Nullzeigerzugriff)",
categoria: "cpu-panics",
sintomas: ["bootloop", "null-pointer"],
gravidade: "Kritisch",
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: "The CPU attempted to read (Load) or write (Store) to an inaccessible or invalid memory address, typically null pointer 0x00000000.",
causaRaiz:
"This is the classic null pointer dereference or dangling pointer access. The EXCVADDR register shows the faulty memory address: if EXCVADDR is 0x00000000 or near zero (e.g. 0x00000008, a struct offset), code attempted to access members of an uninitialized object or a failed malloc allocation.",
gambiarra: {
titulo: "Inserting random delays or rebooting in loop without fixing root cause",
descricao: "Assuming it is a timing glitch and scattering delay() calls or masking reboots.",
consequencia: "The firmware continues crashing intermittently in production whenever the null pointer condition recurs.",
},
solucaoEngenharia: {
titulo: "Defensive validation and Backtrace decoding",
passos: [
"Always verify that pointers returned by allocation or lookup functions (malloc, WiFi.client(), JSON parsing, xQueueReceive) are non-NULL before accessing their fields.",
"Install 'Espressif Exception Decoder' in your IDE (Arduino IDE / PlatformIO) or run 'xtensa-esp32-elf-addr2line -pfia -e firmware.elf 0x400d14bc' to pinpoint the exact line of code that triggered the crash.",
"In ESP-IDF, run 'idf.py monitor' which decodes the call backtrace in real-time.",
],
},
codigoArduino: `// DEFENSIVE CODING:
struct SensorData {
float temperature;
float humidity;
};
void processSensor(SensorData* sensor) {
// Mandatory check against LoadProhibited:
if (sensor == nullptr) {
Serial.println("[ERROR] Null sensor pointer!");
return;
}
Serial.printf("Temp: %.1f C\\n", sensor->temperature);
}`,
codigoEspIdf: `// In ESP-IDF, use ESP_RETURN_ON_FALSE or explicit assertions:
#include "esp_log.h"
#include "esp_check.h"
static const char* TAG = "SENSOR";
esp_err_t read_data(char* buffer, size_t max_len) {
ESP_RETURN_ON_FALSE(buffer != NULL, ESP_ERR_INVALID_ARG, TAG, "Null buffer supplied!");
// Safe operation...
return ESP_OK;
}`,
codigoMicroPython: `# Preventing NoneType exceptions in MicroPython:
import json
def process_sensor(raw_data):
if raw_data is None:
print("[ERROR] Null data received!")
return None
try:
obj = json.loads(raw_data)
# Safe lookup with fallback default
temperature = obj.get("temp", 0.0)
return temperature
except (ValueError, AttributeError) as e:
print("Error processing payload:", e)
return None`,
dicaPro: "If EXCVADDR is 0x3fxxxxxx or 0x40xxxxxx but the code crashes, you likely experienced a buffer overflow that corrupted adjacent pointers in RAM.",
},
{
id: "guru-iram-cache",
titulo: "Cache-Fehler und InstructionFetchError in Interrupt-Serviceroutinen (ISRs)",
categoria: "cpu-panics",
sintomas: ["bootloop", "null-pointer"],
gravidade: "Hoch",
logSerial: "Guru Meditation Error: Core 0 panic'ed (Cache disabled but cached memory region accessed)\nGuru Meditation Error: Core 0 panic'ed (InstructionFetchError)",
resumo: "An interrupt service routine (ISR) tried to execute code or read constants from SPI Flash while the Flash memory controller was disabled for a write or erase operation.",
causaRaiz:
"By default, ESP32 application code resides in external SPI Flash and is fetched into CPU execution pipeline via internal Instruction Cache. When the ESP32 writes to Flash (such as NVS commits, LittleFS, SPIFFS, or OTA updates), the hardware cache is momentarily disabled. If an ISR fires during this window and its function body resides in Flash, the CPU cannot fetch the instruction and enters an immediate panic.",
gambiarra: {
titulo: "Disabling all interrupts before writing to Flash",
descricao: "Wrapping Flash file operations in indiscriminate noInterrupts() blocks.",
consequencia: "Causes dropped sensor pulses, jitter on system timers, and potential watchdog resets.",
},
solucaoEngenharia: {
titulo: "Allocating ISRs and callback constants in IRAM / DRAM",
passos: [
"Decorate EVERY hardware interrupt handler with the IRAM_ATTR attribute (e.g., void IRAM_ATTR isrHandler()).",
"Ensure any variables or constant strings accessed inside the ISR reside in DRAM (avoid inline string literals in ISR without DRAM_ATTR in ESP-IDF).",
"Never call heavy library functions (such as Serial.print or floating-point formatting) inside an interrupt handler.",
],
},
codigoArduino: `// ISR properly placed in internal IRAM:
volatile uint32_t pulseCount = 0;
void IRAM_ATTR handleGpioInterrupt() {
pulseCount++;
}
void setup() {
pinMode(4, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(4), handleGpioInterrupt, FALLING);
}`,
codigoEspIdf: `// ESP-IDF:
#include "esp_attr.h"
#include "driver/gpio.h"
static volatile uint32_t pulses = 0;
// Placed explicitly in IRAM:
static void IRAM_ATTR gpio_isr_handler(void* arg) {
pulses++;
}
void app_main(void) {
gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
gpio_isr_handler_add(GPIO_NUM_4, gpio_isr_handler, NULL);
}`,
codigoMicroPython: `# Safe interrupt handling (ISR) in MicroPython:
import micropython
from machine import Pin
# Pre-allocate emergency exception buffer for ISR debugging:
micropython.alloc_emergency_exception_buf(100)
pulse_count = 0
# Interrupt callback: do NOT allocate memory (no new strings, no new floats)
def handle_pulse(pin):
global pulse_count
pulse_count += 1
sensor = Pin(4, Pin.IN, Pin.PULL_UP)
sensor.irq(trigger=Pin.IRQ_FALLING, handler=handle_pulse)`,
dicaPro: "When passing ESP_INTR_FLAG_IRAM in ESP-IDF, every function invoked by the ISR (including FreeRTOS API calls) MUST support IRAM (e.g. xQueueSendFromISR).",
},
{
id: "freertos-twdt",
titulo: "Timeout des Task Watchdog Timers (TWDT-Timeout auf Core 0 oder Core 1)",
categoria: "freertos",
sintomas: ["bootloop", "wdt-reset"],
gravidade: "Kritisch",
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: "A high-priority task entered a busy loop without yielding CPU time, preventing the FreeRTOS IDLE task from feeding the watchdog.",
causaRaiz:
"FreeRTOS runs an essential priority-0 task called IDLE on each CPU core. The Task Watchdog monitors whether the IDLE task executes periodically (by default, within 5 seconds). If a task with priority >= 1 runs a tight while(1) loop without blocking calls (vTaskDelay, queue reads, semaphores), it starves the IDLE task, triggering an emergency hardware reset.",
gambiarra: {
titulo: "Disabling Task Watchdog in menuconfig or increasing timeout to 60s",
descricao: "Turning off the TWDT to prevent the board from rebooting.",
consequencia: "If the firmware encounters an unexpected deadlock or infinite loop, the device freezes permanently and requires manual power cycling.",
},
solucaoEngenharia: {
titulo: "Event-driven architecture and periodic CPU yield",
passos: [
"Never write empty busy-wait loops like while(!condition); in FreeRTOS tasks.",
"Always insert vTaskDelay(pdMS_TO_TICKS(10)) or wait for events with xQueueReceive(), ulTaskNotifyTake(), or xSemaphoreTake() with a timeout.",
"If heavy compute tasks must run continuously, feed the watchdog explicitly via esp_task_wdt_reset().",
],
},
codigoArduino: `// CORRECT ARDUINO FREERTOS PATTERN:
void myTask(void *pvParameters) {
for (;;) {
float sensorValue = analogRead(36);
// YIELD CPU to FreeRTOS scheduler and IDLE task:
vTaskDelay(pdMS_TO_TICKS(100)); // Non-blocking 100ms pause
}
}`,
codigoEspIdf: `// ESP-IDF Task Watchdog pattern:
#include "esp_task_wdt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void compute_task(void *pvParameters) {
esp_task_wdt_add(NULL);
while (1) {
// Compute...
// Feed watchdog during long processing cycles:
esp_task_wdt_reset();
vTaskDelay(pdMS_TO_TICKS(50));
}
}`,
codigoMicroPython: `# Watchdog and non-blocking tasks with uasyncio in MicroPython:
from machine import WDT
import uasyncio as asyncio
wdt = WDT(timeout=5000)
async def sensor_task():
while True:
wdt.feed()
await asyncio.sleep_ms(100)
async def main():
asyncio.create_task(sensor_task())
while True:
await asyncio.sleep(1)
asyncio.run(main())`,
dicaPro: "In Arduino, delay(ms) internally calls vTaskDelay. However, delayMicroseconds() or raw compute loops do not yield CPU time and will trigger the TWDT if held for more than a few seconds.",
},
{
id: "freertos-stack-overflow",
titulo: "Task-Stack-Überlauf in FreeRTOS (Stack Overflow)",
categoria: "freertos",
sintomas: ["bootloop", "null-pointer"],
gravidade: "Kritisch",
logSerial: "Guru Meditation Error: Core 1 panic'ed (Unhandled debug exception).\nDebug exception reason: Stack canary watchpoint triggered (my_task)",
resumo: "The task consumed more stack memory than allocated upon creation, corrupting the RTOS protection canary.",
causaRaiz:
"Each FreeRTOS task is allocated a fixed contiguous memory block for local variables, function arguments, and return addresses. Declaring large arrays on the stack (e.g., char buffer[2048];), heavy JSON documents, or deep call recursions within a default 2048-byte stack overflows the boundary and overwrites adjacent memory.",
gambiarra: {
titulo: "Assigning 64KB stack blindly to every task",
descricao: "Inflating task stack sizes indiscriminately to avoid overflow crashes.",
consequencia: "The ~320 KB usable SRAM of the ESP32 is quickly exhausted, leading to out-of-memory errors in Wi-Fi and TLS allocations.",
},
solucaoEngenharia: {
titulo: "Deliberate stack sizing and HighWaterMark monitoring",
passos: [
"Measure actual stack consumption using uxTaskGetStackHighWaterMark(). It returns the minimum free stack remaining since task creation.",
"Move large buffers from the stack to the heap (using malloc/free) or declare them static outside function scope if reused.",
"Tasks running secure TLS/HTTPS or MQTT over SSL connections require at least 6 KB to 8 KB of stack due to MbedTLS cryptographic frame complexity.",
],
},
codigoArduino: `// MONITORING TASK STACK IN ARDUINO:
void sensorTask(void *pvParameters) {
for (;;) {
// Task workload...
UBaseType_t freeStack = uxTaskGetStackHighWaterMark(NULL);
Serial.printf("[STACK] Remaining free stack: %d bytes\\n", (int)freeStack);
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
void setup() {
Serial.begin(115200);
// Allocate 4096 bytes (4KB) with safety margin:
xTaskCreatePinnedToCore(sensorTask, "sensorTask", 4096, NULL, 1, NULL, 1);
}`,
codigoEspIdf: `// Enable double stack checking in menuconfig:
// Component config -> FreeRTOS -> Set a end of stack check -> Option 2 (Check by Stack Canary)
// This catches overflows BEFORE memory structures become silently corrupted at runtime.`,
codigoMicroPython: `# Memory and stack inspection in MicroPython:
import gc
import micropython
micropython.mem_info()
gc.collect()
print("Free Heap:", gc.mem_free(), "bytes")
print("Allocated Heap:", gc.mem_alloc(), "bytes")`,
dicaPro: "If a function only processes an HTTP or JSON payload occasionally, allocate the buffer dynamically on the heap during the transaction and free it immediately, rather than permanently inflating task stack.",
},
{
id: "memoria-fragmentacao-heap",
titulo: "Heap-Fragmentierung und Speicherlecks (Memory Leaks)",
categoria: "memoria",
sintomas: ["random-freeze", "tls-fail"],
gravidade: "Hoch",
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: "The ESP32 fails to allocate memory despite reporting a seemingly adequate total free heap size.",
causaRaiz:
"Heap memory becomes fragmented after thousands of allocations and deallocations of varying sizes over time (common when repeatedly concatenating Arduino String objects in loops). Free heap becomes split into tiny isolated chunks. When Wi-Fi or TLS libraries request a single contiguous 40 KB block for an SSL certificate buffer, malloc fails even if 100 KB total free memory exists across disconnected fragments.",
gambiarra: {
titulo: "Scheduling periodic ESP.restart() every few hours",
descricao: "Triggering a daily reboot to reset fragmented memory.",
consequencia: "Merely conceals the bug: during traffic spikes the device crashes well ahead of the scheduled reboot.",
},
solucaoEngenharia: {
titulo: "Eliminate dynamic strings and use pre-allocated static buffers",
passos: [
"In Arduino, avoid the String class. Use standard C-style character arrays (char buffer[128];) with safe snprintf().",
"Monitor fragmentation by comparing total free memory (heap_caps_get_free_size) with the largest contiguous free block (heap_caps_get_largest_free_block).",
"In complex ESP-IDF firmware, enable Heap Memory Tracing (CONFIG_HEAP_TRACING) to locate missing free() calls.",
],
},
codigoArduino: `// COMPARISON:
// ❌ AVOID (Causes severe heap fragmentation):
// String json = "{\\"temp\\":";
// json += String(temperature) + "}";
// ✅ RECOMMENDED (Zero heap allocations):
char payload[64];
snprintf(payload, sizeof(payload), "{\\"temp\\":%.2f,\\"hum\\":%.2f}", temperature, humidity);
// Health check:
Serial.printf("Free Heap: %u | Largest Block: %u\\n",
ESP.getFreeHeap(),
ESP.getMaxAllocHeap());`,
codigoEspIdf: `// Heap monitoring in ESP-IDF:
#include "esp_heap_caps.h"
#include "esp_log.h"
void inspect_memory(void) {
size_t total_free = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t largest_block = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
ESP_LOGI("HEAP", "Total free: %d bytes | Largest contiguous: %d bytes", total_free, largest_block);
}`,
codigoMicroPython: `# Preventing heap fragmentation in MicroPython:
import gc
gc.enable()
# Pre-allocate reusable bytearrays instead of instantiating new strings:
rx_buffer = bytearray(256)
def read_sensor_zero_alloc(stream):
bytes_read = stream.readinto(rx_buffer)
return rx_buffer[:bytes_read]
gc.collect()
print(f"Free Heap: {gc.mem_free()} B | Allocated: {gc.mem_alloc()} B")`,
dicaPro: "If the largest contiguous free block drops below 35 KB to 40 KB, modern HTTPS/TLS connections will fail during the cryptographic handshake.",
},
{
id: "memoria-dma-psram",
titulo: "Fehler bei DMA-Allokationen im externen Speicher (PSRAM)",
categoria: "memoria",
sintomas: ["bootloop", "random-freeze"],
gravidade: "Hoch",
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: "Firmware attempted to pass a buffer allocated in external PSRAM to a DMA-driven peripheral (SPI, I2S, LCD, SDMMC) that can only access internal SRAM.",
causaRaiz:
"On ESP32 family chips (especially classic ESP32, ESP32-S2, and ESP32-S3 standard bus), the peripheral DMA engine has no direct physical access to external SPI/QSPI PSRAM. DMA transfers strictly require source and destination buffers to reside in internal SRAM.",
gambiarra: {
titulo: "Disabling DMA on peripherals",
descricao: "Switching SPI/I2S buses to polled CPU transfer mode without DMA.",
consequencia: "Throughput plummets and the CPU core stays 100% occupied during display updates or audio streaming.",
},
solucaoEngenharia: {
titulo: "Explicit allocation with MALLOC_CAP_DMA and MALLOC_CAP_INTERNAL",
passos: [
"Always allocate DMA buffers using heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL).",
"Keep heavy non-DMA assets (decoded images, machine learning weights, inactive audio) in PSRAM, copying small frames to internal DMA buffers on demand (ping-pong buffering).",
],
},
codigoArduino: `// Allocating DMA buffers in Arduino ESP32:
#include <esp_heap_caps.h>
uint8_t* dmaBuffer = nullptr;
void setup() {
size_t size = 4096;
// Guarantees buffer is allocated in DMA-accessible internal SRAM:
dmaBuffer = (uint8_t*) heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (dmaBuffer == nullptr) {
Serial.println("[ERROR] Failed to allocate internal DMA buffer!");
}
}`,
codigoEspIdf: `// ESP-IDF:
#include "esp_heap_caps.h"
uint8_t* allocate_spi_buffer(size_t len) {
return (uint8_t*) heap_caps_aligned_alloc(4, len, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
}`,
codigoMicroPython: `# In MicroPython, inspect available PSRAM:
import gc
import esp32
print("Total accessible memory in MicroPython:", gc.mem_free() + gc.mem_alloc(), "bytes")
buffer_spi = bytearray(1024)`,
dicaPro: "On the ESP32-P4, the advanced AXI bus matrix enables DMA into specific external memory regions, but for the ESP32/S2/S3/C3 lines, internal SRAM placement is mandatory.",
},
{
id: "boot-failed-connect",
titulo: "Serieller Verbindungsfehler beim Flashen (Timed out waiting for packet header)",
categoria: "boot-flash",
sintomas: ["upload-fail"],
gravidade: "Mittel",
logSerial: "A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header\nesptool.py v4.6\nConnecting...................",
resumo: "The programming tool (esptool / Arduino IDE / PlatformIO) was unable to place the microcontroller into UART bootloader mode.",
causaRaiz:
"To initiate flashing, the USB-UART bridge (CH340, CP2102, FTDI) toggles DTR and RTS lines to pull GPIO 0 LOW while pulsing EN/RST LOW then HIGH. On many third-party development boards, the RC timing circuit on EN lacks adequate capacitance to hold the reset state during the DTR transition.",
gambiarra: {
titulo: "Holding the physical BOOT button with your finger at every upload",
descricao: "Pressing BOOT/GPIO 0 manually each time the compiler finishes generating binaries.",
consequencia: "Inconvenient during rapid prototyping and impossible on sealed boards enclosed in enclosures.",
},
solucaoEngenharia: {
titulo: "Add a 10 µF capacitor on EN or verify USB data cable",
passos: [
"Solder a 10 µF (or 1 µF to 10 µF) ceramic or electrolytic capacitor between the EN (RST) and GND pins. This stabilizes the automatic reset ramp.",
"Ensure the USB cable has active data lines (D+ and D-). Many cheap charging cables contain only power wires.",
"On Linux, confirm your user belongs to the 'dialout' group (sudo usermod -a -G dialout $USER) and that the 'brltty' service is not holding the serial port.",
],
},
codigoArduino: `// Command-line verification with esptool:
// python -m esptool --port /dev/ttyUSB0 chip_id
// If it prints the MAC and chip model, physical communication is working.`,
codigoEspIdf: `// In ESP-IDF:
// idf.py -p /dev/ttyUSB0 -b 460800 flash
// If flashing fails at high speeds, reduce baud rate:
// idf.py -p /dev/ttyUSB0 -b 115200 flash`,
codigoMicroPython: `# Flashing official MicroPython firmware via terminal:
# 1. Erase flash:
# esptool.py --port /dev/ttyUSB0 erase_flash
# 2. Flash binary at safe baud rate:
# esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 ESP32_GENERIC-*.bin`,
dicaPro: "When using ESP32-S3 or C3 modules with native USB (Direct USB-JTAG), verify that your tooling is configured for the USB CDC/JTAG port rather than a legacy UART bridge.",
},
{
id: "tls-sntp-clock-fail",
titulo: "Fehlgeschlagener TLS/HTTPS-Handshake wegen nicht synchronisierter Uhrzeit (Jahr 1970)",
categoria: "conectividade",
sintomas: ["tls-fail", "random-freeze"],
gravidade: "Hoch",
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: "Secure HTTPS, AWS IoT, MQTT over TLS, or Web API requests fail because the internal ESP32 RTC defaults to 01/01/1970.",
causaRaiz:
"Digital certificates (X.509 SSL/TLS) include strict validity windows (Not Before and Not After). Because typical ESP32 boards lack an external RTC battery, the internal clock resets to the Unix epoch (1970) on every cold boot. When MbedTLS checks the server certificate date, it deems it 'not yet valid' (since current dates are decades ahead of 1970), aborting the handshake with error -0x2700 (MBEDTLS_ERR_X509_CERT_VERIFY_FAILED).",
gambiarra: {
titulo: "Disabling SSL certificate verification (Insecure / No-Verify)",
descricao: "Using client.setInsecure() in Arduino or turning off CA validation in ESP-IDF.",
consequencia: "Creates a critical security vulnerability: the device is completely exposed to Man-in-the-Middle (MitM) attacks, allowing credentials and firmware to be intercepted.",
},
solucaoEngenharia: {
titulo: "Mandatory SNTP time synchronization prior to opening TLS sockets",
passos: [
"Immediately after acquiring an IP address, start the SNTP client querying reliable NTP servers (e.g. pool.ntp.org, time.google.com).",
"Block outbound HTTPS/MQTT connections until system time is confirmed synchronized.",
"Set the correct timezone string so log timestamps match local operational time.",
],
},
codigoArduino: `// SNTP SYNCHRONIZATION BEFORE HTTPS IN ARDUINO:
#include <WiFi.h>
#include <time.h>
void syncClock() {
configTime(0, 0, "pool.ntp.org", "time.google.com");
Serial.print("Waiting for NTP time sync");
time_t now = time(nullptr);
// Year 2024 in Unix timestamp is > 1700000000. If smaller, clock is still in 1970:
while (now < 1700000000) {
delay(500);
Serial.print(".");
now = time(nullptr);
}
Serial.println("\\n[OK] Clock synchronized! TLS handshakes enabled.");
}`,
codigoEspIdf: `// SNTP in ESP-IDF:
#include "esp_sntp.h"
#include "esp_log.h"
void initialize_sntp(void) {
ESP_LOGI("SNTP", "Starting SNTP client...");
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
esp_sntp_setservername(0, "pool.ntp.org");
esp_sntp_init();
}`,
codigoMicroPython: `# SNTP synchronization and HTTPS requests in MicroPython:
import ntptime
import time
import urequests
def sync_and_request():
try:
print("Synchronizing clock via NTP...")
ntptime.host = "pool.ntp.org"
ntptime.settime()
print("UTC Time synchronized:", time.localtime())
response = urequests.get("https://api.github.com")
print("HTTPS Response:", response.status_code)
response.close()
except Exception as e:
print("[TLS/NTP ERROR]:", e)`,
dicaPro: "If operating in isolated local networks without internet access, configure a local NTP server on the gateway router or add a physical DS3231 RTC module over I2C.",
},
];
export const regrasDecodificadorLog = [
{
padrao: /Brownout detector was triggered/i,
titulo: "Brownout-Detektor (Kritische Unterspannung)",
tipo: "Stromversorgung / Hardware",
explicacao:
"Die Spannung an der 3.3V-Schiene fiel unter die sichere Betriebsgrenze (typischerweise verursacht durch Wi-Fi/BLE-Sendeimpulse oder ein zu schwaches Netzteil).",
acaoRecomendada:
"Fügen Sie einen 10-µF- bis 100-µF-Low-ESR-Kondensator an der VCC-Leitung hinzu, prüfen Sie die Stromkabel und stellen Sie sicher, dass der LDO-Regler ausreichend Strom liefert.",
},
{
padrao: /LoadProhibited|StoreProhibited/i,
titulo: "Guru Meditation: Load/StoreProhibited (Null- oder ungültiger Zeiger)",
tipo: "CPU-Panic / Exception",
explicacao:
"Es wurde versucht, auf eine ungültige Speicheradresse zuzugreifen (meist Dereferenzierung eines Nullzeigers oder Feldgrenzenüberschreitung).",
acaoRecomendada:
"Dekodieren Sie den Backtrace mit Exception Decoder oder 'addr2line', um die genaue Zeile zu finden. Fügen Sie defensive Prüfungen 'if (ptr != NULL)' ein.",
},
{
padrao: /Cache disabled but cached memory region accessed|InstructionFetchError/i,
titulo: "Interrupt-Cache-Fehler (ISR außerhalb des IRAM)",
tipo: "CPU-Panic / Flash",
explicacao:
"Eine Interrupt-Serviceroutine (ISR) versuchte, Code aus dem externen Flash auszuführen, während der SPI-Flash-Cache für Schreib-/Löschvorgänge deaktiviert war.",
acaoRecomendada:
"Versehen Sie die Interrupt-Routine mit dem IRAM_ATTR-Attribut und alle in der ISR verwendeten Konstanten/Strings mit DRAM_ATTR.",
},
{
padrao: /Task watchdog got triggered|TWDT/i,
titulo: "Task-Watchdog-Timeout (Blockierte FreeRTOS-Task)",
tipo: "FreeRTOS / Watchdog",
explicacao:
"Eine hochpriorisierte Task belegt die CPU dauerhaft, sodass die IDLE-Task nicht zur Ausführung kommt und den Watchdog nicht zurücksetzen kann.",
acaoRecomendada:
"Fügen Sie vTaskDelay(1) oder delay(1) in rechenintensive Endlosschleifen ein, oder nutzen Sie Queues und Semaphore statt aktiver Warteschleifen.",
},
{
padrao: /Stack canary watchpoint got triggered|Stack overflow/i,
titulo: "Task-Stack-Überlauf (Stack Overflow)",
tipo: "FreeRTOS / Task-Speicher",
explicacao:
"Die Task hat den bei ihrer Erstellung reservierten Stack-Speicher aufgebraucht und die Sicherheitsmarkierung (Stack Canary) überschrieben.",
acaoRecomendada:
"Erhöhen Sie den Stack in xTaskCreate (z. B. von 2048 auf 4096 Bytes) und verlagern Sie große lokale Arrays auf den Heap.",
},
{
padrao: /Timed out waiting for packet header|Failed to connect to ESP32/i,
titulo: "Serieller Verbindungsfehler beim Flashen",
tipo: "Bootloader / Verbindung",
explicacao:
"Der Computer konnte den ESP32 über die DTR/RTS-Signale der seriellen Schnittstelle nicht in den Download-Modus versetzen.",
acaoRecomendada:
"Schließen Sie einen 10-µF-Kondensator zwischen EN und GND an, prüfen Sie das USB-Datenkabel oder halten Sie die BOOT-Taste beim Einstecken gedrückt.",
},
{
padrao: /The certificate is not yet valid|-0x2700/i,
titulo: "TLS/HTTPS-Zertifikatsfehler (Systemzeit im Jahr 1970)",
tipo: "Konnektivität / TLS",
explicacao:
"Der ESP32 versuchte, ein HTTPS/TLS-Zertifikat mit nicht synchronisierter interner Uhrzeit (Unix-Epoche 1970) zu validieren.",
acaoRecomendada:
"Synchronisieren Sie die Uhrzeit über SNTP (configTime in Arduino oder ntptime in MicroPython) vor dem Aufbau von TLS-Verbindungen.",
},
{
padrao: /rst:0x1 \(POWERON_RESET\),boot:0x[0-9a-fA-F]+/i,
titulo: "Power-On-Reset / Abtastung der Strapping-Pins",
tipo: "Hardware / Boot",
explicacao:
"Der Mikrocontroller wurde neu gestartet und hat seine Boot-Pins abgetastet. Friert er sofort ein, liegt an einem Strapping-Pin ein falscher Pegel an.",
acaoRecomendada:
"Stellen Sie sicher, dass die GPIO-Strapping-Pins beim Einschalten nicht durch externe Schaltungen auf unzulässige Pegel gezwungen werden.",
},
];
export const analisarLogSerial = regrasDecodificadorLog;
export const ERROS_COMUNS = errosCatalogo;