Skip to content

zephyr-cp: size nvm and storage to a whole erase block on RP2040/RP2350 - #11272

Open
lynt-smitka wants to merge 2 commits into
adafruit:mainfrom
MakerClassCZ:zephyr-cp-nvm-erase-block
Open

zephyr-cp: size nvm and storage to a whole erase block on RP2040/RP2350#11272
lynt-smitka wants to merge 2 commits into
adafruit:mainfrom
MakerClassCZ:zephyr-cp-nvm-erase-block

Conversation

@lynt-smitka

Copy link
Copy Markdown

nvm_partition and storage_partition are 0x800 on all five RP2040/RP2350 boards, but the erase block on those chips is 4096.

common_hal_nvm_bytearray_set_bytes reads a whole erase page before modifying it, and takes that page size from the flash device rather than the partition, so it asks flash_area_read for 4096 bytes out of a 2048-byte area. flash_area_read bounds-checks and returns -EINVAL.

Measured on a picopad running zephyr-cp:

    >>> len(microcontroller.nvm)
    2048
    >>> microcontroller.nvm[0:4] = b"ABCD"
    RuntimeError: Unable to write to nvm.

The same test on the raspberrypi port, where nvm is a full 4096, writes and reads back fine.

Both partitions grow to one erase block, which shifts circuitpy_partition 4 KB up. The filesystem moves with it, so a board updating to this comes up with an empty CIRCUITPY drive...

@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.

Did you check these ranges against the addresses used in ports/raspberrypi? Let's make sure nvm and circuitpy have the same region. storage_partition may need to use some firmware space.

@lynt-smitka

Copy link
Copy Markdown
Author

Good point. No, I hadn't checked those against ports/raspberrypi... Will do, and try to rework the overlays so nvm and circuitpy match the classic layout.

@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.

Did you test switching between the two?

Both partitions are 0x800 on the five RP2040 and RP2350 boards, but the
erase block on those chips is 4096. common_hal_nvm_bytearray_set_bytes
takes its page size from the flash device, so it asks flash_area_read for
4096 bytes out of a 2048-byte area; flash_area_read bounds-checks that and
returns -EINVAL, and the write fails. Were it to get past that, the
following flash_area_erase of a full page would take storage_partition
with it.

Measured on a picopad running zephyr-cp: len(microcontroller.nvm) is 2048
and nvm[0:4] = b"ABCD" raises RuntimeError: Unable to write to nvm. The
same code on the raspberrypi port, where nvm is a full 4096, writes and
reads back fine.

Both partitions grow to one erase block, which shifts circuitpy_partition
4 KB up. The filesystem moves with it, so a board updating to this comes up
with an empty CIRCUITPY drive and whatever was on it is gone.
After the previous commit the partitions sat at 0x180000 (nvm), 0x181000
(storage) and 0x182000 (circuitpy) on all five boards, which matches neither
port. ports/raspberrypi derives both from CIRCUITPY_FIRMWARE_SIZE: nvm sits at
that address, the drive 4 KB above it. Three of the boards take the 1020K
default, so nvm at 0xff000 and CIRCUITPY at 0x100000; pico_w and pico2_w set
1536K, so 0x180000 and 0x181000.

Use those addresses, and take storage out of the code partition rather than
pushing circuitpy up, so a board keeps both its filesystem and its nvm contents
across a switch between the two ports. That leaves the W boards' nvm and
circuitpy where they already were; the three non-W boards move circuitpy down
from 0x181000, which grows their drive by 516 KB (rpi_pico: 508 KB -> 1 MB) and
costs one empty CIRCUITPY on update.

The code partitions are just under 1016 KB and 1532 KB, against images of
490 KB (rpi_pico) and 1042 KB (rpi_pico_w).

Verified on an RP2040 with 2 MB flash, both layouts and both directions,
against the 10.3.0 raspberry_pi_pico and raspberry_pi_pico_w release images:
CIRCUITPY keeps its files and nvm keeps its contents across every switch.
@lynt-smitka
lynt-smitka force-pushed the zephyr-cp-nvm-erase-block branch from 42c0119 to fdb56f9 Compare September 2, 2026 18:12
@lynt-smitka

Copy link
Copy Markdown
Author

Yes, they didn't match at first (thanks!), but line up now:

code ends storage nvm circuitpy
rpi_pico, rpi_pico2, feather_rp2040 0xfe000 0xfe000 0xff000 0x100000
rpi_pico_w, rpi_pico2_w 0x17f000 0x17f000 0x180000 0x181000

Tested the switch on an RP2040, both directions, against the 10.3.0 raspberry_pi_pico and raspberry_pi_pico_w release images: CIRCUITPY keeps its files and nvm keeps its contents each way, and the nvm write that used to fail works.

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.

2 participants