我在Zephyr和MCUboot下使用RP2040。最终目标是能够通过UART总线使用MCUMGR更新固件。MCUboot采用A/B无缝(双插槽内存)方式,提供安全的更新算法。当设备重新启动时,MCUboot检查是否有新的固件可用,在这种情况下,在新的固件上启动。为此,交换算法将目标固件放在槽位0中。由于该算法操作flash,必须将某些函数映射到SRAM中,以确保该函数不会擦除自己的代码。通常,由于RP2040上的Direct-XIP,代码直接从flash执行。问题是SRAM似乎不是可执行的。当程序进入位于SRAM中的函数并执行第一条指令时,这会导致硬故障:
0x2000c144
: push {r4, r5, r6, r7, lr}
幸运的是,Zephyr crash的处理程序给出了一些信息:
E: ***** HARD FAULT *****
E: r0/a1: 0x0003d000 r1/a2: 0x00002000 r2/a3: 0x00002000
E: r3/a4: 0x00000000 r12/ip: 0x2000c145 r14/lr: 0x100022e5
E: xpsr: 0x21000000
E: Faulting instruction address (r15/pc): 0x2000c144
E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
E: Current thread: 0x2000c3d0 (unknown)
E: Halting system
一切正常,电脑地址正确。我强烈怀疑是MPU配置错误导致程序在执行位于SRAM中的代码时崩溃。
我的问题是:MPU会导致Hardfault吗?如何在Zephyr中配置SRAM以执行SRAM中的代码?
首先,我试图检查相同的功能是否可从flash执行。我删除了指示位于flash上的宏。
:
void __no_inline_not_in_flash_func(flash_range_erase)(uint32_t flash_offs, size_t count) {
...
:后void flash_range_erase(uint32_t flash_offs, size_t count) {
...
…它有效!函数按预期执行。我现在很确定MPU不愿意让我在SRAM内执行代码。
我搜索了有关如何配置MPU以让我在SRAM中执行代码的信息,我发现此页面:https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/hardware/arch/arm_cortex_m.html解释了如何配置固定区域。我在我的设备树叠加中添加了以下几行:
&sram0 {
/delete-property/ compatible ;
/delete-property/ reg ;
compatible = "zephyr,memory-region", "mmio-sram";
zephyr,memory-region = "RAM_EXECUTABLE";
zephyr,memory-region-mpu = "RAM";
reg = < 0x20000000 0x10000 >; //Configure SRAM for MCUboot fixed for MPU
// RAM size has to match with BOOTLOADER_SRAM_SIZE (see menuconfig)
};
但这并没有解决问题。
这是Zephyr中RP2040的flash控制器的问题。
flash控制器必须禁用XiP才能运行flash操作(r/w)。在此过程中,控制器试图运行未链接到RAM(在闪存中)的函数。
要恢复,控制器在禁用flash执行后试图调用flash中的函数。我可能很快会发布一个补丁。
更多关于西风之神不和的信息在这里:https://discord.com/channels/720317445772017664/938474761405726800/1060917537405157446
注意在我的问题中,我试图使用MPU,但我不得不禁用引导加载程序配置。