在 RP2040 的多核模式下使用 littlefs 文件系统
RP2040 的程序存储在 SPI Flash 中,运行时会随机读取 Flash 中的程序到内部的高速缓存以便执行。这在单核工作时并不构成问题,但是在多核模式下,如果一个核在执行程序,另一个核在写 Flash(例如使用 littlefs 文件系统管理 SPI Flash 中不存储程序的剩余空间),则有可能造成同时读写 Flash 的状况,导致一个或两个核上的程序停止运行。
在常见的场景下,写 Flash 只发生在一个核上。例如核 0 (默认启动的核)处理用户界面等复杂操作,核 1 作为数字信号处理器使用,只处理信号链相关的业务。这种情况下,可以通过下面的方法简单地解决这一问题。
#include "pico/multicore.h"
#include "hardware/irq.h"
volatile int Pause_core1=0;
volatile int Core1_paused=1; //set as "paused" initially (before core 1 starts)
//call on core1 to pause at Pause_core1
//must be called in a __time_critical_func
void __time_critical_func(core1_pause)(void){
if (Pause_core1){
int s=save_and_disable_interrupts();
Core1_paused=1;
while(Pause_core1){
tight_loop_contents();
}
// Necessary re-init codes for resume processing here
// .........
// .........
restore_interrupts_from_disabled(s);
Core1_paused=0;
}
}
//call on core0 to stop core1
void core1_stop(void){
Pause_core1=1; //pause core1
while (!Core1_paused){ //wait until core1 paused
tight_loop_contents();
}
}
//call on core0 to resume core1
void core1_resume(void){
Pause_core1=0; //resume core1
}
//core1_process() must be a __time_critical_func
//but it can call normal xip functions
void __time_critical_func(core1_process)(void){
while(1){
// ... Signal processing codes ...
// ...............................
// ...............................
core1_pause();
}
}
//call on core0 to launch core1_process
void core1_launch(void){
Core1_paused=0;
multicore_launch_core1(core1_process);
}
在写 Flash 之前用 core1_stop() 暂停核 1 的运行,写 Flash 之后用 core1_resume() 恢复核 1 的运行,即可安全地写 Flash。例如(例子修改自这里):
static int pico_flash_prog(const struct lfs_config *c,
lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size) {
LFS_ASSERT(block < c->block_count);
// program with SDK
core1_stop(); // stop core1 when writing to flash (read is OK)
uint32_t p = (uint32_t)FS_BASE + (block * c->block_size) + off;
uint32_t ints = save_and_disable_interrupts();
flash_range_program(p, buffer, size);
restore_interrupts(ints);
core1_resume(); // resume core1
return LFS_ERR_OK;
}
static int pico_flash_erase(const struct lfs_config *c, lfs_block_t block) {
LFS_ASSERT(block < c->block_count);
// erase with SDK
core1_stop(); // stop core1 when writing to flash (read is OK)
uint32_t p = (uint32_t)FS_BASE + block * c->block_size;
uint32_t ints = save_and_disable_interrupts();
flash_range_erase(p, c->block_size);
restore_interrupts(ints);
core1_resume(); //resume core1
return LFS_ERR_OK;
}