Binary Bootloader-embedded Config (CF2)
The goal of CF2 is to run the same binary on a number of devices with different peripheral configuration, but the same MCU. Typically, this has been achieved by embedding identification components in hardware (eg. connecting certain MCU pins to GND or 3V) and having the firmware dynamically detect these. While simple, this only allows a few bits of configuration data to be stored on device.
Instead, we use the bootloader area for storing device specific configuration data. Such data is not altered when the device is programmed with new firmware, and the said firmware can refer to the configuration data in the bootloader area to alter its behavior.
For example, MakeCode Arcade requires a device with 7 buttons (directions, A, B, and MENU), a screen from a specific family, and one of the few supported accelerometers. The exact configuration depends on the manufacturer, but the binary produced by MakeCode will work on any device with the right MCU, provided it has the right configuration data in the bootloader area.
Thus, the user only needs to select the type of MCU (which is color coded, and is assigned a simple user-facing name), and the resulting binary will work on their device. Moreover, they can drag the UF2 file between devices, provided they run the same MCU. Once bootloaders are updated with networking support (wired or wireless), one device with a given MCU will be able to flash another.
Configuration data format
Data comes as pairs of 32 bit unsigned integers (in machine byte order).
- first pair is
- second pair consists of the number of configuration entries, and a zero (reserved)
- then configuration entries follow, where the first element is the configuration entry key number, and the second is the value (these entries are sorted by key number)
- finally, a number of zeroes follows (typically at least a few hundred), to store any additional configuration data in future
configkeys.h with definitions of key names can be downloaded from the
patcher website (see below).
If you require your own key names, please use random large key names.
At https://microsoft.github.io/uf2/patcher/ we provide a tool, which given a UF2 or BIN file and a configuration definition, binary-patches the UF2/BIN file and lets the user download it. The tool also parses existing configuration information from the UF2/BIN file to show it.
Such tool is to be used by makers of devices. For example, for MakeCode Arcade, this includes both factories and users who take an existing multi-purpose board and connect keys and screen. Such user would then download generic MakeCode Arcade bootloader (either a UF2 file, which upgrades the bootloader, or a .BIN file with the bootloader) for the given MCU, and binary patch it with their configuration. Then, they would update the bootloader, and have a Arcade-compatible device.
Configuration file syntax
# This is comment, which is ignored // this is also a comment # Configuration values for display registers and size DISPLAY_CFG0 = 0x80 DISPLAY_CFG1 = 0x603 DISPLAY_CFG2 = 0x16 DISPLAY_HEIGHT = 128 DISPLAY_WIDTH = 160 PINS_PORT_SIZE = PA_32 # see below # pin headers (if any) PIN_A0 = PA02 PIN_A1 = PA05 PIN_A2 = PB08 PIN_D2 = PA07 PIN_D3 = PB22 PIN_SCK = PA01 PIN_MISO = PB23 PIN_MOSI = PA00 # pin functions PIN_BTN_LEFT = PIN_D2 # use pin header name PIN_BTN_UP = PB13 # use pin directly PIN_DISPLAY_CS = 18 # can even just use a number for the pin PIN_DISPLAY_SCK = PIN_SCK PIN_DISPLAY_MOSI = PIN_MOSI # custom configuration keys _679732427 = 123 _815320287 = 0x80192 # remove an existing config entry PIN_BTN_MENU2 = null
The keys are either key names, or underscore followed by a decimal number.
The values are numbers in either decimal or hexadecimal,
references to other keys, or pin numbers.
The way pin numbers are parsed depends on the
PA_16- pins are
PB00-PB15, ..., used on STM32
PA_32- pins are
PA31, ... - used on Microchip ATSAMD
P0_16- pins are
P1_0-P1_15, ... - not used?
P0_32- pins are
P0_0-P0_31, ... - used on Nordic NRF
0or missing - pins are
Certain keys (like
PINS_PORT_SIZE) have a number of pre-defined values,
which can be used instead of integers.
Because you're usually use this syntax to patch an existing configuration,
you sometimes may want to remove an entry that's already there.
To do that, use
null as the value of the key.
For list of keys and predefined values, see
configkeys.h which can be downloaded
from the patcher website.
Running from node.js
The patcher tool can be also run from command line. Download patcher.js and run it with node. It will print out help.