如何利用指针存储的固件实现Raspberry Pi Pico程序化重编程?
程序化重编程Raspberry Pi Pico的可行方案
核心思路:基于内部Flash自编程实现固件更新
你提到的flash_range_erase()和flash_range_program()是实现自编程的核心API,它们并非只能编辑“小部分内存”——只要规划好Flash分区并遵循安全操作流程,完全可以实现全程序的更新。关键是要避开当前运行代码所在的Flash区域,通过独立引导加载程序处理更新逻辑。
步骤1:拆分Flash为引导加载区与应用区
将Pico的256KB Flash划分为两个独立区域:
- 引导加载区:固定在Flash起始位置(比如前16KB,地址范围
0x10000000-0x10003FFF),负责接收CM3传来的固件、验证固件完整性、写入应用区,最后跳转至应用程序执行。这部分代码要极简且独立,确保更新过程中不会崩溃。 - 应用区:从引导加载区结束位置开始(比如
0x10004000),存放你的主业务程序,剩余Flash空间都可分配给该区域。
步骤2:实现安全的Flash自编程流程
当CM3通过专有协议将新固件传输到Pico内存指针后,执行以下操作:
- 屏蔽干扰源:
Flash操作会暂停指令读取,必须确保无其他代码干扰:// 关闭全局中断 __disable_irq(); // 停止第二核心(若使用双核) multicore_reset_core1(); - 擦除应用区Flash:
擦除地址必须4KB对齐(Pico Flash的最小擦除块为4KB),注意Flash操作使用相对于XIP基地址的偏移量:#define APP_START_ADDR 0x10004000 #define APP_TOTAL_SIZE 0x3C000 // 240KB,对应剩余Flash空间 // 计算偏移量:APP_START_ADDR - XIP_BASE(0x10000000) flash_range_erase(APP_START_ADDR - XIP_BASE, APP_TOTAL_SIZE); - 写入新固件:
直接将内存中的固件数据写入应用区:// new_firmware_ptr为CM3传输过来的固件内存指针 flash_range_program(APP_START_ADDR - XIP_BASE, (const uint8_t*)new_firmware_ptr, APP_TOTAL_SIZE); - 恢复系统并跳转至新应用:
操作完成后恢复系统状态,跳转到新应用的重置向量:__enable_irq(); // 从应用区起始地址+4位置读取重置向量地址 void (*app_reset_handler)(void) = (void (*)(void))(*(uint32_t*)(APP_START_ADDR + 4)); app_reset_handler();
步骤3:处理不同固件格式的解析
针对你支持的三种格式,需在Pico中做对应解析:
- .bin格式:直接是Flash二进制镜像,无需转换,按对应地址写入即可。
- .hex格式:解析Intel Hex的记录结构,提取数据段和对应地址,再写入Flash的对应位置。
- .uf2格式:解析UF2的块结构,提取其中的Flash数据和目标地址,忽略引导块等无关信息。
为何reset_usb_boot()不适用?
reset_usb_boot()会让Pico进入出厂USB引导模式,但重启后之前存在内存的固件指针会失效,且无USB连接无法传输固件,完全匹配不了你的硬件场景,因此无需考虑该方案。
关键注意事项
- 引导加载区代码必须绝对稳定,禁止被更新操作覆盖,否则会导致Pico变砖。
- Flash操作过程中严禁断电,可在更新前加入电源检测逻辑,或确保供电稳定。
- 固件传输后必须做完整性校验(如CRC32),避免写入损坏的固件导致无法启动。
内容的提问来源于stack exchange,提问作者Bibibou
相关产品推荐
相关产品推荐

