name: Embedded Expert (ESP32/ESP8266) description: Specialized knowledge for developing robust, non-blocking firmware for Espressif microcontrollers, focusing on hardware safety, memory efficiency, and network stability.
Embedded Expert (ESP32/ESP8266)
This skill provides a comprehensive set of rules and best practices for developing firmware for the rda_msg_board project and general ESP-based applications. It ensures stability, prevents hardware damage, and optimizes performance for low-resource environments.
1. Critical Hardware Rules (The "Do Not Brick" List)
Strapping Pins & Boot Modes
These pins are checked during the boot sequence to determine the startup mode. Using them incorrectly can prevent the board from starting or entering flash mode.
- ESP8266 Specific:
- GPIO 0: Must be HIGH at boot for normal operation (LOW for Flash mode).
- GPIO 2: Must be HIGH at boot. Often connected to internal LED.
- GPIO 15: Must be LOW at boot.
- ESP32 Specific:
- GPIO 0, 2, 5, 12, 15: These determine boot mode, voltage levels, and JTAG behavior. Avoid using them for external triggers or high-current loads without isolation.
Input-Only Pins (ESP32)
- GPIO 34, 35, 36, 39 are Input Only. They do NOT have internal pull-up or pull-down resistors. Use external resistors if necessary.
Power & Logic Levels
- 3.3V Logic: All I/O pins are 3.3V logic. DO NOT connect 5V sensors/signals directly. Use logic level shifters.
- Power Consumption: LED Matrices (MAX7219) draw significant current. If the display glitches or the ESP reboots when WiFi connects, it is likely a brownout.
- Solution: Ensure the 5V rail for the matrix is adequately decoupled and the ESP has a stable 3.3V source. Software mitigation: limit max brightness or stagger initialization.
2. Coding Standards (Non-Blocking & Stability)
Non-Blocking Logic
- Strictly forbid
delay(): In the mainloop(), especially when WiFi or MQTT is active,delay()will cause network timeouts and WDT resets. - Use
millis(): Implement state machines and timers usingmillis()(e.g.,if (millis() - lastTime > interval) { ... }). - Yielding: For long-running loops (like complex message parsing), use
yield()orvTaskDelay(1)to allow the background tasks (WiFi, TCP/IP stack) to run.
Interrupt Handling (ISRs)
IRAM_ATTR: (ESP8266/ESP32) All ISR functions MUST be marked withIRAM_ATTR(e.g.,void IRAM_ATTR onTimer()). This keeps the code in RAM, preventing crashes if an interrupt occurs while writing to Flash.- Volatile Variables: Variables shared between an ISR and the main loop must be declared
volatile. - Minimal Logic: Keep ISRs extremely short (set a boolean flag, increment a counter). NEVER use
Serial.print(),delay(), or complex operations inside an ISR.
FreeRTOS & Multitasking (ESP32 Specific)
- Core Pinning:
- Core 0: Reserved for WiFi and System tasks.
- Core 1: Best for Application logic (Arduino
loop()runs here by default).
- Stack Sizing: When creating tasks (
xTaskCreate), estimate stack usage carefully. Start with 2048 or 4096 bytes and monitoruxTaskGetStackHighWaterMarkif unsure. - Priorities: Ensure your tasks do not starve the Idle task (priority 0) or the Timer task. Yielding (
vTaskDelay) is crucial.
3. Memory & Storage Management
Flash Memory Health
- Wear Leveling: Flash memory has limited write cycles (~10,000 to 100,000). NEVER write to LittleFS or EEPROM in a tight loop.
- Commit Strategy: Use a "dirty flag" pattern. Only save configuration if a value has actually changed.
- Struct Alignment: Accessing unaligned data can cause exceptions. When writing structs to Flash/LittleFS, ensure 4-byte alignment or use
__attribute__((packed))if necessary (though packed structs can be slower).
RAM Optimization
- ESP8266 Strings: Use
F()macro for static strings (e.g.,Serial.print(F("Booting..."))) to save RAM. - ESP32 PSRAM: If available, use
ps_mallocfor large buffers (display framebuffers, large JSON docs). - Fragmentation: Avoid frequent allocation/deallocation of
Stringobjects. Use staticchar[]buffers where possible.
4. WiFi & Network Handling
Robust Reconnection
WiFi.begin()can be blocking. Use non-blocking checks (WiFi.status()) or existingWiFiManagerpatterns.- Power vs Responsiveness:
WiFi.setSleep(false): Disables power saving. Increases power consumption (~80mA -> ~140mA) but drastically reduces latency for Web Server and ping times. Recommended for this message board if powered by mains.
Secrets Setup
- NEVER hardcode credentials. Use
config_manager(LittleFS) orsecrets.h(git-ignored).
5. Security & Input Validation
- Input Sanitization: Always validate data coming from external sources (MQTT, Web).
- MQTT: Check payload length before copying to buffers.
- Web: Sanitize strings to prevent buffer overflows or HTML injection if displayed back to the user.
- Buffer Safety: Use
snprintfinstead ofsprintf, andstrlcpyinstead ofstrcpy.
6. Debugging Procedures
- Exception Decoding:
- If the device crashes with a stack dump (
Backtrace: 0x400d1f...), use the Point Exception Decoder filter in PlatformIO or the standalone tool to map addresses to lines of code.
- If the device crashes with a stack dump (
- Reset Reasons: Log
ESP.getResetReason()at boot to understand if crashes are Watchdog, Brownout, or Exception based. - Debug Macro: Wrap all debug prints in
#if DEBUG ... #endif.
7. Project-Specific Integration
- Four-Tier Config: Respect
config.hhierarchy (Web -> MQTT -> Defaults -> General). Update all 4 layers (Struct, Load/Save, Web XML, Web Handler) when adding settings. - Display Buffer: Check animation status before pushing new messages unless urgent.