RPI pico записывает во флэшку программно

Я пытаюсь написать программу для пико на ржавчине, которая должна сохранять данные между возможными отключениями. Влезло бы во флэшку с программой и флэшка "по интернету" записываемая.

Я скопировал репозиторий шаблонов посольства 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, неправильная карта памяти или что-то еще?

Вы не можете просто назначить переменную, хранящуюся во флэш-памяти, она не реагирует так же, как ОЗУ. Запись на флэш-чип, подключенный к RP2040, возможна, но вам необходимо отправлять на него правильные команды. Вероятно, вам следует найти пример в pico-sdk, а если его нет, то узнать, как это делает MicroPython (он хранит записываемую файловую систему во флэш-памяти RP2040).

David Grayson 22.04.2024 23:18

Хотя некоторые процессоры могут отображать карту памяти флэш-памяти, чтобы вы могли читать из нее, запись во флэш-память является более сложным процессом, поскольку обычно он спроектирован таким образом, что за раз стирается вся страница. Это зависит от микроконтроллера и флэш-памяти, но обычно вам нужно вызвать специальную команду, чтобы сначала стереть страницу, прежде чем вы сможете на нее записать. После этого некоторые микроконтроллеры позволят вам записывать адрес, отображенный в памяти, после того, как вы его очистили, другие могут потребовать от вас использования специального командного механизма, как отмечает @DavidGrayson.

effect 23.04.2024 01:09
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
2
408
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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);

Другие вопросы по теме