0

I am using an STM32H753 which has two flash banks. For my firmware update I use the bank swapping feature so the mcu boots to the correct version.

When I swap the banks, the microcontroller crashes. No hardfault or any other exception. The debugger tells me that the PC is at 0x72c269e and the SP is at 0xbf00d7b4, but these have been different before and I assume those addresses are random.

Eventually the watchdog kicks in and resets the mcu after which the banks are swapped, so it did work. When I swap the banks back, there is no crash and everything works fine.

Here's the code that does this:

pub fn swap_bank(flash: &mut stm32h7xx_hal::stm32::FLASH) -> Result<(), &'static str> {
    assert!(flash.optcr().read().optlock().bit_is_clear());

    // Get the current config
    let current_bank = get_current_bank(flash) != 1;
    let swapped_bank = !current_bank;

    // Config the new bank
    flash
        .optsr_prg()
        .modify(|_, w| w.swap_bank_opt().bit(swapped_bank));

    // Start the config write
    flash.optcr().modify(|_, w| w.optstart().set_bit());
    
    // Wait for the change to propegate
    while flash.optsr_cur().read().opt_busy().bit_is_set() {
        cortex_m::asm::nop();
    }

    // We're done, now we need to reboot
    Ok(())
}

pub fn get_current_bank(flash: &mut stm32h7xx_hal::stm32::FLASH) -> u8 {
    flash.optcr().read().swap_bank().bit() as u8 + 1
}

If I put a bkpt instruction before the while loop, it gets hit both times (and if I then continue there's no crash both times).
If I put a bkpt instruction after the while loop, it does not get hit when swapping the first time.

The reference manual (4.3.13) tells us this:

  1. Unlock OPTLOCK bit, if not already unlocked.
  2. Set the new desired SWAP_BANK_OPT value in the FLASH_OPTSR_PRG register.
  3. Start the option byte change sequence by setting the OPTSTART bit in the FLASH_OPTCR register.
  4. Once the option byte change has completed, FLASH_OPTSR_CUR contains the expected SWAP_BANK_OPT value, but SWAP_BANK bit in FLASH_OPTCR has not yet been modified and the bank swapping is not yet effective.
  5. Force a system reset or a POR. When the reset rises up, the bank swapping is effective (SWAP_BANK value updated in FLASH_OPTCR) and the new firmware shall be executed.

I think I am doing this correctly. I've also checked the errata and there were issues in older silicon with bank switching, but I'm using the newest V revision.

I hope someone can give me a tip.

Geoxion
  • 448
  • 1
  • 4
  • 14
  • 1
    Are you trying to write to flash from the same bank the flash driver is located in? I don't know the details of this specific part, but MCUs in general don't like when you do that. So if you are trying to implement some manner of bootloader to program either bank 1 or 2, you need to have the identical flash driver code placed in both banks, and execute from the one which isn't getting programmed. – Lundin May 18 '21 at 10:33
  • The program is entirely located in one bank. The firmware update is written to the second bank after which the banks are swapped and a reboot happens to start the new firmware. Only the second bank's memory is written to and erased. – Geoxion May 18 '21 at 11:00
  • What exactly do you write in flash bank 2 ? – GabrielT May 18 '21 at 13:14
  • @GabrielT So, bank 1 contains firmware v1.0.0. Then I've got a new version v1.0.1. The server starts the update and sends over 1.0.1. The device will put the data on bank 2. When everything is finished receiving, the server sends the CRC of the data. When the device verifies that the CRC of the received and stored data on bank 2 is correct, then it will initiate the swap and reboot. The version it runs is now 1.0.1 – Geoxion May 18 '21 at 13:18
  • Okay, it's a bootload have you tried to flash(program with probe) bank 2 with a different version and perform a jump ? – GabrielT May 18 '21 at 13:20
  • No, have not tried, but if you're asking if bank 2 can execute code, then the answer is yes because my Debug build is 1.3MB (and thus spills over to bank 2) and works fine. – Geoxion May 18 '21 at 13:29
  • @Lundin this part is sector-wise. You can execute from one sector and flash another sector (but of course your program may stall for the time when flash is not available - which is not a big issue if you poll for the flash operation completion). – 0___________ May 18 '21 at 13:47
  • @0___________ Okay every vendor use their own terms. Segments, sectors, banks, pages... – Lundin May 18 '21 at 13:53
  • 1
    If it works correctly with a breakpoint then maybe there is a timing issue that is avoided when the breakpoint causes a delay. Try adding a short delay (maybe nop(s)) before the while loop. – kkrambo May 18 '21 at 15:42
  • Agree with @kkrambo , also keep in mind that interrupts may be ignored when using breakpoints – GabrielT May 18 '21 at 16:08

0 Answers0