cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H755 stalling CPU when erasing bank 1 flash from code running in bank 2 (but not the other way around)

mark03
Associate III

I am implementing a firmware-update mechanism on STM32H755 (Nucleo board, MCU rev U) in which the two flash banks are independent.  New firmware is flashed by erasing the "other" bank (which is always mapped at 0x0810 0000 and accessed with the ____2 register set, e.g. FLASH_CR2), then writing the candidate firmware image into that bank, verifying a SHA hash after programming, and finally toggling the SWAP_BANK bit in option bytes, performing an option-byte update, and software reset to boot into the new image.  This works, and I can perform one update after another, ping-ponging back and forth between the banks.  Note that the running application is always mapped at 0x0800 0000, is [much] less than 1 MByte, and never touches the other bank at 0x0810 0000 except to erase and program it when an update is requested.

The issue I am having is that when the code runs in Bank 2 and an update commences, the bank erase of Bank 1 is stalling the CPU for several seconds.  The same thing does *not* happen when the code is running in Bank 1 and performs a bank erase on Bank 2.  Also, the actual programming never stalls the CPU---only the initial bank erase, and only when it is Bank 1 being erased.

AFAICT, there is no difference at all between these two scenarios---everything should be identical between them, down to the contents of every single register and memory location, *except* for the SWAP_BANK bit in the option bytes.  So why would one behave differently?  (Note, for this test, I am updating with an identical firmware image, so there is no difference pre- and post-update.)

I was able to find corroborating evidence of this unexpected behavior in another forum post, here:

https://community.st.com/t5/stm32-mcus-products/bus-stall-when-writing-erasing-flash-on-stm32h7/td-p/360606 

(Note the OP is not describing it---it's later in the thread, user @MDrew.1 , and they apparently never got to the bottom of it.)

I know better than to claim a silicon bug :)  although I cannot think of another explanation.  Can you?  Best-case scenario, someone has figured out an undocumented way around this problem.

Why does this matter?  Well, I'd like to use a watchdog timer, and 4+ seconds is a pretty long watchdog expiration.  Also, other RTOS tasks are supposed to be running in the background during the update process, and they do, just fine---when the code is running in Bank 1.

5 REPLIES 5
mƎALLEm
ST Employee

Hello,

You did accept the solution in this thread: STM32H755 failing to erase bank 1 while running from bank 2 (opposite works fine) , do you mean you didn't solve your issue? If yes, better to continue the discussion.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
mark03
Associate III

I don't think code is going to explain better than I already have above, but in case someone asks, here is the code which erases the inactive flash bank.  The CPU stall happens at the first write to FLASH_CR2 (setting the BER and START bits), and lasts about four seconds.  Afterwards, the code resumes and everything works as expected.  (The actual flash writes do not stall the CPU.)  And again, the stall doesn't happen at all if we are running in Bank 1 and staging a new image in Bank 2, only when running in Bank 2 and staging the new image in Bank 1.

// Bank-erase the inactive flash (always BANK2, i.e. the bank mapped at 0x08100000)
if (FLASH->CR2 & FLASH_CR_LOCK)
{
  FLASH->KEYR2 = 0x45670123;
  FLASH->KEYR2 = 0xcdef89ab;
}

FLASH->CR2 |= (FLASH_CR_BER | FLASH_CR_START);  // start erase of inactive bank
while (FLASH->SR2 & FLASH_SR_QW)
{ vTaskDelay(pdMS_TO_TICKS(100)); }  // yield to other tasks while we wait

FLASH->CR2 |= FLASH_CR_PG;  // enable programming on this bank

// programming flash at 0x0810 0000 happens here (not shown)

// New image hash checked out; swap banks, update option bytes, and reset
if (FLASH->OPTCR & FLASH_OPTCR_OPTLOCK)
{
  FLASH->OPTKEYR = 0x08192a3b;
  FLASH->OPTKEYR = 0x4c5d6e7f;
}

FLASH->OPTSR_PRG ^= FLASH_OPTSR_SWAP_BANK_OPT;  // toggle the SWAP_BANK_OPT bit
FLASH->OPTCR |= FLASH_OPTCR_OPTSTART;           // start option-byte write
while (FLASH->OPTSR_CUR & FLASH_OPTSR_OPT_BUSY) // wait for it to complete
{ vTaskDelay(pdMS_TO_TICKS(100)); }

SCB->AIRCR = (0x5fa << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk;

The other thread was about a separate misunderstanding I had about the ____1 registers versus the ____2 registers in the FLASH block; I didn't realize that swapping the banks also swaps the register sets, so that the ____2 registers *always* relate to whichever bank is mapped at 0x0810 0000.  The issue I'm seeing now is different, hence the new thread.  I've posted my updated code in case that clarifies the question.

waclawek.jan
Super User

VTOR is set how?

JW

VTOR does not need to be changed because the interrupt vectors are in the same place as usual, 0x0800 0000, regardless of which bank is mapped there.  An updated firmware image contains everything that the original image contains, including the interrupt vectors and the code which performs firmware updates.  (In this scheme, there is no separate bootloader.)