Skip to content

Flash or recover over UART

Goal: Flash the firmware over UART, or recover a board that no longer boots.

You need: Start here done and a firmware build for your board.

Run every command from the project root (~/CrossPad, Windows C:\CrossPad\firmware), with ESP-IDF loaded as in 2. Build the firmware and the crosspad-hil venv from 1. Set up the toolchain active (one-line installer: crosspad-hil already works). Used the one-line installer? Use crosspad-idf in place of idf.py.

A UART flash writes everything (bootloader, partition table, firmware, assets) and resets the boot selection, so it also works when the board cannot start its USB connection. Steps 2 and 3 are for a v2 board (PCB r20), steps 4 and 5 for a v1 board (PCB r16 / r19).

  1. Identify the ports

    The STM32 bridge port (0483:5740) is the console and the UART flash port on a v2 board; a v1 board is flashed on the ESP USB port in ROM bootloader mode (step 5). List the ports with their USB IDs and note the one you need.

    Terminal window
    python3 -m serial.tools.list_ports -v

    You should see: one entry per port, each with a hwid: line. On a v2 board one of them reads USB VID:PID=0483:5740 …; that port is the STM32 bridge port. The ESP USB port (303A:3456) shows only while the board is in USB serial mode.

    <port>
    desc: …
    hwid: USB VID:PID=0483:5740 SER=… LOCATION=…
    …
    … ports found

    If not: The STM32 bridge port is not listed

  2. Flash a v2 board (PCB r20) through the STM32 bridge port

    esptool resets the ESP through the bridge by itself, so no bootloader request is needed; if it cannot sync, hold BOOT while resetting. Use the build of the board’s revision.

    Terminal window
    idf.py -B build_v2 -DSDKCONFIG=sdkconfig.v2 -p <port> -b 460800 flash

    Do not add monitor here: -b would open it at the flash speed instead of 115200 baud.

    You should see: esptool connects, then writes five images (bootloader, partition table, OTA data, CrossPad.bin, assets.bin), each ending with Hash of data verified.; idf.py ends with Done.

    Connecting....
    …
    Hash of data verified.
    …
    Done

    If not: esptool cannot connect over UART. If the port is held by another program: Serial port is busy.

  3. Recover a boot-looping v2 board

    This re-flashes everything over the STM32 bridge port, then checks that the board answers again. crosspad-hil finds the port; without it the script falls back to /dev/ttyACM0, so on macOS and Windows add --port <port>.

    Terminal window
    python3 tools/bench.py recover --build build_v2

    You should see:

    recovering over <port> from build_v2 (sdkconfig sdkconfig.v2)
    Connecting....
    …
    Hash of data verified.
    …

    If not: Board boot-loops after a flash. If it says UART flash failed: esptool cannot connect over UART. If it says idf.py not on PATH: idf.py command not found.

  4. Put a v1 board (PCB r16 / r19) into the bootloader

    On a v1 board, ask the ESP to enter its ROM bootloader first. The script asks over the ESP USB port in USB serial mode, then over MIDI, and waits for the ESP USB port to come back in ROM bootloader mode.

    Terminal window
    python3 tools/requestBootloader.py --method cdc,midi

    You should see:

    === MIDI SYSEX/USB CDC Bootloader Request ===
    …
    ✓ Bootloader request sent successfully!
    …
    ✓ Device entered bootloader mode on: <port>

    If the board was already in its bootloader, it prints ✓ Device is already in Espressif bootloader mode! and the port. Note the port for step 5.

    If not: A v1 board does not enter its bootloader

  5. Flash the v1 board on the ESP USB port

    Use the port the previous step printed and keep --after watchdog_reset, or the chip stays in ROM. The command runs in the v1 build folder, because the file names are relative to it, and cd .. returns to the project folder.

    Terminal window
    cd build_v1
    python3 -m esptool --chip esp32s3 -p <port> -b 460800 --before default_reset --after watchdog_reset write_flash --flash_mode dio --flash_size 16MB --flash_freq 80m 0x0 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 ota_data_initial.bin 0x20000 CrossPad.bin 0x720000 assets.bin
    cd ..

    You should see: Connecting..., then Hash of data verified. once for each of the five files. The board then restarts into the new firmware.

    If not: esptool cannot connect over UART

On a v2 board, open the console on the STM32 bridge port (115200 baud, Ctrl+] to exit) and wait for the success line:

Terminal window
idf.py -B build_v2 -DSDKCONFIG=sdkconfig.v2 -p <port> monitor

You should see: I (…) crosspad_main: All systems operational - Crosspad ready

If not: No boot log on the console