Я пытаюсь написать программу для пико на ржавчине, которая должна сохранять данные между возможными отключениями. Влезло бы во флэшку с программой и флэшка "по интернету" записываемая.
Я скопировал репозиторий шаблонов посольства Pico и изменил memory.x, чтобы он содержал раздел .log размером 1 Мб.
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, неправильная карта памяти или что-то еще?
Хотя некоторые процессоры могут отображать карту памяти флэш-памяти, чтобы вы могли читать из нее, запись во флэш-память является более сложным процессом, поскольку обычно он спроектирован таким образом, что за раз стирается вся страница. Это зависит от микроконтроллера и флэш-памяти, но обычно вам нужно вызвать специальную команду, чтобы сначала стереть страницу, прежде чем вы сможете на нее записать. После этого некоторые микроконтроллеры позволят вам записывать адрес, отображенный в памяти, после того, как вы его очистили, другие могут потребовать от вас использования специального командного механизма, как отмечает @DavidGrayson.

RPIPico отображает свою флэш-память на «обычные» адреса для чтения, поэтому вы можете просто читать с флэш-адресов. Что касается записи, то эта флэш-память не адресуется напрямую - запись напрямую по адресам флэш-памяти не дает ничего полезного.
Обратите внимание, что приведенное ниже справедливо для функций C API — вам нужно будет найти подходящие эквиваленты Rust в вашем SDK.
Вам необходимо использовать функции API
flash_range_erase (offset, size)
flash_range_write (offset, buffer, size)
сначала стереть определенный блок во флеше, а потом записать его.
Ситуация немного усложняется тем, что обе функции, очевидно, будут работать правильно только с отключенными прерываниями. Кроме того, вам необходимо убедиться, что вы не стираете/не записываете во флэш-область, содержащую вашу программу.
Флэш-память на RPi 2040 должна обрабатываться блоками по 4 КБ. Это означает, что вы должны убедиться, что вы записываете в следующий блок следующий адрес «позади» вашей программы во флэш-памяти, который можно разделить на 4096 поровну. Ваша последняя программа Адрес удобно предоставляется библиотеками в переменной flash_binary_end (которая является абсолютным адресом, в то время как две вышеуказанные функции требуют смещения относительно начала флэш-памяти, которое можно найти по константе XIP_BASE).
Итак, чтобы записать блок данных длиной blockдлиной 4096 во флэш-память вашего программного кода, вы можете концептуально сделать следующее:
void *flashAddress = (flash_binary_end + 4096) & 0xfffff000;
int flashOffset = flashAddress - XIP_BASE;
uint32_t ints = save_and_disable_interrupts();
flash_range_erase (flashOffset, 4096);
flash_range_write (flashOffset, block, 4096)
restore_interrupts (ints);
Вы не можете просто назначить переменную, хранящуюся во флэш-памяти, она не реагирует так же, как ОЗУ. Запись на флэш-чип, подключенный к RP2040, возможна, но вам необходимо отправлять на него правильные команды. Вероятно, вам следует найти пример в pico-sdk, а если его нет, то узнать, как это делает MicroPython (он хранит записываемую файловую систему во флэш-памяти RP2040).