TCHAIN_PREFIX = arm-none-eabi-

export CODE_SOURCERY = NO to skip -fpromote-loop-indicies

Command line programming

There’s an experimental command line programmer in ground/openpilotgcs/src/experimental/USB_UPLOAD_TOOL. Use to build it.

Custom code

The link command is

arm-none-eabi-gcc ... $defines $includes $objs
  --output foo.elf -nostartfiles -Wl,,--cref,--gc-sections
  -lc -lm -lgcc

The firmware image has a 100 byte header generated by:

python $openpilot/make/scripts/
  --type=0x04 --revision=0x02

According to the linker script:

  • BL_FLASH is 0x08000000 to +0x2f7f
  • BD_INFO is 0x08002f80 to +0x80
  • FLASH is 0x08003000 onwards to (128 - 12) k
  • SRAM is 0x20000000 to +20 k

Vectors are at the start of user flash (…3000), live in .isr_vectors, and are from startup_stm32f10x_MD_CC.S.

Bootloader checks the blob at pios_board_info_blob (0x08002f80):

struct pios_board_info {
  uint32_t magic;
  uint8_t  board_type;
  uint8_t  board_rev;
  uint8_t  bl_rev;
  uint8_t  hw_type;
  uint32_t fw_base;
  uint32_t fw_size;
  uint32_t desc_base;
  uint32_t desc_size;
  uint32_t ee_base;
  uint32_t ee_size;
} __attribute__((packed));

for bdinfo->fw_base & 0x2FFE0000 == 0x20000000. Sets SP to fw_base[0] and jumps to *fw_base[1]. Ah, so checks that the SP is valid.

What does the image look like? The command line flasher just takes a binary file and programs it to 0x08003000.


The status LED is on PA6. Crystal is 8 MHz. Blink it!.

Schematic is at


  • USART connectors are GND / PWR / TX / RX
  • CONN2 is USART1 on PA9 & PA10 with an invert select on PB2
  • CONN3 (Flexi) is USART3 on PB10 & PB11