Skip to content

PlatformIO Setup

OpenSkyhawk firmware builds with PlatformIO. Each board is its own project. Start from the templates in Firmware/Templates/ — not from an existing panel's platformio.ini, which may carry stale dependencies.

Start from a template

Firmware/Templates/ has a ready project per tier: PanelGroup/, PanelBridge/, and SimGateway/. Copy the one you need into place (a PanelGroup goes under Firmware/Panels/<YourPanel>/) and edit its platformio.ini.

A PanelGroup platformio.ini, annotated

[env:PanelGroup]
platform = ststm32@^20.0.0        ; major held on purpose — see note below
board = genericSTM32F103C8        ; STM32F103C8 for nodes (see board note below)
framework = arduino
board_build.f_cpu = 72000000L

build_flags =
    -DNODE_ID=1                   ; unique per board, 1–63 — set this!
    -DHAL_CAN_MODULE_ENABLED      ; enable the bxCAN peripheral
    -DUSB_NONE                    ; inert — USB is off because USBCON is never defined
    -DHSE_VALUE=8000000           ; external 8 MHz crystal, required for CAN timing

lib_extra_dirs = ${PROJECT_DIR}/../../Libraries
lib_ldf_mode = deep+              ; needed so Adafruit BusIO finds framework headers
lib_deps =
    HIDControls
    STM32Board
    PanelGroup
    CANProtocol
    A4EC
    blemasle/MCP23017@^2.0.0
    adafruit/Adafruit ADS1X15@^2.0.0

upload_protocol = stlink
monitor_speed = 115200

The two build flags people forget: -DNODE_ID (every board needs a unique value — see NODE_ID & CAN Addressing) and -DHSE_VALUE=8000000 (declares the 8 MHz crystal frequency to HAL — needed for correct CAN timing, since the internal RC oscillator isn't accurate enough for 500 kbps CAN). Note -DHSE_VALUE does not by itself select HSE; STM32Board's SystemClock_Config does that (see Design Decisions).

-DUSB_NONE is a label, not a switch — nothing in STM32duino or PlatformIO reads it. USB really is off, and CAN really does own PA11/PA12 (they're the F103's USB D+/D− pins), but what keeps USB off is that USBCON is never defined. Leave the flag in place as documentation of the decision.

For every flag in this file — plus the ones that aren't, their defaults, and where each is read — see Build Flags.

Keep the version constraint

The @^20.0.0 is deliberate — don't drop it back to a bare platform = ststm32. An unconstrained platform resolves to whatever is newest at build time, so an upstream release lands in your build with no change on our side. That is exactly how the weekly firmware build went red for two weeks: ststm32 20.0.0 arrived with STM32 Arduino core 3.0.0, which renamed the HardwareSerial class (see below), and every STM32 project stopped compiling.

The caret accepts 20.x — new boards and Cube HAL patches still flow in — but blocks the next major, which is where a break of that kind comes from. Crossing a major is a deliberate change: do it in a PR, with a full build behind it.

Declaring your own UART: use Uart, not HardwareSerial

Core 3.0.0 adopted ArduinoCore-API. The concrete STM32 serial class is now Uart, and the name HardwareSerial refers to the abstract arduino::HardwareSerial base — you cannot instantiate it. A second UART is declared Uart Diag(PA10, PA9);. Most sketches never need this: STM32Board::diagSerial() already hands you USART1 on the DiagSerial header. On the RP2040 side (SimGateway) the arduino-pico core is unaffected — HardwareSerial is still the concrete class there.

Which STM32 variant

Per the variant policy, all STM32 boards default to genericSTM32F103C8 (64 KB) — both PanelGroup nodes and PanelBridge. PanelBridge carries the full DCS-BIOS input map yet still compiles to ~26 KB flash, so it fits the C8 comfortably. genericSTM32F103CB (128 KB) is a drop-in fallback (identical LQFP48 footprint) for any future build that ever exceeds 64 KB — no board currently needs it. Note: the in-tree Templates/PanelGroup should target genericSTM32F103C8.

Flashing

STM32 boards flash over SWD with an ST-Link (upload_protocol = stlink). PlatformIO drives the probe directly — pio run -t upload. SimGateway (RP2040) flashes over USB by UF2 or straight from PlatformIO; no ST-Link.

If an upload fails — old ST-Link firmware, or a clone's non-standard tap ID — see Flashing → ST-Link troubleshooting.

Serial monitor

monitor_speed = 115200 matches the DiagSerial debug stream (USART1, PA9/PA10). Attach a USB-to-TTL adapter to the board's 3-pin debug header and pio device monitor. See Debugging on STM32.