Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 7742

General • Re: Pico minimal 2nd stage boot loader

$
0
0
Finally C code to make a UF2 to bind the two sections above into one UF2 file to load to PICO

You compile the code on your OS to make an executable I call mine UF2AppMaker.exe because I use windows.
Code only uses stand C libraries so should work on anything.

The code needs 3 arguments when run (1) the bootloader binary (2) The app binary (3) name of UF2 file to produce
So an example for me it looks like
UF2AppMaker boot.bin app.bin final.uf2

The code takes the loader binary runs the CRC and writes the loader and CRC to UF2 1st section
Then it places the app in each successive UF2 section for however big it is.

That means when the UF2 is loaded into the PICO your bootloader is at 0x10000000 and your APP is at 0x10000100 to whatever size

Code:

#include <stdio.h>#include <string.h>#include <stdint.h>#define APP_START_ADDRESS 0x10000000#define UF2_MAGIC_START0 0x0A324655UL // "UF2\n"#define UF2_MAGIC_START1 0x9E5D5157UL // Randomly selected#define UF2_MAGIC_END 0x0AB16F30UL    // Ditto#define UF2_FLAG_FAMILY_ID      0x00002000  // familyID present#define UF2_PICO_FAMILY_ID      0xE48BFF56  // Raspberry PICO family ID#pragma pack(1)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;#pragma pack()unsigned int crc32b(uint8_t* message, size_t l){    size_t i, j;    unsigned int crc, msb;    crc = 0xFFFFFFFF;    for (i = 0; i < l; i++) {        // xor next byte to upper bits of crc        crc ^= (((unsigned int)message[i]) << 24);        for (j = 0; j < 8; j++) {    // Do eight times.            msb = crc >> 31;            crc <<= 1;            crc ^= (0 - msb) & 0x04C11DB7;        }    }    return crc;}int main(int argc, char **argv) {    UF2_Block bl = { 0 };        FILE* f = fopen(argv[1], "rb");    if (!f) {        fprintf(stderr, "No such bootloader input file\n");        return 1;    }    fseek(f, 0L, SEEK_END);    int32_t tsz = ftell(f);    fseek(f, 0L, SEEK_SET);    if (tsz > 252) {        fprintf(stderr, "Boot loader can only be 252 bytes max\n");        return 1;    }    fread(&bl.data[0], 1, 256, f);    uint32_t crc = crc32b(&bl.data[0], 252);    bl.data[255] = ((crc & 0xFF000000) >> 24);    bl.data[254] = ((crc & 0x00FF0000) >> 16);    bl.data[253] = ((crc & 0x0000FF00) >> 8);    bl.data[252] = ((crc & 0x000000FF));    FILE* fa = fopen(argv[2], "rb");    if (!fa) {        fprintf(stderr, "No such app input file\n");        return 1;    }    fseek(fa, 0L, SEEK_END);    int32_t sz = ftell(fa);    fseek(fa, 0L, SEEK_SET);    FILE* fout = fopen(argv[3], "wb");    if (!fout) {        fprintf(stderr, "Output file create failed\n");        return 1;    }    bl.magicStart0 = UF2_MAGIC_START0;    bl.magicStart1 = UF2_MAGIC_START1;    bl.magicEnd = UF2_MAGIC_END;    bl.targetAddr = APP_START_ADDRESS;    bl.flags = UF2_FLAG_FAMILY_ID;    bl.reserved = UF2_PICO_FAMILY_ID;    bl.blockNo = 0;    bl.numBlocks = (tsz + sz + 255) / 256;    bl.payloadSize = 256;    fwrite(&bl, 1, sizeof(bl), fout);    while (sz > 0)    {        uint32_t rem = sz;        if (rem > 256) rem = 256;        memset(&bl.data[0], 256, 0);        bl.targetAddr = bl.targetAddr + 256;        bl.blockNo = bl.blockNo + 1;        fread(&bl.data[0], 1, rem, fa);        fwrite(&bl, 1, sizeof(bl), fout);        sz = sz - rem;    }    fclose(f);    fclose(fa);    fclose(fout);    return 0;}

Statistics: Posted by LdB — Thu Oct 16, 2025 11:59 pm



Viewing all articles
Browse latest Browse all 7742

Latest Images

Trending Articles



Latest Images