2

I have an issue where I try to write a value to a flash page (page 256 @ 0x08080000) in the STM32L476. However, I get a PROGERR error set in the flash Status Register. This means that a non-zero value was attempted to be written into a flash location not erased to 0xFFFFFFFF.

I do erase the flash like this:

uint32_t page = 256;
HAL_FLASH_Unlock();
FLASH_PageErase(page, FLASH_BANK_BOTH);
FLASH_WaitForLastOperation((uint32_t) FLASH_TIMEOUT_VALUE);
CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB));
HAL_FLASH_Lock();

However, when I check the flash contents after the erase, it did not change from the old, unerased values.

I tried to change it to

uint32_t page = 256;
HAL_FLASH_Unlock();
SET_BIT(FLASH->SR, (FLASH_FLAG_ALL_ERRORS));
FLASH_WaitForLastOperation((uint32_t) FLASH_TIMEOUT_VALUE);
FLASH_PageErase(page, FLASH_BANK_BOTH);
FLASH_WaitForLastOperation((uint32_t) FLASH_TIMEOUT_VALUE);
CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB));
HAL_FLASH_Lock();

but to no avail.

Am I missing something obvious?

halfer
  • 19,824
  • 17
  • 99
  • 186
Louis Cloete
  • 421
  • 3
  • 16

2 Answers2

1

Each bank has 256 pages, numbered 0-255. Page 256 is therefore not valid. The flash at address 0x08080000 is page 0 of bank 2. The invalid page number will cause FLASH_PageErase to fail an assert or use a different value.

The value FLASH_BANK_BOTH is not valid for FLASH_PageErase, so that will also fail an assert or use a different bank value. You can only erase one bank at a time. Otherwise, running from flash would cause a crash, since you can't read and write a single bank at the same time.

To erase the page at 0x08080000, you want to do FLASH_PageErase(page, FLASH_BANK_2 ); with page set to 0.

Thomas Jager
  • 4,836
  • 2
  • 16
  • 30
  • Found the issue myself just now. This is technically not true: `FLASH_PageErase` just masks the page number with `0xFF` and check if `Banks & FLASH_BANK_1 != 0`. So erasing with `FLASH_BANK_BOTH` and `256` is in effect erasing bank 1 page 0. `FLASH_PageErase()` doesn't fail. It does erase the wrong page. – Louis Cloete Aug 18 '21 at 13:06
  • 1
    It does mask and check for page 1, but that's after it's done `assert_param(IS_FLASH_PAGE(Page));` and `assert_param(IS_FLASH_BANK_EXCLUSIVE(Banks));`, which check for a valid page and for only one bank being set. – Thomas Jager Aug 18 '21 at 13:08
  • 1
    Though I'm actually not familiar enough with it to know if those checks are excluded in non-debug builds (seems to depend on `USE_FULL_ASSERT`). Either way, good job solving the problem yourself and including a useful answer. – Thomas Jager Aug 18 '21 at 13:10
  • Ah yes, `USE_FULL_ASSERT` is independent of the build config in STM32CubeIDE, and not set at the moment in project. – Louis Cloete Aug 18 '21 at 13:20
1

Found the issue. It has to do with the dual-bank flash on the STM32L476. Erasing page 256 erases page 0 in bank 1 instead.

Correctly checking for that and erasing the correct page would look like this:

uint32_t page = 256;
HAL_FLASH_Unlock();
FLASH_PageErase(page & 0xFF, (page & 0x100) == 0 ? FLASH_BANK_1 : FLASH_BANK_2);
FLASH_WaitForLastOperation((uint32_t) FLASH_TIMEOUT_VALUE);
CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB));
HAL_FLASH_Lock();
Louis Cloete
  • 421
  • 3
  • 16