Files
MicrOBU/obu-firmware/FLASHING.md
T
Ashin Walpola 0e9525162d Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
2026-09-23 17:46:40 +02:00

7.0 KiB

obu-firmware — setup & flashing notes

Two toolchains - use a dedicated terminal for each

Since 2026-09-23 this project builds against ESP-IDF 6.0.2 exactly (C:\Espressif\frameworks\esp-idf-v6.0.2): it is the vanetza-idf port (see NOTES.md), and vanetza-idf's radio_c5.cmake refuses any other version because the raw TX path pokes private Wi-Fi driver structures only validated there. The previous C firmware used the receiver firmware's IDF 6.1; the separate obu-cam-transmistter project builds against the global ESP-IDF 5.5.4. Exporting two of them in one PowerShell window fails: the second export inherits the first's IDF_PYTHON_ENV_PATH and reports every Python dependency as unmet. Don't run install.bat to "fix" that - open a fresh terminal, or clear the state with $env:IDF_PYTHON_ENV_PATH = $null; $env:IDF_PATH = $null.

The build also needs the colleague's microbu-esp32c5 tree, which this repository carries as ordinary files in microbu-esp32c5/: vanetza-idf is taken from its external/vanetza-idf. Pass -DVANETZA_IDF_DIR=<path> to idf.py if it lives elsewhere. The first build downloads espressif/esp-boost into managed_components/.

microbu-esp32c5/ is a copy, not a submodule: nothing is fetched from or pushed to the colleague's repository (HAW GitLab, urban-mobility-lab/microbu/ microbu-esp32c5). It was taken at their commit cf4b99f plus our V2X2MAP signature verification (local commit 428a386; that repository's history is kept outside this one in ..\microbu-esp32c5-colleague.git). To take a newer version of their tree, copy it over this folder, rebuild and test, and commit it here.

Every new PowerShell session

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
$env:IDF_TOOLS_PATH = "C:\Espressif"
C:\Espressif\frameworks\esp-idf-v6.0.2\export.ps1
idf.py --version    # v6.0.2

Going back to the previous firmware

firmware-backups/ in the repository root (gitignored) holds a full-flash image of the COM3 board as it was before the port, with the esptool command to write it back in its README.txt.

Build & flash

cd C:\Users\Ashin\AndroidStudioProjects\MicrOBU\obu-firmware
idf.py set-target esp32c5      # only needed once per clean build folder
idf.py build
idf.py -p COM5 -b 921600 flash monitor

Swap COM5 for whatever port the ESP32-C5 enumerates as (Device Manager → Ports). monitor opens the serial console after flashing — Ctrl+] to exit.

If the build fails

  • "includes X.h, provided by Y component(s)... not in the requirements list" — IDF 5.x split the old monolithic driver component apart (esp_driver_gpio, esp_driver_uart, etc.). Add the named component to REQUIRES in main/CMakeLists.txt and rebuild. Already fixed once for esp_driver_gpio + esp_driver_uart — if a new header comes up, same fix.
  • Otherwise, start clean before re-building:
    idf.py fullclean
    idf.py build
    

Connecting the phone (ESP32-C5-WIFI6-KIT)

The board has two USB-C ports — use the right one:

  • Native USB-C port (labeled for JTAG/native USB, up to 12 Mbps) — this is where the phone plugs in via USB-OTG. The CAM serial link (serial_link.c) runs over the ESP32-C5's native USB Serial/JTAG peripheral on this port, enumerating as a CDC-ACM device under Espressif's VID/PID (0x303A/0x1001).
  • UART-bridge port (labeled for flashing) — this is what you use for idf.py flash monitor from your PC. Leave the phone unplugged from this one; it only carries idf.py's flashing protocol and the ESP_LOG console.

The app recognizes the ESP32-C5's VID/PID via a custom probe table in UsbSerialTransport.kt (the default usb-serial-for-android prober doesn't know Espressif's device IDs). If the phone doesn't detect anything when plugged into the native port, first confirm with a tool like "USB Device Info" (or adb shell dumpsys usb from a PC) that Android sees a USB device at all — that isolates a bad/charge-only OTG cable from an app-side issue.

Work down this list — each step isolates the layer below it.

  1. Flash and install together. SERIAL_LINK_MAX_PAYLOAD is 512 on both sides. A phone at 512 talking to firmware still at 160 (or vice versa) silently rejects every large frame at the length exceeds max, resync branch. Never update one side alone.
  2. Does Android see the device at all? Plug the phone into the native USB-C port, hit Connect, and read logcat for UsbSerialTransport. It logs every attached device and each device's interfaces. Empty list = cable / OTG / wrong port, below the app entirely.
  3. Did the right interface get claimed? The C5's USB Serial/JTAG is a composite device — expect CDC control (class 2) + CDC data (class 10) + vendor-specific JTAG (class 255) in that dump. Compare against the ports= count on the matched device line.
  4. Is the link alive? The firmware sends a STATUS heartbeat at 1 Hz regardless of radio traffic, and the app marks the link ERROR after ~3.5 s of silence. Connected-and-staying-connected means device→host actually works.
  5. If it connects but no CAM_RX ever arrives — suspect DTR. The app now asserts DTR/RTS on open (openDevice() in UsbSerialTransport.kt), because CdcAcmSerialDriver doesn't do it by default and the ESP32's USB Serial/JTAG endpoint may gate TX on the host opening the CDC line. This is still unverified on real hardware — test it both ways (with the setDTR(true) call and with it commented out) and record the answer in serial_link.h next to the VID/PID note, so nobody has to guess again.
  6. Watch the counters, not just "Sent: N". The CAM Pinger card shows consecutive write failures (phone side) and the firmware's tx-failure / oversize-drop / CRC-error totals from the heartbeat. A rising tx fail means CAMs reach the ESP32 but esp_wifi_80211_tx rejects them — a radio problem, not a link problem.

Connecting over Bluetooth instead

Settings > Connection > ESP32-C5 > link: Bluetooth, then Connect. The board advertises as micrOBU-XXXX (last two bytes of its BT MAC; micrOBU-4AFA on COM3), but only while nothing uses its native USB port. Android asks to pair the first time: passkey 123456 (fixed in simple_ble.cpp). The bond is kept on both sides; the board keeps one bond, so pairing a second phone or a PC replaces the first. Log lines on the console start with cits_ble:.

Notes

  • No git submodule update needed here — obu-firmware has no pinned submodule of its own, unlike its-g5-receiver-firmware.
  • Don't use the global "ESP-IDF 5.5 PowerShell" shortcut or the receiver firmware's 6.1 checkout — export from esp-idf-v6.0.2, the version the vanetza-idf radio's undocumented driver internals were verified against.
  • The console (ESP_LOG, boot messages, panics) stays on the UART-bridge port. Opening it resets the board; do that only while nothing else depends on the session.