Skip to content

Build and Flash

Mae PUGIN edited this page Mar 21, 2026 · 1 revision

Build and Flash

Requirements

  • ESP-IDF v5.4+
  • CMake 3.16+
  • ESP32-S3 target

Build Commands

Single board build

source ~/esp/esp-idf/export.sh

# Build for a specific board
idf.py -DBOARD=kase_v2 build

# Default board (kase_v2_debug) if -DBOARD is omitted
idf.py build

Clean build (recommended when switching boards)

# Remove build directory and rebuild
rm -rf build
idf.py -DBOARD=kase_v1 build

Full clean (also removes managed_components)

idf.py fullclean
idf.py -DBOARD=kase_v1 build

Note: fullclean removes managed_components/. The next build will re-download them automatically.

How the Build System Works

Root CMakeLists.txt

if(NOT DEFINED BOARD)
    set(BOARD "kase_v2_debug" CACHE STRING "Target board")
endif()

set(BOARD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD}" CACHE INTERNAL "")

# Validate board exists
if(NOT EXISTS "${BOARD_DIR}/board.h")
    message(FATAL_ERROR "Board '${BOARD}' not found at ${BOARD_DIR}/board.h")
endif()

main/CMakeLists.txt

Board-specific files are included via ${BOARD_DIR}:

idf_component_register(
    SRCS
        "main.c"
        ...
        "${BOARD_DIR}/board_keymap.c"
        "${BOARD_DIR}/board_layout.c"
    INCLUDE_DIRS
        "."
        ...
        "${BOARD_DIR}"
    PRIV_REQUIRES
        esp_driver_gpio esp_timer bt esp_hid nvs_flash esp_lcd unity esp_driver_i2c
)

The INCLUDE_DIRS entry for ${BOARD_DIR} makes #include "board.h" resolve to the correct board's header.

Flash

Via USB-OTG

idf.py -p /dev/ttyACM0 flash

Via UART programmer

idf.py -p /dev/ttyUSB0 flash

Manual esptool

python -m esptool --chip esp32s3 -p /dev/ttyUSB0 -b 460800 \
  --before default_reset --after hard_reset \
  write_flash --flash_mode dio --flash_size 16MB --flash_freq 80m \
  0x0     build/bootloader/bootloader.bin \
  0x8000  build/partition_table/partition-table.bin \
  0x10000 build/KeSp.bin \
  0x210000 build/storage.bin

Flash only the application (faster iteration)

python -m esptool --chip esp32s3 -p /dev/ttyUSB0 -b 460800 \
  --before default_reset --after hard_reset \
  write_flash --flash_mode dio --flash_size 16MB --flash_freq 80m \
  0x10000 build/KeSp.bin

DFU mode

If the keyboard is already running KeSp firmware, send the DFU command via CDC serial to reboot into DFU mode, then flash.

Monitor

idf.py -p /dev/ttyUSB0 monitor

Press Ctrl+] to exit.

Release Build

The scripts/build_release.sh script builds all board variants:

./scripts/build_release.sh v3.4

This produces:

release/
├── KaSe_v3.4_V1.bin
├── KaSe_v3.4_V2.bin
└── KaSe_v3.4_V2_Debug.bin

Manual multi-board build

for board in kase_v1 kase_v2 kase_v2_debug; do
    rm -rf build
    idf.py -DBOARD=$board build
    cp build/KeSp.bin "KeSp_${board}.bin"
done

Tests

Unit tests use the Unity framework:

cd test/build
cmake ..
make
./test_runner

Tests validate board configuration (GPIO uniqueness, macro values, USB IDs, etc.).

Partition Table

The default partition layout includes:

Partition Offset Size Type
bootloader 0x0 32K bootloader
partition-table 0x8000 4K data
app 0x10000 2M app
storage 0x210000 varies LittleFS
nvs varies 16K NVS

The storage partition is populated from flash_data/ at build time via littlefs_create_partition_image().

Troubleshooting

"Board not found" error

Verify boards/<name>/board.h exists. The BOARD name is case-sensitive.

Wrong display / GPIOs after switching boards

Run rm -rf build before building for a different board. CMake caches the BOARD variable.

Flash fails with "No serial data received"

  • Check the USB cable supports data (not charge-only)
  • Hold BOOT button while pressing RESET to enter bootloader
  • Try a different USB port

NVS errors on first boot

Normal on first flash — NVS is empty. Default keymaps from board_keymap.c are used.