You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust开发RPI Pico:自定义Flash分区写入无效果问题排查求助

问题分析与解决方案

核心原因:Flash不能直接内存映射写入

RP2040搭载的是SPI串行Flash,其内存映射区域(从0x10000000开始)默认是只读状态。你直接对该区域的内存地址执行赋值操作,本质是向只读映射空间写入,硬件会直接忽略这类操作,所以数据不会发生变化。Flash的写入必须遵循「先擦除再编程」的固定流程,且只能通过RP2040的Flash控制器硬件接口完成,不能像操作RAM那样直接赋值。

你的代码/配置问题拆解

  1. memory.x配置问题:
    你新增的.log分区地址0x10100000属于Flash的内存映射范围,这个区域硬件层面就是只读的,即便通过链接脚本将变量放在这里,也无法直接写入。另外要确认Pico实际Flash容量:RP2040通常配备2M或4M Flash,你分配了1M给主程序+1M给LOG,需确保总容量不超过硬件实际Flash大小。

  2. MaybeUninit的使用:
    这里的MaybeUninit用法没有问题,它只是用来在Flash区域预留一个未初始化的数组空间,问题根源不在这个变量本身。

正确实现方式

要实现Flash数据持久化,需使用专门的Flash操作库,比如Embassy生态的embassy-rp或rp2040-hal提供的Flash API。

示例步骤(基于Embassy)

  1. 移除memory.x中的.log分区配置:无需手动在链接脚本中分配Flash区域,Flash操作库会直接操作物理Flash地址。
  2. 使用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();
  1. 关键注意事项:
    • 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ý

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 12:52:44