The bootloader¶
Every driver shipped with firmware 105 or newer carries a small bootloader in the first 12 KB of its flash. It starts the firmware on a normal boot, and it loads a new firmware over UART or CAN when a host asks, so a driver is updated without a programming adapter and without opening anything. The bootloader is open source: stm32f103c-bootloader, shared with the Spectral Micro.
Memory layout¶
| Address | Contents |
|---|---|
0x08000000 – 0x080022FF |
the bootloader (about 9 KB) |
0x08002C00 – 0x08002FFF |
the bootloader's configuration page: the board ID, the firmware's page count and CRC, the bootloader's build version |
0x08003000 – 0x0801FFFF |
the firmware (up to 116 KB) |
RAM 0x20001000 |
a magic word the bootloader sets to hand over to the firmware |
The firmware is linked to start at 0x08003000 and sets its vector table there (VECT_TAB_OFFSET=0x3000); the
first 0x3000 bytes belong to the bootloader and the firmware never touches them.
What happens at boot¶
- On a reset, the bootloader runs first. If the magic word is in RAM and the reset was a software reset, it checks the firmware's stack pointer and reset vector and jumps straight into the firmware: about 10 ms, the normal boot.
- Otherwise it initialises the clocks, CAN, UART and its watchdog, and listens for a host for 2 s. The LED flashes three times at the start, then blinks while the bootloader listens, faster while a host talks to it.
- With no host, and a firmware whose stored CRC is valid, it sets the magic word and resets; the next boot takes the fast path.
- With a host talking, it stays as long as the host keeps talking: 3 s after the last command, 60 s once a flash
is in progress. Any
PINGresets the timer. - With no valid firmware (never flashed, or a flash that was interrupted), it stays in bootloader mode and waits,
with the LED blinking; the driver answers nothing on
#Info.
Entering the bootloader¶
- From the firmware:
#Resetover UART or Send_Reset (command 14) over CAN. Since firmware 105 both reset the driver into the bootloader's 2 s window; the host tools send them for you. - At power-on: the 2 s window after every power-up, if the host is already polling.
- Always, when there is no valid firmware.
The board ID¶
The bootloader has a board ID of its own, 0 to 13, stored in its configuration page. 14 and 15 do not exist
for it: its command frame, identifier 0x700, decodes as node 14 in the firmware's identifier scheme, so those
two node IDs are reserved. Give drivers node IDs 0 to 13. The firmware accepts #CANID 14 and 15, but the
bootloader then keeps its old board ID and a firmware update over CAN cannot reach the driver. The firmware keeps
the board ID in step with its CAN node ID when the configuration is saved: #Save or Send_Save_config writes the
node ID into the bootloader's board ID, so a driver answers the host tools under its node ID. A node ID that is set
but not saved is not the board ID yet. A
replacement board ships as ID 0; two boards with the same ID on one bus corrupt each other's flash stream, so
give the new board its ID alone on the bus first (set-id in the host tool).
Transports and protocol¶
Over CAN (1 Mbit/s, standard 11-bit identifiers) the host commands on identifier 0x700 with 8 data bytes
(board_id, cmd, two parameters); the board replies on 0x701 + board_id with 5 bytes (board_id, cmd,
error code, a 16-bit parameter); the firmware image streams in bulk frames on (board_id << 7) | sequence,
16 frames of 8 bytes per chunk, with no reply per frame. Over UART (256000 baud) the same commands travel in
framed packets [0xBB][CMD][LEN][BOARD_ID][DATA…][CRC16] with the same 5-byte reply, but the first four have other
numbers.
Commands over CAN: WBUF (1), WPAGE (2), WCRC (3), PING (4), SET_ID (5), ERASE_APP (6),
STREAM_BEGIN (7), STREAM_STATUS (8). Over UART: PING (1), WBUF (2), WPAGE (3), WCRC (4), and the
others as over CAN, plus STREAM_DATA (9), which carries the stream frames. Error codes: 0 OK, 1 invalid offset, 2 invalid CRC, 3 flash write failed, 4 invalid
page number. A flash is: ping, reset the firmware if it answers, ping until the bootloader answers, ERASE_APP
(about 3.5 s), then for each 1 KB page STREAM_BEGIN, 8 chunks of 16 frames, STREAM_STATUS, WPAGE with the
page's CRC32; finally WCRC with the page count and the image's CRC32. The bootloader stores the CRC and
reboots into the new firmware. The full wire protocol is in the bootloader repository's docs/PROTOCOL.md.
The host side¶
| Tool | Transport | Use |
|---|---|---|
| Motor GUI | serial adapter (Web Serial) or CANvas | one driver on the bench, releases fetched from GitHub |
host_tools/bl_flash.py in the bootloader repository |
slcan or gs_usb CAN adapters, or UART | scripts, several boards, list, set-id, flash --erase-first |
the PAR6 control box's flash_motor_firmware.py and the dashboard's Firmware tab |
the robot's own CAN bus | every joint of a robot, from the box |
Updating through the bootloader has the commands.
Recovery¶
An interrupted flash leaves an invalid CRC; the bootloader refuses to start the firmware and waits, so the board is
not lost: flash again. A board that answers nothing at all: power-cycle it with the host already polling, to catch
the 2 s window. The one thing the tools refuse, and that would need a programming adapter to undo, is flashing an
image linked for 0x08000000 (a firmware from the main branch) over the firmware region.
Installing it¶
Boards that run release 103 or older from the main branch have no bootloader; some boards shipped before 105
have it although they report 103 (Drivers that report 103).
Installing the bootloader on an older board
puts it there once, with a programming adapter at 0x08000000; from then on the board updates like any other.
Comments
Found a mistake on this page? Edit it on GitHub · Report it · Get help · This page as Markdown · llms.txt · The whole manual as PDF