Firmware Overview
The alarm clock firmware runs on ESP-IDF v5 with FreeRTOS. Each hardware subsystem runs in its own FreeRTOS task; a central event loop coordinates them via a state machine.
Why ESP-IDF (Not Arduino)
The Arduino framework is simpler to start with, but ESP-IDF is the better choice here because:
- Real RTOS tasks — audio streaming needs its own task pinned to core 1; Arduino's
loop()runs everything on one core with no preemption - Proper I2S DMA — the
i2s_std.hAPI in IDF v5 is stable and supports correct stereo/mono configuration - NVS (Non-Volatile Storage) — ESP-IDF's built-in NVS flash storage is the easiest way to persist alarm settings across power cycles
- Production-quality drivers — SPI, I2C, FATFS, WiFi, SNTP are all well-tested IDF components
The Dev Environment doc covers ESP-IDF v5 installation.
Task Architecture
Each task communicates through FreeRTOS queues:
| Queue | Direction | Contents |
|---|---|---|
button_event_queue | button_task → main | button_event_t (which button, press/long-press) |
display_cmd_queue | main → display_task | display_cmd_t (which screen to render) |
audio_cmd_queue | main → audio_task | audio_cmd_t (play file, stop, set volume) |
ntp_sync_event | ntp_task → main | EventBits_t (NTP synced flag) |
main_event_queue | power_monitor → main | EVT_POWER_LOSS / EVT_POWER_RESTORED |
State Machine
The main task runs a finite state machine that determines what is shown on the display and what audio (if any) is playing:
The full state machine implementation is in the main loop doc.
Firmware Sections in This Guide
- Dev Environment — install ESP-IDF, create project
- Project Structure — CMake component layout
- Drivers — one driver per hardware component
- Features — higher-level behaviour built on top of the drivers
- Main Loop — the state machine and event loop
Follow this order. Each driver is a self-contained component you can test independently before wiring into the main loop.