Skip to content

zephyr-cp: fix flash scratch page bugs; use 4 KB NOR flash layout pages; fix RP2 layout - #11613

Merged
tannewt merged 7 commits into
adafruit:mainfrom
dhalbert:zephyr-cp-qspi-4k-page
Oct 16, 2026
Merged

tannewt merged 7 commits into
adafruit:mainfrom
dhalbert:zephyr-cp-qspi-4k-page

Conversation

@dhalbert

@dhalbert dhalbert commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

PR note by @dhalbert.
Code and tests by Claude, at the direction of @dhalbert.

  • The zephyr port was using 64 KB flash layout pages, as opposed to the 4 KB used in the non-zephyr ports. This made the CIRCUITPY partitions different sizes on some boards, non-zephyr vs zephyr. Fixed; now they are the same size. 4 KB is faster for small writes, and also allows a bigger CIRCUITPY.
  • Claude found a bug where scratch page blocks were rewritten without an erase beforehand. This caused filesystem corruption when the RAM cache couldn't be allocated, which was likely with the 64 KB cache size. Fixed by changes to ports/zephyr-cp/supervisor/flash.c. This was not a problem in the non-zephyr supervisor/shared/external_flash/external_flash.c.
  • The scratch page could run past the end of the partition, or could overlap the last data page. Fixed. Ideally this would be checked at compile time, and some compile-time checks were added. But it is not possible to detect completely at compile time, so flash.c now uses the last whole page as the scratch page, and leaves any partial page unused.
  • On RP2, CIRCUITPY was 4 KB smaller on zephyr than on ports/raspberrypi, because zephyr reserved a flash scratch page and ports/raspberrypi doesn't (it only uses a RAM cache). Added a new Kconfig setting, CIRCUITPY_FLASH_SCRATCH_PAGE, which is on by default and off for RP2.

This does not break existing filesystems, and they will get larger when reformatted.

Extensive testing was done on live boards and native_sim. The native_sim tests were augmented to check for the problems mentioned here.

dhalbert and others added 6 commits October 15, 2026 12:37
When the RAM cache can't be allocated, flash.c stages writes in the
scratch page. A block written there twice, or written after a flush
filled the whole scratch page, was programmed over flash that had not
been erased. FAT and directory sectors are rewritten often, so the
filesystem was corrupted.

Start a fresh scratch page when a block is written again, and unload the
page after flushing it, as supervisor/shared/external_flash does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Zephyr's default nRF QSPI layout page is the 64 KB erase block. flash.c
reserves one page as its scratch page and caches one page in RAM while
writing, so the filesystem lost 64 KB and the RAM cache needed 64 KB.

Use the 4 KB sector instead. The filesystem now has 4088 blocks, like
ports/nordic, so a filesystem formatted there fits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fill the heap so flash.c can't allocate its RAM cache, then repeatedly
append to and flush files so the same directory and FAT blocks are
written again while their page is staged in the scratch page. The flash
simulator rejects writes to flash that isn't erased, so this fails
without the scratch page fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
flash.c used the page holding the partition's last block as its scratch
page, but it addresses pages relative to the start of the partition.
When the partition doesn't start and end on page boundaries, that
scratch page either runs past the end of the partition, so erasing it
fails (native_sim with 64 KB erase blocks), or overlaps the last data
page, which a scratch-page flush then corrupts (the nRF54LM20 DK: a
0x62b000-byte partition at 0x1d5000, with 64 KB SPI NOR layout pages).

Use the last whole page instead, and leave the partial page unused.
Update the test littlefs geometry to match, and add a native_sim test
with a partial last page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Like the nRF QSPI driver, the SPI NOR and MSPI NOR drivers default to
64 KB layout pages. The nRF54LM20 DK's filesystem partition (0x62b000
bytes at 0x1d5000) isn't 64 KB-aligned, so part of it was unusable, and
the RAM cache needed 64 KB. Default both to their 4 KB sectors. Boards
that set the size themselves (the nRF54L15 DK, nRF54H20 DK) keep it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d time

flash.c addresses erase pages relative to the start of the filesystem
partition. For the NOR flash drivers, whose layout page size is a Kconfig
setting, fail the build if the partition doesn't start and end on a
layout page boundary. This would have caught the nRF54LM20 DK's partition
with 64 KB SPI NOR layout pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dhalbert
dhalbert requested review from tannewt and a balanced review from Copilot October 15, 2026 18:19

This comment was marked as low quality.

@dhalbert

dhalbert commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator Author

I did not mean to ask for a Copilot review. That was a mouse slip. But I'll look at it anyway. EDIT: both critiques were specious.

ports/raspberrypi caches one 4 KB flash sector in a static buffer and
reserves no scratch page, so its filesystem was one page larger than
zephyr-cp's on the same board, and a filesystem it formatted didn't fit.

Add CIRCUITPY_FLASH_SCRATCH_PAGE, off by default on RP2040 and RP2350.
With it off, flash.c allocates the RAM cache once at startup and keeps
it, and the filesystem gets every whole page of the partition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dhalbert dhalbert changed the title zephyr-cp: fix flash scratch page bugs; use 4 KB NOR flash layout pages zephyr-cp: fix flash scratch page bugs; use 4 KB NOR flash layout pages; fix RP2 layout Oct 15, 2026
@dhalbert
dhalbert requested a review from mikeysklar October 16, 2026 15:19

@tannewt tannewt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you!

@tannewt
tannewt merged commit 66ddb7c into adafruit:main Oct 16, 2026
47 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants