|
| 1 | +# Universal Examples |
| 2 | + |
| 3 | +These examples show ways to load the same code onto different chips, and package |
| 4 | +it in such a way that the bootrom only executes the code compatible with that chip. |
| 5 | + |
| 6 | +## Universal Binary vs Universal UF2 |
| 7 | + |
| 8 | +There is a difference between a **Universal Binary** and a **Universal UF2**, |
| 9 | +for the purposes of these examples: |
| 10 | +- A **Universal Binary** is a `.bin` file that can be loaded into flash (or sram) and executed, |
| 11 | +allowing RP2040 and RP2350 (Arm & RISC-V) to run from identical flash contents. |
| 12 | +- A **Universal UF2** is multiple individual `.uf2` files with different family IDs |
| 13 | +concatenated together to create a single `.uf2` file. When dragged & dropped onto a device, |
| 14 | +only the file with a family ID corresponding to that device will be loaded onto it, and the |
| 15 | +rest of the files will be ignored. |
| 16 | + |
| 17 | +A **Universal Binary** can be packaged into a UF2 file for loading onto a device. However, |
| 18 | +as there isn't a common family ID between RP2040 and RP2350, you would have to package it into a **Universal UF2** with two copies (using `rp2040` and `absolute` family IDs), thus creating a **Universal UF2** of a **Universal Binary**. |
| 19 | + |
| 20 | +## How Universal Binaries work |
| 21 | + |
| 22 | +Universal binaries must be recognised by both the RP2040 and RP2350 bootroms. Therefore, they need the following structure for flash binaries: |
| 23 | +- RP2040 boot2 |
| 24 | + - Required by the RP2040 bootrom |
| 25 | +- RP2040 binary containing an embedded block |
| 26 | + - The embedded block contains an `IGNORED` item due to RP2350-E13, but you can use an RP2040 |
| 27 | + `IMAGE_DEF` item instead if not using RP2350-A2 chips |
| 28 | +- RP2350 Arm binary containing an embedded block |
| 29 | + - In addition to the RP2350 `IMAGE_DEF` item, this embedded block contains a |
| 30 | + `ROLLING_WINDOW_DELTA` item to translate this binary to the start of flash for execution |
| 31 | +- RP2350 RISC-V binary containing an embedded block |
| 32 | + - Same as the Arm one |
| 33 | + |
| 34 | +All of the embedded blocks are linked into one big block loop. |
| 35 | + |
| 36 | +These are then booted by the respective bootroms: |
| 37 | +- **RP2040** - sees the boot2 at the start and uses that to execute the RP2040 binary, as |
| 38 | +RP2040 has no support for embedded blocks. |
| 39 | +- **RP2350** - sees the block loop and parses it to find the correct embedded block to boot |
| 40 | +from (Arm vs RISC-V). It then translates the flash address according to the |
| 41 | +`ROLLING_WINDOW_DELTA` so that the binary containing that embedded block is at the start of the |
| 42 | +flash address space, and executes from there. |
| 43 | + |
| 44 | +For no_flash binaries the RP2040 boot2 is omitted as the bootrom just executes from the start |
| 45 | +of SRAM, and instead of `ROLLING_WINDOW_DELTA` items the RP2350 binaries use `LOAD_MAP` items, |
| 46 | +to copy the code in SRAM to the correct location for execution rather than using address |
| 47 | +translation. |
| 48 | + |
| 49 | +## How you should use them |
| 50 | + |
| 51 | +For most use cases, **Universal UF2s** are the best option to use. They will only load into |
| 52 | +flash the code that runs on that device. The [blink_universal](blink_universal) example uses a |
| 53 | +Universal UF2 for that reason, as the Wi-Fi firmware is quite large. **Universal Binaries** |
| 54 | +are only currently useful when the commonality of having a single `.bin` file for programming |
| 55 | +outweighs the disadvantage of the extra flash usage. |
0 commit comments