Initial
This commit is contained in:
commit
b9752da8ac
4 changed files with 118 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
tmp
|
||||
*.sw?
|
||||
37
README.md
Normal file
37
README.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# USB Flashing Format (UF2)
|
||||
|
||||
UF2 (USB Flashing Format) is a name of a file format, that is particularly
|
||||
suitable for flashing devices over MSC (Mass Storage Class most commonly used
|
||||
by various pendrives) The file consists of 512 byte blocks, each of which is
|
||||
self-contained and independent of others.
|
||||
|
||||
Each 512 byte block consist of (see `uf2.h` for details):
|
||||
* magic numbers at the beginning and at the end
|
||||
* address where the data should be flashed
|
||||
* size of data
|
||||
* data (up to 476 bytes; for SAMD it's 256 bytes so it's easy to flash in one go)
|
||||
|
||||
Thus, it's really easy for the microcontroller to recognize a block of
|
||||
a UF2 file is written and immediately write it to flash.
|
||||
|
||||
In `uf2conv.c` you can find a small converter from `.bin` to `.uf2`.
|
||||
|
||||
## Board identification
|
||||
|
||||
There is also `BOARD_ID`, which is meant to be machine-readable and specific
|
||||
to a given version of board hardware. The programming environment might use
|
||||
this to suggest packages to be imported (i.e., a package for a particular
|
||||
external flash chip, SD card etc.).
|
||||
|
||||
These configuration values can be read from `INFO_UF2.TXT` file.
|
||||
Presence of this file can be tested to see if the board supports `UF2` flashing,
|
||||
while contest, particularly `Board-ID` field, can be used for feature detection.
|
||||
|
||||
The current flash contents of the board is exposed as `CURRENT.UF2` file.
|
||||
This file includes the bootloader address space. The last word of bootloader
|
||||
space points to the string holding the `INFO_UF2.TXT` file, so it can be parsed
|
||||
by a programming environment to determine which board does the `.UF2` file comes from.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
34
uf2.h
Normal file
34
uf2.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef UF2FORMAT_H
|
||||
#define UF2FORMAT_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// All entries are little endian.
|
||||
|
||||
#define UF2_MAGIC_START0 0x0A324655UL // "UF2\n"
|
||||
#define UF2_MAGIC_START1 0x9E5D5157UL // Randomly selected
|
||||
#define UF2_MAGIC_END 0x0AB16F30UL // Ditto
|
||||
|
||||
// If set, the block is "comment" and should not be flashed to the device
|
||||
#define UF2_FLAG_NOFLASH 0x00000001
|
||||
|
||||
typedef struct {
|
||||
// 32 byte header
|
||||
uint32_t magicStart0;
|
||||
uint32_t magicStart1;
|
||||
uint32_t flags;
|
||||
uint32_t targetAddr;
|
||||
uint32_t payloadSize;
|
||||
uint32_t blockNo;
|
||||
uint32_t numBlocks;
|
||||
uint32_t reserved;
|
||||
|
||||
// raw data;
|
||||
uint8_t data[476];
|
||||
|
||||
// store magic also at the end to limit damage from partial block reads
|
||||
uint32_t magicEnd;
|
||||
} UF2_Block;
|
||||
|
||||
#endif
|
||||
45
utils/uf2conv.c
Normal file
45
utils/uf2conv.c
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "uf2format.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "USAGE: %s file.bin [file.uf2]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
FILE *f = fopen(argv[1], "rb");
|
||||
if (!f) {
|
||||
fprintf(stderr, "No such file: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fseek(f, 0L, SEEK_END);
|
||||
uint32_t sz = ftell(f);
|
||||
fseek(f, 0L, SEEK_SET);
|
||||
|
||||
const char *outname = argc > 2 ? argv[2] : "flash.uf2";
|
||||
|
||||
FILE *fout = fopen(outname, "wb");
|
||||
|
||||
UF2_Block bl;
|
||||
memset(&bl, 0, sizeof(bl));
|
||||
|
||||
bl.magicStart0 = UF2_MAGIC_START0;
|
||||
bl.magicStart1 = UF2_MAGIC_START1;
|
||||
bl.magicEnd = UF2_MAGIC_END;
|
||||
bl.targetAddr = APP_START_ADDRESS;
|
||||
bl.numBlocks = (sz + 255) / 256;
|
||||
bl.payloadSize = 256;
|
||||
int numbl = 0;
|
||||
while (fread(bl.data, 1, bl.payloadSize, f)) {
|
||||
bl.blockNo = numbl++;
|
||||
fwrite(&bl, 1, sizeof(bl), fout);
|
||||
bl.targetAddr += bl.payloadSize;
|
||||
// clear for next iteration, in case we get a short read
|
||||
memset(bl.data, 0, sizeof(bl.data));
|
||||
}
|
||||
fclose(fout);
|
||||
fclose(f);
|
||||
printf("Wrote %d blocks to %s\n", numbl, outname);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue