Summary
The extflash_program() function in every board's extflash_driver.cpp does not account for a non-page-aligned starting address on the first write. The loop always uses min(len, QSPI_NOR_PAGE_SIZE) as the write size, but if address % QSPI_NOR_PAGE_SIZE != 0, the first program command can cross a NOR page boundary, which causes the hardware to silently wrap and overwrite data at the start of the same page rather than continuing into the next page.
Affected files
The same logic (and therefore the same gap) is present in all of these:
radio/src/boards/helloradio-h750/extflash_driver.cpp
radio/src/boards/jumper-h750/extflash_driver.cpp
radio/src/boards/rm-h750/extflash_driver.cpp
radio/src/targets/c14/extflash_driver.cpp
radio/src/targets/st16/extflash_driver.cpp
Current code (identical in all affected files)
static int extflash_program(uint32_t address, void* data, uint32_t len)
{
address -= QSPI_BASE;
int ret = 0;
while (len > 0) {
uint32_t size = (len > QSPI_NOR_PAGE_SIZE) ? QSPI_NOR_PAGE_SIZE : len;
ret = stm32_qspi_nor_program(address, data, size);
if (ret != 0) break;
len -= size;
address += size;
data = (uint8_t*)data + size;
}
return ret;
}
Proposed fix
Limit the first write to the remaining bytes in the current NOR page:
static int extflash_program(uint32_t address, void* data, uint32_t len)
{
address -= QSPI_BASE;
int ret = 0;
uint32_t page_offset = address % QSPI_NOR_PAGE_SIZE;
while (len > 0) {
uint32_t size = (len > QSPI_NOR_PAGE_SIZE - page_offset) ? QSPI_NOR_PAGE_SIZE - page_offset : len;
ret = stm32_qspi_nor_program(address, data, size);
if (ret != 0) break;
len -= size;
address += size;
data = (uint8_t*)data + size;
page_offset = 0; // subsequent iterations are always page-aligned
}
return ret;
}
Alternatively, the fix could be applied once in stm32_qspi_nor_program() / stm32_xspi_nor_program() so all callers benefit automatically.
Impact / Severity
In practice the normal firmware update path erases 64 KB sectors and writes sequentially from a sector start, so all addresses are currently page-aligned (256-byte boundary) and the bug is latent rather than active. However, any future caller that passes a non-page-aligned address would encounter silent data corruption.
Notes
stm32_qspi_nor_program() and stm32_xspi_nor_program() (the lower-level HAL wrappers) also do not perform any alignment correction — the fix needs to live either here or in each board's extflash_program().
- This issue is not specific to any one board; fixing it in only one place would create inconsistency. A coordinated fix across all affected files (or in the shared lower-level driver) is recommended.
Summary
The
extflash_program()function in every board'sextflash_driver.cppdoes not account for a non-page-aligned starting address on the first write. The loop always usesmin(len, QSPI_NOR_PAGE_SIZE)as the write size, but ifaddress % QSPI_NOR_PAGE_SIZE != 0, the first program command can cross a NOR page boundary, which causes the hardware to silently wrap and overwrite data at the start of the same page rather than continuing into the next page.Affected files
The same logic (and therefore the same gap) is present in all of these:
radio/src/boards/helloradio-h750/extflash_driver.cppradio/src/boards/jumper-h750/extflash_driver.cppradio/src/boards/rm-h750/extflash_driver.cppradio/src/targets/c14/extflash_driver.cppradio/src/targets/st16/extflash_driver.cppCurrent code (identical in all affected files)
Proposed fix
Limit the first write to the remaining bytes in the current NOR page:
Alternatively, the fix could be applied once in
stm32_qspi_nor_program()/stm32_xspi_nor_program()so all callers benefit automatically.Impact / Severity
In practice the normal firmware update path erases 64 KB sectors and writes sequentially from a sector start, so all addresses are currently page-aligned (256-byte boundary) and the bug is latent rather than active. However, any future caller that passes a non-page-aligned address would encounter silent data corruption.
Notes
stm32_qspi_nor_program()andstm32_xspi_nor_program()(the lower-level HAL wrappers) also do not perform any alignment correction — the fix needs to live either here or in each board'sextflash_program().