- Notifications
You must be signed in to change notification settings - Fork172
UF2 file format specification
License
microsoft/uf2
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
UF2 is a file format, developed by Microsoft forPXT(also known asMicrosoft MakeCode), that is particularly suitable forflashing microcontrollers over MSC (Mass Storage Class; aka removable flash drive).
For a more friendly explanation, check outthis blog post.Also, take a look at the list ofimplementations at the bottom of this document.
The UF2 file consists of 512 byte blocks, each of which is self-contained and independent of others.Each 512 byte block consists of (see below for details):
- magic numbers at the beginning and at the end
- address where the data should be flashed
- up to 476 bytes of data
The data transfers over MSC always arrive in multiples of 512 bytes.Together with the FAT file system structure, this means that blocks of theUF2 file are always aligned with the MSC writes - the microcontrollernever gets a partial file.
The magic numbers let the microcontroller distinguish an UF2 file block fromother data (eg., FAT table entry, or various book-keeping files stored by someoperating systems). When a UF2 block is recognized, it can be flashedimmediately (unless flash page size is more than 256 bytes; in that case a bufferis needed). The actual handling of file format during writing is very simple(~10 lines of C code in simplest version).
A UF2 file consists of 512 byte blocks. Each block starts with a 32 byteheader, followed by data, and a final magic number.All fields, except for data, are 32 bit unsigned little endian integers.
Offset | Size | Value |
---|---|---|
0 | 4 | First magic number,0x0A324655 ("UF2\n" ) |
4 | 4 | Second magic number,0x9E5D5157 |
8 | 4 | Flags |
12 | 4 | Address in flash where the data should be written |
16 | 4 | Number of bytes used in data (often 256) |
20 | 4 | Sequential block number; starts at 0 |
24 | 4 | Total number of blocks in file |
28 | 4 | File size or board family ID or zero |
32 | 476 | Data, padded with zeros |
508 | 4 | Final magic number,0x0AB16F30 |
The following C struct can be used:
structUF2_Block {// 32 byte headeruint32_tmagicStart0;uint32_tmagicStart1;uint32_tflags;uint32_ttargetAddr;uint32_tpayloadSize;uint32_tblockNo;uint32_tnumBlocks;uint32_tfileSize;// or familyID;uint8_tdata[476];uint32_tmagicEnd;}UF2_Block;
Currently, there are five flags defined:
0x00000001
-not main flash - this block should be skipped when writing thedevice flash; it can be used to store "comments" in the file, typicallyembedded source code or debug info that does not fit on the device flash0x00001000
-file container - see below0x00002000
-familyID present - when set, thefileSize/familyID
holds a valueidentifying the board family (usually corresponds to an MCU)0x00004000
-MD5 checksum present - see below0x00008000
-extension tags present - see below
This field is optional, and should be set only when the correspondingflag is set. It is recommended that new bootloaders require the field tobe set appropriately, and refuse to flash UF2 files without it.If you're developing your own bootloader, and yourboard family isn't listed here, pick a new family ID at random. It's goodto also send a PR here, so your family can be listed.
If thefamilyID
doesn't match, the bootloader should disregard theentire block, includingblockNo
andnumBlocks
fields.In particular, writing a full UF2 file with non-matchingfamilyID
should not reset the board.This also allows for several files with differentfamilyID
to besimply concatenated together, and the whole resulting file to be copiedto the device with only one actually being written to flash.
The reason to pick numbers at random is to minimize risk of collisionsin the wild. Do not pick random numbers by banging on keyboard, or by using0xdeadf00d
,0x42424242
etc. A good way is to use the followingshell command:printf "0x%04x%04x\n" $RANDOM $RANDOM
Another good way is the link at the bottom ofhttps://microsoft.github.io/uf2/patcher/This procedure was unfortunately not used for the SAMD51 and NRF52840 below.
The current master list of family IDs is maintained in aJSON file.
The magic number at the end is meant to mitigate partial block writes.
Second and final magic numbers were randomly selected, except for the last byteof final magic number, which was forced to be'\n'
(0xA
). Together with thefirst magic number being"UF2\n"
this makes it easy to identify UF2 blocks ina text editor.
The header is padded to 32 bytes, as hex editors commonly use 16 or 32 bytesas line length. This way, the data payload is aligned to line start.
32 bit integers are used for all fields so that large flash sizes can besupported in future, as well as for simplicity. Little endian is used, as mostmicrocontrollers are little endian. 8 bit microcontrollers can choose to justuse the first 16 bits of various header fields.
The total number of blocks in the file and the sequential block number make iteasy for the bootloader to detect that all blocks have been transferred. Itrequires one bit of memory per block (eg., on SAMD21G18A it's 128 bytes).Alternatively, the bootloader might ignore that and just implement a resetafter say 1 second break in incoming UF2 blocks.
The number of data bytes is configurable and depends on the size ofthe flash page (that is the smallest size that can be erased) on themicrocontroller.
- if the page size is more than
476
bytes, the bootloader should supportany payload size, as it needs to buffer the entire page in memory anyway - if the page size is less than
476
bytes, the payload should be a multipleof page size, so it can be written without buffering; the target addressshould also be a multiple of page size
In any event, payload size and target address should always be 4-byte aligned.
Note that payload size of256
is always correct, and makes it easy to convertbetween flash addresses and UF2 file offsets.
For example, on Atmel's SAMD21 chips the page size is256
bytes, and thisalso is the payload size. If the page size was128
bytes, one could usepayload of128*3
. Nordic nRF51 has page size of1024
bytes, and thusany payload size should be allowed.
Some IDEs will embed program sources in the UF2 file. This allows a UF2 files to beloaded by the IDE and serve as a natural backup and transfer format.This can be done in two ways:
- using the "not main flash" flag
- using normal blocks that are flashed to the device
If the bootloader can exposeCURRENT.UF2
file (see below) and there is enoughflash available, than the second option is more desirable, as it allows sharingprograms directly from the board.
Seehttps://makecode.com/source-embedding for more info.
The file format is designed specifically to deal with the following problems:
- operating system (OS) writing blocks in different order than occurs in a file
- OS writing blocks multiple times
- OS writing data that is not UF2 blocks
- OS writing first/final part of a block, possibly for metadata detection or search indexing
The only file system assumption we make is that blocks of file are aligned withblocks on the hard drive. It's likely true of many file systems besides FAT.
We also assume that USB MSC device reports its block size to be a multiple of512
bytes. In the wild these devices always almost report exactly512
, and someoperating systems do not support other values.
Bootloaders may expose virtual files in their MSC devices. These arestandardized here, so that flashing tools can automatically detect thebootloaders.
INFO_UF2.TXT
- contains information about the bootloader build and the board on which it is runningINDEX.HTM
- redirects to a page that contains an IDE or other informationCURRENT.UF2
- the contents of the entire flash of the device, starting at0x00000000
, with256
payload size;thus, the size of this file will report as twice the size of flash
Flashing tools can use the presence ofINFO_UF2.TXT
(in upper or lower case,as FAT is case-insensitive) file as an indication that a given directory isactually a connected UF2 board. The other files should not be used fordetection.
TypicalINFO_UF2.TXT
file looks like this:
UF2 Bootloader v1.1.3 SFAModel: Arduino ZeroBoard-ID: SAMD21G18A-Zero-v0
TheBoard-ID
field is machine-readable and consists of a number of dash-separated tokens.The first token is the CPU type, second is the board type, and third is the board revision.More tokens can be also added.
The bootloader should contain its info file as a static string somewhere in its code.If possible, the last word of the bootloader code should point to this string.This way, the info file can be found in the initial section of theCURRENT.UF2
file as well. Thus, a board type can be determined from the contents ofCURRENT.UF2
.This is particularly useful with the source embedding (see above).
It is also possible to use the UF2 format as a container for one or moreregular files (akin to a TAR file, or ZIP archive without compression). Thisis useful when the embedded device being flashed sports a file system.
The program to run may reside in one of the files, or in the main flash memory.
In such a usage thefile container
flag is set on blocks, the fieldfileSize
holds the file size of the current file, and the fieldtargetAddr
holds theoffset in current file.
Thenot main flash
flag on blocks should be ignored when thefile container
is set.
The file name is stored at&data[payloadSize]
(ie., right after the actual payload) andterminated with a0x00
byte. The format of filename is dependent on thebootloader (usually implemented as some sort of file system daemon).
The bootloader will usually allow any size of the payload.
The current files on device might be exposed as multiple UF2 files, instead ofa singleCURRENT.UF2
. They may reside in directories, however, due to UF2 generaldesign, it doesn't matter which directory the UF2 file is written to.
Typical writing procedure is as follows:
- validate UF2 magic numbers
- make sure that
targetAddr < fileSize
and thatfileSize
isn't out of reasonable range - write
0x00
atdata[475]
to ensure NUL termination of file name - read file name from
&data[payloadSize]
; perform any mapping on the file name - create a directory where the file is to be written if it doesn't exist
- open the file for writing
- truncate the file to
fileSize
- seek
targetAddr
- write the payload (ie.,
data[0 ... payloadSize - 1]
) - close the file
The fieldsblockNo
andnumBlocks
refer to the entire UF2 file, not the currentfile.
When the0x4000
flag is set, the last 24 bytes ofdata[]
hold the following structure:
Offset | Size | Value |
---|---|---|
0 | 4 | Start address of region |
4 | 4 | Length of region in bytes |
8 | 16 | MD5 checksum in binary format |
The flashing program should compute the MD5 sum of the specified region.If the region checksum matches, flashing of the current block can be skipped.Typically, many blocks in sequence will have the same region specified,and can all be skipped, if the matching succeeded.The position of the current block will typically be inside of the region.The position and size of the region should be multiple of page erase size(4k or 64k on typical SPI flash).
This is currently only used on ESP32, which is also why MD5 checksum is used.
When the0x8000
flag is set, additional information can be appended right afterpayload data (i.e., it starts at32 + payloadSize
).Every tag starts at 4 byte boundary.The first byte of tag contains its total size in bytes (including the size byteand type designation).The next three bytes designate the type of tag (if you want to define customtags, pick them at random).The last tag has size of0
and type of0
.
Standard tag designations follow:
0x9fc7bc
- version of firmware file - UTF8 semver string0x650d9d
- description of device for which the firmware file is destined (UTF8)0x0be9f7
- page size of target device (32 bit unsigned number)0xb46db0
- SHA-2 checksum of firmware (can be of various size)0xc8a729
- device type identifier - a refinement offamilyID
meant to identify a kind of device(eg., a toaster with specific pinout and heating unit), not only MCU; 32 or 64 bit number; can be hash of0x650d9d
For example, the following bytes encode firmware version0.1.2
for devicenamedACME Toaster mk3
(line breaks added for clarity):
09 bc c7 9f 30 2e 31 2e 32 00 00 0014 9d 0d 65 41 43 4d 45 20 54 6f 61 73 74 65 72 20 6d 6b 3300 00 00 00
Extension tags can, but don't have to, be repeated in all blocks.
- Microchip ATSAMD21 and ATSAMD51
- Arduino UNO
- STM32F103
- STM32F4
- Nordic NRF52840
- Linux (RPi Zero)
- Cypress FX2
- Tiny UF2 - Support ESP32-S2, iMXRT10xx, STM32F4
- RP2040 chip - native support in silicon
- UF2-ChibiOS - Supports STM32H7
There's an ongoing effort to implement UF2 inCodal.
- https://arcade.makecode.com
- https://makecode.adafruit.com
- https://makecode.seeedstudio.com
- https://maker.makecode.com
MIT
This project has adopted theMicrosoft Open Source Code of Conduct. For more information see theCode of Conduct FAQ or contactopencode@microsoft.com with any additional questions or comments.