{"skill":{"slug":"esp32","displayName":"ESP32","summary":"Avoid common ESP32 mistakes — GPIO conflicts, WiFi+ADC2 trap, deep sleep gotchas, and FreeRTOS pitfalls.","description":"---\nname: ESP32\ndescription: Avoid common ESP32 mistakes — GPIO conflicts, WiFi+ADC2 trap, deep sleep gotchas, and FreeRTOS pitfalls.\nmetadata: {\"clawdbot\":{\"emoji\":\"📟\",\"os\":[\"linux\",\"darwin\",\"win32\"]}}\n---\n\n## GPIO Restrictions\n- Strapping pins boot behavior — GPIO0, GPIO2, GPIO12, GPIO15 affect boot mode\n- GPIO6-11 connected to flash — don't use, crashes immediately\n- GPIO34-39 input only — no output, no pullup/pulldown\n- ADC2 unusable with WiFi active — use ADC1 (GPIOs 32-39) when WiFi enabled\n\n## Deep Sleep\n- Only RTC GPIOs for wakeup — GPIO0, 2, 4, 12-15, 25-27, 32-39\n- `RTC_DATA_ATTR` for persistent variables — regular RAM lost in deep sleep\n- `esp_sleep_enable_ext0_wakeup()` for single pin — `ext1` for multiple pins\n- WiFi reconnect takes 1-3 seconds after wake — plan for this delay\n\n## WiFi Gotchas\n- Call `WiFi.mode()` before `WiFi.begin()` — mode affects behavior\n- `WiFi.setAutoReconnect(true)` doesn't always work — implement reconnect in loop\n- Event-driven with `WiFi.onEvent()` more reliable — don't poll `WiFi.status()`\n- Static IP faster than DHCP — saves 2-5 seconds on connect\n\n## FreeRTOS\n- Default stack too small for printf/WiFi — use 4096+ for complex tasks\n- Task watchdog triggers at 5s default — call `vTaskDelay()` or feed watchdog\n- `xTaskCreatePinnedToCore()` for core affinity — WiFi on core 0, your code on core 1\n- `delay()` yields to scheduler — `vTaskDelay(pdMS_TO_TICKS(ms))` in tasks\n\n## Memory\n- Heap fragments over time — preallocate buffers, avoid repeated malloc/free\n- `ESP.getFreeHeap()` for monitoring — log periodically in long-running apps\n- PSRAM available on some boards — `heap_caps_malloc(size, MALLOC_CAP_SPIRAM)`\n- String concatenation fragments heap — use `reserve()` or char arrays\n\n## Peripherals\n- No native `analogWrite()` — use LEDC: `ledcSetup()`, `ledcAttachPin()`, `ledcWrite()`\n- I2C needs external pullups usually — internal pullups too weak for fast speeds\n- SPI CS pin must be managed — `SPI.begin()` doesn't auto-configure\n- UART0 is Serial/USB — use UART1/2 for external devices\n\n## OTA Updates\n- Needs two OTA partitions — default partition scheme may have only one\n- Check `ESP.getFreeSketchSpace()` — OTA fails silently if not enough space\n- `ArduinoOTA` blocks during update — handle in loop, not in time-critical code\n\n## Power\n- Brown-out detector resets at ~2.4V — `esp_brownout_disable()` if using battery\n- WiFi TX uses 300mA peaks — power supply must handle spikes\n- Deep sleep ~10µA — but RTC peripherals add more if enabled\n","tags":{"latest":"1.0.0"},"stats":{"comments":0,"downloads":1786,"installsAllTime":8,"installsCurrent":8,"stars":3,"versions":1},"createdAt":1770681823358,"updatedAt":1778486278647},"latestVersion":{"version":"1.0.0","createdAt":1770681823358,"changelog":"Initial release","license":null},"metadata":{"setup":[],"os":["linux","darwin","win32"],"systems":null},"owner":{"handle":"ivangdavila","userId":"s178jdk12x4qj3gs2se3etxf3h83h7ft","displayName":"Iván","image":"https://avatars.githubusercontent.com/u/81719670?v=4"},"moderation":null}