viniciusdias.tech

research

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.

play_tone/main/main.c
#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"

Project layout

play_tone/                  ← projeto ESP-IDF
├── CMakeLists.txt
├── sdkconfig.defaults      ← alvo, flash e PSRAM
└── main/
    ├── CMakeLists.txt
    └── main.c              ← o firmware inteiro, 486 linhas

Build 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.

play_tone/sdkconfig.defaults
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:

play_tone/CMakeLists.txt
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)
play_tone/main/CMakeLists.txt
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.