← index #18839Issue #8680
Related · high · value 2.854
QUERY · ISSUE

SEEED_XIAO_RP2350: Flash size configured as 4MB, board only has 2MB

openby mimi89999opened 2026-02-18updated 2026-02-18
bugport-rp2

Port, board and/or hardware

SEEED_XIAO_RP2350

MicroPython version

MicroPython v1.28.0-preview.175.ge154b6a8bf on 2026-02-17; Seeed XIAO RP2350 with RP2350

Reproduction

The SEEED_XIAO_RP2350 board definition appears to configure 4MB of flash, but the board only has 2MB. This causes the filesystem partition to extend beyond the physical flash boundary, risking silent data corruption due to address wrap-around.

MicroPython reports 3MB filesystem:

import rp2
f = rp2.Flash()
size = f.ioctl(4, 0) * f.ioctl(5, 0)
print(f"Flash: {size / 1024:.0f} KB")
# Flash: 3072 KB

import os
s = os.statvfs('/')
total = s[0] * s[2] / 1024
free = s[0] * s[3] / 1024
print(f"Total: {total:.1f} KB, Free: {free:.1f} KB")
# Total: 3072.0 KB, Free: 3064.0 KB

picotool info -a (in BOOTSEL mode) reports 2MB flash:

 flash size:             2048K

Seeed's product page and wiki also confirm 2MB of flash:

  • https://www.seeedstudio.com/Seeed-XIAO-RP2350-p-5944.html
  • https://wiki.seeedstudio.com/getting-started-xiao-rp2350/#specification

Expected behaviour

rp2.Flash() and os.statvfs('/') should report sizes consistent with the 2MB physical flash. The filesystem partition should not extend beyond the flash boundary.

Expected usable filesystem: ~1MB (2MB flash minus ~320KB firmware, minus alignment/overhead), not 3MB.

Observed behaviour

rp2.Flash() reports 3072 KB (3MB) of flash available for the filesystem. os.statvfs('/') confirms a 3072 KB filesystem. Both exceed the physical 2MB flash size reported by picotool and the board specifications.

Writing files that fill more than ~700KB of the filesystem would likely cause address wrap-around, silently overwriting firmware or earlier filesystem data.

Additional Information

Full picotool info -a device Information:

Device Information
 type:                   RP2350
 revision:               A2
 package:                QFN60
 chipid:                 0x20a0aaf2555c6673
 flash devinfo:          0x0c00
 current cpu:            ARM
 available cpus:         ARM, RISC-V
 default cpu:            ARM
 secure boot:            0
 debug enable:           1
 secure debug enable:    1
 boot_random:            a3fcac58:e68fafed:c6f6277e:2353da1d
 boot type:              bootsel
 last booted partition:  none
 diagnostic source:      slot 0
 last boot diagnostics:  0x00000000
 reboot param 0:         0x00000000
 reboot param 1:         0x00000000
 rom gitrev:             0x312e22fa
 flash size:             2048K

Code of Conduct

Yes, I agree

CANDIDATE · ISSUE

rp2: per-board custom memmap_mp.ld to enforce configured flash size

openby Gadgetoidopened 2022-05-18updated 2023-10-09
enhancement

I'm not sure this pertains just to RP2, but I have little experience with other platforms so I'm going to keep the scope narrow unless anyone wants to chime in. That said I think this approach is pretty generic and should be - SDK's willing - portable to other platforms.

The long and short of it is that ports/rp2/boards/PICO/mpconfigboard.h specifies MICROPY_HW_FLASH_STORAGE_BYTES which - at runtime - is the region allocated to the user-facing filesystem on an RP2-based MicroPython board.

This is configurable since boards can have 2MB, 4MB, 8MB and 16MB (and maybe beyond?) of Flash storage.

However this region is not enforced by the memmap_mp.ld linker script used to build the RP2 ports.

The practical upshot of this is that you can build a MicroPython port with too much stuff baked into it (and oh my do we bake in a lot of stuff) which will happily link and flash but then immediately soft-brick the board it's flashed to. (Turns out MicroPython has some pretty important stuff at the high-end of its binary.)

My proposal is either:

  1. To pre-process the port's memmap_mp.ld in order to configure the flash size correctly (I don't know how we'd do this, but it prevents duplication)

or

  1. To introduce the concept of board-specific memmap_mp.ld files that are auto-detected and used in place of the port one.

The latter would be achieved something like so:

diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt
index a5e421734..2db097364 100644
--- a/ports/rp2/CMakeLists.txt
+++ b/ports/rp2/CMakeLists.txt
@@ -296,7 +296,11 @@ endif()
 #  a linker script modification) until we explicitly add  macro calls around the function
 #  defs to move them into RAM.
 if (PICO_ON_DEVICE AND NOT PICO_NO_FLASH AND NOT PICO_COPY_TO_RAM)
-    pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp.ld)
+    if(EXISTS ${MICROPY_BOARD_DIR}/memmap_mp.ld)
+        pico_set_linker_script(${MICROPY_TARGET} ${MICROPY_BOARD_DIR}/memmap_mp.ld)
+    else()
+        pico_set_linker_script(${MICROPY_TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_mp.ld)
+    endif()
 endif()
 
 pico_add_extra_outputs(${MICROPY_TARGET})

And then boards/PICO/memmap_mp.ld would correctly configure the flash size:

FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 640k

This ensures that an oversized build (for whatever reason) will fail something like this:

/usr/lib/gcc/arm-none-eabi/10.3.1/../../../arm-none-eabi/bin/ld: firmware.elf section `.rodata' will not fit in region `FLASH'
/usr/lib/gcc/arm-none-eabi/10.3.1/../../../arm-none-eabi/bin/ld: region `FLASH' overflowed by 90736 bytes
collect2: error: ld returned 1 exit status
make[3]: *** [CMakeFiles/firmware.dir/build.make:9088: firmware.elf] Error 1
make[2]: *** [CMakeFiles/Makefile2:1553: CMakeFiles/firmware.dir/all] Error 2
make[1]: *** [Makefile:91: all] Error 2
make: *** [Makefile:23: all] Error 2

Rather than failing when it's flashed, run and inevitably overwrites something important!

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied