Правильно ли работает двойное чтение и запись в STM32L071?

Я пытаюсь перепрограммировать NVM (банк флэш-памяти 2) при выполнении кода из банка флэш-памяти 1 в микроконтроллере STM32L071CB.

Как указано в AN4808 и AN4767, «интерфейс памяти способен читать оба банка параллельно или читать один банк при записи в другой …», но у меня возникают некоторые проблемы:

  1. Отладка показывает, что бит FWWERR становится высоким в регистре состояния флэш-памяти во время операции записи половины страницы во флэш-банк 2. Это означает, что запись flash банка 2 была остановлена ​​из-за выборки кода.
  2. Стирание банка 2 по коду в банке 1 работает корректно.
  3. Запись по банку слов 2 по коду в банке 1 вроде бы работает правильно (но у меня есть сомнения, может это просто совпадение).
  4. Запись половины страницы заканчивается установленным битом FWWERR в FLASH_SR и нулями в памяти, которую я пытаюсь записать.

Я знаю, что что-то упускаю, но не могу понять, что именно. Может у кого была похожая проблема? Я начинаю думать, что что-то не так с микроконтроллером (в листе ошибок указаны некоторые проблемы с механизмом переключения двух банков, но в моем случае это не должно быть проблемой, потому что я не переключаю банки прямо сейчас).

Моя функция работает правильно при выполнении из оперативной памяти, но я бы предпочел, чтобы она запускалась из флэш-банка 1.

Функция (1) ниже отвечает за запись половины страницы. Код (2) показывает, как я звоню (2).

(1)

void nvm_prog_write_halfpages(uint32_t* addr, uint32_t* data, uint32_t length){

    // There can't be any previous alignment errors in the flash SR
    if ((FLASH->SR & FLASH_SR_PGAERR_Msk) == FLASH_SR_PGAERR){
         FLASH->SR = FLASH_SR_PGAERR; // clear any previous alignment errors
    }

    // Check if any operation was stopped previously due to code fetching
    if ((FLASH->SR & FLASH_SR_FWWERR_Msk) == FLASH_SR_FWWERR){
        FLASH->SR = FLASH_SR_FWWERR; // clear any previous fetch related errors
    }

    nvm_prog_unlock();

    FLASH->PECR |= FLASH_PECR_PROG | FLASH_PECR_FPRG;

    uint32_t cnt = 0;
    while (length > 0){
        *addr = *data; // Destination address will be increased by the hardware automatically
        data++;
        cnt++;

        // When a half-page has been written
        if (cnt == 16){
            while ((FLASH->SR & FLASH_SR_BSY_Msk) == FLASH_SR_BSY)
                ;
            cnt = 0;
            addr += 16; // Write the next half-page
            length--;
        }
    }

    FLASH->PECR &= ~(FLASH_PECR_PROG | FLASH_PECR_FPRG);

    nvm_prog_lock();
}

(2)

nvm_prog_erase_page((uint32_t *) 0x08010000); // Erase flash bank 2; it starts at 0x08010000

uint32_t dummydata[32], i;
for (i=0; i<32; i++){
    dummydata[i] = i;
}

nvm_prog_write_halfpages((uint32_t *) 0x08010000, &dummydata[0], 2); // Write 2 half-pages at the beginning of flash bank 2
Убедитесь, что отладчик не считывает содержимое флэш-памяти во время программирования. Не выполняйте пошаговую последовательность программирования, используйте точки останова.

Ответы (1)

Чтение во время записи имеет некоторые ограничения в случае операции множественного программирования. См. RM0377 § 3.3.4 Запись/стирание NVM — Половина страницы программы во флэш-памяти программ, стр. 82:

Когда начинается операция с половиной страницы, интерфейс памяти ожидает 16 адресов/данных, прерывая (с серьезной ошибкой) все операции чтения, не являющиеся выборкой (см. Выборка и предварительная выборка). Выборка останавливает операцию с половиной страницы. Содержимое памяти остается без изменений, в регистре FLASH_SR устанавливается ошибка FWWERR.

Это означает, что операции выборки не разрешены во флэш-памяти при подаче в интерфейс памяти 16 слов (независимо от того, какой код выполняется в банке 1, а программирование половины страницы выполняется в банке 2). Как только 16 слов будут отправлены в интерфейс памяти, вы можете возобновить выполнение из флэш-памяти, то есть во время физической записи данных во флэш-банк (при условии, что ваш код выполняется в другом банке).

Короче говоря, вам нужно выполнить из SRAM загрузку интерфейса памяти 16 словами и убедиться, что прерывания не вызовут выборку во флэш-памяти (либо замаскируйте все прерывания, либо переместите обработчики прерываний и вектор прерываний в SRAM).

Примечание: в случае одиночной операции программирования такого ограничения нет.