Update firmware over USB (OTA)
Goal: Go beyond the first OTA flash: release images, delta updates, the assets partition, a flash with automatic verification and the way back to the previous firmware.
You need: Start here done, the board running and on USB.
Run every command from the project root (~/CrossPad, Windows C:\CrossPad\firmware) with ESP-IDF loaded as in 2. Build the firmware. Used the one-line installer? Use crosspad-idf in place of idf.py.
The board stays in charge of every update. It runs the new image on trial first and confirms it after 10 seconds; a reset before that boots the previous image again.
-
Flash a release image
A release image is a firmware file from a CrossPad release, named
CrossPad-<tag>-<rev>-<kit>.bin. Pass--boardwith the image’s revision: the script needs it when crosspad-hil cannot report the board’s own, and it is always safe.Terminal window python3 tools/ota_flash.py path/to/CrossPad-<tag>-v2-<kit>.bin --board v2Terminal window python tools\ota_flash.py path\to\CrossPad-<tag>-v2-<kit>.bin --board v2Answer the board’s prompts as in 3. Flash the board, steps 2 to 4: Allow (USB serial mode) within 10 s, then Update within 60 s, then leave it alone for 10 s. The delta (step 2) and the verified flash (step 4) ask the same.
You should see:
Auto-detected CrossPad on <port>Board: dev_… v2 -> image v2: path/to/CrossPad-<tag>-v2-<kit>.binFirmware: path/to/CrossPad-<tag>-v2-<kit>.bin (… bytes, … MB)Connecting to <port>...Sending: OTA_BEGIN <size> <version>Waiting for user confirmation on device...Device ready. Sending firmware...OTA complete! (…s, … KB/s)Device restarting...Running slot: trialdo not reset the board for ~10 s, the image is on trial — a reset before it confirms rolls it back to the other slotWith Auto-accept updates ticked, the
Waiting for user confirmationline does not appear. Without crosspad-hil, theBoard:line readsboard revision unknownin place ofdev_… v2.If not: OTA flash cannot find the board. If it says
… is a v1 board and the image is v2: OTA refuses an image for the other revision. If it stops atexpected OTA_READY: OTA times out waiting for confirmation. -
Send a delta update
A delta update sends only the difference from the image on the board, so
--base-fwmust be that exact image. Copybuild_v2/CrossPad.binaside after each flash to use as the next base.Terminal window python3 tools/ota_flash.py --delta --base-fw <bin on device>Terminal window python tools\ota_flash.py --delta --base-fw <bin on device>You should see:
Auto-detected CrossPad on <port>Board: dev_… v2 -> image v2: …/build_v2/CrossPad.binGenerating delta patch...Base: <bin on device> (… bytes)New: …/build_v2/CrossPad.bin (… bytes)Patch: … (… bytes, …% of full firmware)Patch size: … bytes (… KB)Connecting to <port>...Sending: OTA_DELTA <size> <version>Waiting for user confirmation on device...Device ready. Sending delta patch...OTA complete! (…s, … KB/s)Device restarting...Running slot: trialThe first delta run may print
Installing detools...right beforeGenerating delta patch.... To send a patch you already have, pass--patch <file>in place of--base-fw; theGenerating delta patchlines are then skipped. With Auto-accept updates ticked, theWaiting for user confirmationline does not appear.If not: Delta update fails. If it says the revision of the board is unknown: OTA flash says the revision of the board is unknown. If it stops at
expected OTA_READY: OTA times out waiting for confirmation. -
Update the assets partition
App icons, the bundled STM32 image and the on-board docs live in the assets partition, which you send separately. The board does not ask for Update here; it restarts once the image is written.
Terminal window python3 tools/fs_transfer.py assetsTerminal window python tools\fs_transfer.py assetsYou should see:
Auto-detected CrossPad on <port>Board v2 (device dev_…, PCB …, firmware v2) -> build_v2/assets.binAssets image: build_v2/assets.bin (… bytes, crc …)Device ready. Streaming (nothing is erased until the CRC matches)...…Assets written and verified. The device is restarting.If not: OTA flash cannot find the board. If it says
Error: no assets.bin for this board, build first: OTA says the image is not built. -
Flash and verify in one go
With the crosspad-hil venv from 1. Set up the toolchain active (one-line installer:
crosspad-hilalready works),tools/bench.py flashdoes the OTA, waits for the trial confirm, compares the image hash and runs the smoke test. Use it to prove the board runs your latest build.Terminal window python3 tools/bench.py flash --assetsTerminal window python tools\bench.py flash --assetsYou should see:
flashing build_v2/CrossPad.bin…OTA complete! (…s, … KB/s)…on the board: LIBVER: …trial: the running slot was already confirmedimage: matches build_v2/CrossPad.elf (…)flashing assets from build_v2/assets.bin (OTA does not touch this partition)…Assets written and verified. The device is restarting./assets holds … entriesPASS: HIL SMOKE: PASSOn a slow boot the trial line reads
trial: confirmed after … sinstead.If not:
bench not ready — nothing was flashedmeans crosspad-hil is missing or sees no board: crosspad-hil install fails.image: MISMATCHmeans the board went back to the old image: Board rolls back to the old firmware. A failed smoke run: Smoke test prints MISSING MARKER, FATAL or BOOT LOOP. -
Go back to the previous firmware
The board keeps the firmware it ran before in its second slot, and the CP Tools doctor shows it.
Terminal window python3 tools/app_manager.py doctorTerminal window python tools\app_manager.py doctorYou should see:
[ ? ] Previous firmware the board still has the one before in its second slot (<version>)-> [Enter] switch back to it — seconds, no buildTo switch, open CP Tools (the same command without
doctor), press 3 (Something’s wrong), pick Previous firmware and press Enter, then confirm. From the crosspad-hil venv you can send the same request directly:Terminal window crosspad-hil cdc FW_SLOTScrosspad-hil cdc FW_SWITCHYou should see: two
FWSLOT: slot=… running=… state=… pkg=… ver=… kit=…rows andFWSLOT: rollback=1, thenOK reboot=1. The board restarts into the other slot. Wait until a fresh flash has confirmed itself (10 s) before you switch: a slot still on trial cannot be left this way.
Check it worked
Section titled “Check it worked”The script ends with OTA complete! and Running slot: trial. After 10 s, open the console on the STM32 bridge port (0483:5740) and look for the success line. Opening the port restarts the board, so wait the full 10 s first.
idf.py -B build_v2 -DSDKCONFIG=sdkconfig.v2 -p <port> monitoridf.py -B build_v2 "-DSDKCONFIG=sdkconfig.v2" -p COMx monitorYou should see: I (…) crosspad_main: All systems operational - Crosspad ready. Press Ctrl+] to leave the monitor.
If not: No boot log on the console