Skip to content

Conversation

@3djc
Copy link
Collaborator

@3djc 3djc commented Jan 11, 2026

This complement #6814 where it was still possible to get locked out.

This basicaly optimise FAT compatibility and allows a firmware to be flashed. It does have a shortcoming to limit flash size to 8Mb when radio have 16Mb, but it requires a fair amount of work to move our current implementation to proper FAT16, so this is a temporary measure.

  • use correct number of blocks for FAT16 according to the FAT specification
  • recalculate max firmware size to fit within corrected FAT16 limit
  • make the build fail if FLASH_SIZE is somehow greater than UF2_MAX_FW_SIZE

For all H7 supporting branches

@3djc 3djc requested a review from raphaelcoeffic January 11, 2026 10:56
@3djc 3djc added this to the 2.12.0 milestone Jan 11, 2026
@pfeerick pfeerick modified the milestones: 2.12.0, 2.11.5 Jan 14, 2026
raphaelcoeffic
raphaelcoeffic previously approved these changes Jan 14, 2026
Copy link
Member

@raphaelcoeffic raphaelcoeffic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@pfeerick
Copy link
Member

Just re: UF2_MAX_FAT16_BLOCKS, it is interesting to note that that elm-chan states:

A volume with count of clusters ≧4086 and ≦65525 is FAT16.

whereas the white paper from Microsoft on FAT states:

Now we can determine the FAT type. Please note carefully or you will commit an off-by-one error!

In the following example, when it says <, it does not mean <=. Note also that the numbers are correct. The first number for FAT12 is 4085; the second number for FAT16 is 65525. These numbers and the ‘<’ signs are not wrong.

If(CountofClusters < 4085) {
/* Volume is FAT12 */
} else if(CountofClusters < 65525) {
    /* Volume is FAT16 */
} else {
    /* Volume is FAT32 */
}

and also

There is no such thing as a FAT16 volume that has less than 4085 clusters or more than 65,524 clusters.

So it seems elm-chan has made an off by one error in the documentation?

That would explain while this is still true some 26 years later 😆

NOTE: As is noted numerous times earlier, the world is full of FAT code that is wrong. There is a lot of FAT type code that is off by 1 or 2 or 8 or 10 or 16. For this reason, it is highly recommended that if you are formatting a FAT volume which has maximum compatibility with all existing FAT code, then you should you avoid making volumes of any type that have close to 4,085 or 65,525 clusters. Stay at least 16 clusters on each side away from these cut-over cluster counts.

@pfeerick
Copy link
Member

Also, UF2_MAX_FAT16_BLOCKS is the size of the drive, not the file system... it is created inside that.

fdisk -l
Disk /dev/sdd: 31.99 MiB, 33548800 bytes, 65525 sectors
Disk model: T15 PRO Radio
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

file -s /dev/sdd
/dev/sdd: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "MSWIN4.1", root entries 64, Media descriptor 0xf8, sectors/FAT 256, sectors/track 1, heads 1, sectors 65523 (volumes > 32 MB), reserved 0x1, serial number 0, label: "EDGETX_UF2 ", FAT (16 bit)

CountofClusters = 65,523 - 1 (reserved) - (2 × 256) (FAT tables) - 4 (root dir)
CountofClusters = 65,523 - 1 - 512 - 4 = 65,006 sectors

If we increase to

#define UF2_MAX_FAT16_BLOCKS 66027

we get

Disk /dev/sdd: 32.24 MiB, 33805824 bytes, 66027 sectors
Disk model: T15 PRO Radio
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

file -s /dev/sdd
/dev/sdd: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "MSWIN4.1", root entries 64, Media descriptor 0xf8, sectors/FAT 258, sectors/track 1, heads 1, sectors 66025 (volumes > 32 MB), reserved 0x1, serial number 0, label: "EDGETX_UF2 ", FAT (16 bit)

CountofClusters = 66,025 - 1 - (2 × 258) - 4
CountofClusters = 66,025 - 1 - 516 - 4 = 65,504 sectors

That puts us ~21 down from the maximum 65,525/65,524, more than the minimum 16 recommended. What do you think?

@raphaelcoeffic
Copy link
Member

@pfeerick I modified the code to use the number of data sectors to compute the maximum UF2 firmware. That seems more correct. Regarding the volume size, I re-instated the old value (2^16 -1). I'd prefer not going over 16 bits.

@pfeerick
Copy link
Member

Makes perfect sense, 250kb in this context is not worth the overhead / potential alignment issues, etc. Will try it out again and merge if everything's working properly still ;)

@pfeerick pfeerick added bug 🪲 Something isn't working house keeping 🧹 Cleanup of code and house keeping labels Jan 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 🪲 Something isn't working house keeping 🧹 Cleanup of code and house keeping

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants