ESP-IDF
The firmware targets plain ESP-IDF: no ESP-ADF, no external components and no component manager entries. Building it requires only a standard ESP-IDF installation.
Why not ESP-ADF
The project initially used ESP-ADF, Espressif’s audio framework. ESP-ADF requires an $ADF_PATH environment variable, a board definition selected in Kconfig (CONFIG_ESP32_S3_KORVO2_V3_BOARD for this hardware), and the audio_pipeline, i2s_stream, raw_stream, board and iot_button components. Each is an environment dependency that has to be reproduced on every machine that builds the project.
Removing ESP-ADF moved two responsibilities into the project: the ES8388 driver, implemented as direct I2C register writes, and the I2S setup, which uses the native driver/i2s_std.h API. The result is a single main.c of 486 lines with no dependencies beyond ESP-IDF itself.
What it uses from ESP-IDF
Six headers, all part of a default installation. ESP-IDF 5.1 or newer is required; the project was developed on 5.5.1. The I2S channel API used here was introduced in 5.x and is not source-compatible with 4.x.
#include <stdio.h> #include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/i2c.h" #include "driver/i2s_std.h" #include "driver/gpio.h" #include "esp_log.h" #include "esp_heap_caps.h"
- driver/i2c.h — the legacy master API, one command link per register write, to configure the codec.
- driver/i2s_std.h — the 5.x channel API. TX and RX are two handles on a single port; see the recording page for the clocking consequence.
- driver/gpio.h — buttons as inputs with internal pull-ups, LED as an output.
- esp_heap_caps.h — allocating audio buffers in PSRAM specifically, with MALLOC_CAP_SPIRAM.
- freertos/FreeRTOS.h and task.h — used only for vTaskDelay. No additional tasks are created.
- esp_log.h — the serial log, the project’s only runtime diagnostic output.
Project layout
play_tone/ ← projeto ESP-IDF
├── CMakeLists.txt
├── sdkconfig.defaults ← alvo, flash e PSRAM
└── main/
├── CMakeLists.txt
└── main.c ← o firmware inteiro, 486 linhasBuild configuration
The PSRAM entries are required: without CONFIG_SPIRAM, the heap_caps_malloc call in do_record() returns NULL and no audio is recorded. The N16R8 module uses octal PSRAM, so CONFIG_SPIRAM_MODE_OCT must be set; quad mode does not detect it.
CONFIG_IDF_TARGET="esp32s3" CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y # PSRAM (8MB Octal no N16R8) CONFIG_SPIRAM=y CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_SPEED_80M=y
The build files are the ESP-IDF defaults, with no components registered beyond main:
cmake_minimum_required(VERSION 3.16)
# Projeto puro ESP-IDF - NÃO precisa de ESP-ADF
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(play_tone)idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")Compiling and flashing
Run from play_tone/, with ESP-IDF exported into the shell. The serial port name varies by system; on macOS the board enumerates as a /dev/tty.usbmodem device.
idf.py set-target esp32s3 idf.py build idf.py -p /dev/tty.usbmodem313301 flash monitor
On ESP32-S3 over USB-Serial/JTAG, the automatic reset via RTS is not always effective. If the log shows rst:0x15 (USB_UART_CHIP_RESET), boot:0x21 (DOWNLOAD) followed by "waiting for download", press RESET on the board without holding BOOT; the monitor reconnects.