我正在尝试为 Rust 中的 pico 编写一个程序,该程序需要在可能的关闭之间保存数据。它将与程序一起装入闪存中,并且闪存是“根据互联网”可写的。
我复制了一些大使馆 pico 模板存储库并更改了
memory.x
以包含大小为 1M 的部分 .log
。
MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 1M - 0x100
LOG : ORIGIN = 0x10100000, LENGTH = 1M
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}
EXTERN(BOOT2_FIRMWARE)
SECTIONS {
/* ### Boot loader */
.boot2 ORIGIN(BOOT2) : {
KEEP(*(.boot2));
} > BOOT2
/* Data log */
.log : {
*(.log);
. = ALIGN(4);
} > LOG
} INSERT BEFORE .text;
然后在我的代码中
#[link_section = ".log"]
static mut LOG: MaybeUninit<[u8; 1 << 20]> = MaybeUninit::uninit();
fn foo() {
let log = unsafe { LOG.assume_init_mut() };
}
但是从行为和调试中我可以看出,分配给数组没有任何作用。该部分最初被清零,即使在分配后也保持这种状态。
我已经通过一个简单的测试函数验证了这一点,该函数检查内存是否可写。
fn test_writable(log: &mut [u8]) -> bool {
let prev = log[0];
let masked = prev ^ 0xb5;
log[0] = masked;
if log[0] == masked {
log[0] = prev;
true
} else {
if log[0] == prev {
error!("Log is not writable");
} else {
error!("Log writing is incorrect. Prev: {}, expected: {}, current: {}", prev, masked, log[0]);
}
false
}
}
我使用
MaybeUninit
是否错误,是内存映射错误还是其他原因?
RPIPico 会将其闪存内存映射到“正常”地址以供读取。对于写入,该闪存不能直接寻址。
您需要使用API函数
flash_range_erase (offset, size)
flash_range_write (offset, buffer, size)
先擦除Flash中的某个块,然后再写入。
让事情变得有点复杂的是,显然这两个函数只有在禁用中断的情况下才能正常工作。另外,您需要确保不会擦除/写入保存程序的闪存区域。
RPi 2040 上的闪存必须以 4k 块进行处理 - 这意味着,您必须确保将下一个块写入闪存中程序“后面”的下一个地址,该地址可以被 4096 整除。程序地址由库在
flash_binary_end
变量中方便地提供(这是一个绝对地址,而上述两个函数需要相对于闪存的 start 的偏移量,可以通过常量 XIP_BASE
找到) .