Rust开发RPI Pico:自定义Flash分区写入无效果问题排查求助
问题分析与解决方案
核心原因:Flash不能直接内存映射写入
RP2040搭载的是SPI串行Flash,其内存映射区域(从0x10000000开始)默认是只读状态。你直接对该区域的内存地址执行赋值操作,本质是向只读映射空间写入,硬件会直接忽略这类操作,所以数据不会发生变化。Flash的写入必须遵循「先擦除再编程」的固定流程,且只能通过RP2040的Flash控制器硬件接口完成,不能像操作RAM那样直接赋值。
你的代码/配置问题拆解
memory.x配置问题:
你新增的.log分区地址0x10100000属于Flash的内存映射范围,这个区域硬件层面就是只读的,即便通过链接脚本将变量放在这里,也无法直接写入。另外要确认Pico实际Flash容量:RP2040通常配备2M或4M Flash,你分配了1M给主程序+1M给LOG,需确保总容量不超过硬件实际Flash大小。MaybeUninit的使用:
这里的MaybeUninit用法没有问题,它只是用来在Flash区域预留一个未初始化的数组空间,问题根源不在这个变量本身。
正确实现方式
要实现Flash数据持久化,需使用专门的Flash操作库,比如Embassy生态的embassy-rp或rp2040-hal提供的Flash API。
示例步骤(基于Embassy)
- 移除memory.x中的.log分区配置:无需手动在链接脚本中分配Flash区域,Flash操作库会直接操作物理Flash地址。
- 使用Flash API执行擦除和写入:
use embassy_rp::flash::Flash; use embassy_rp::peripherals::FLASH; // 初始化Flash控制器 let mut flash = Flash::new(p.FLASH); // 定义LOG区域起始地址(需避开主程序占用的Flash空间,比如从0x10100000开始) const LOG_START: u32 = 0x10100000; const LOG_SECTOR_SIZE: u32 = 4096; // RP2040 Flash扇区大小为4K const LOG_PAGE_SIZE: u32 = 256; // Flash页大小为256字节 // 写入前先擦除对应扇区 flash.erase(LOG_START, LOG_START + LOG_SECTOR_SIZE).unwrap(); // 写入数据(需按页对齐) let data = [0xb5u8; 256]; flash.write(LOG_START, &data).unwrap(); // 读取数据验证 let mut buf = [0u8; 256]; flash.read(LOG_START, &mut buf).unwrap();
- 关键注意事项:
- Flash有擦写寿命限制(通常约10万次),避免频繁擦写同一区域
- 写入操作必须按页对齐,擦除操作必须按扇区对齐
- 需确保LOG区域不与主程序Flash空间重叠,可通过调整
memory.x中FLASH的LENGTH参数实现,比如设为1M - 0x100,这样LOG区域从0x10100000开始就不会冲突
测试函数修正
原测试函数是针对RAM的写入逻辑,不适用于Flash,需改用Flash API实现:
fn test_flash_writable(flash: &mut Flash<FLASH>) -> bool { const TEST_ADDR: u32 = 0x10100000; let mut prev = [0u8; 1]; flash.read(TEST_ADDR, &mut prev).unwrap(); let masked = prev[0] ^ 0xb5; // 擦除对应扇区 flash.erase(TEST_ADDR, TEST_ADDR + 4096).unwrap(); // 写入测试值 flash.write(TEST_ADDR, &[masked]).unwrap(); let mut current = [0u8; 1]; flash.read(TEST_ADDR, &mut current).unwrap(); if current[0] == masked { // 恢复原数据 flash.erase(TEST_ADDR, TEST_ADDR + 4096).unwrap(); flash.write(TEST_ADDR, &prev).unwrap(); true } else { error!("Flash writing failed. Prev: {}, expected: {}, current: {}", prev[0], masked, current[0]); false } }
内容的提问来源于stack exchange,提问作者Martin Horský
相关产品推荐
相关产品推荐

