cancel
Showing results for 
Search instead for 
Did you mean: 

Hardfaults in external flash loader when clicking disconnect in STM32CubeProgrammer

unsigned_char_array
Senior III

A year ago I made an external flash loader and that works (https://github.com/STMicroelectronics/stm32-external-loader/pull/13). I now ported the loader to the STM32H735IG. I use a serial port to print debug messages at certain points. While the flash loader works I do get hardfaults(in the loader, not the application) under certain conditions:

If I connect in STM32CubeProgrammer and then open memory viewer to 0x90000000 and then click disconnect. It doesn't occur when I did not open the memory viewer to 0x90000000 since that doesn't lead to an init of the loader. The flash loader will properly flash the internal and external flash and optionally runs the MCU. So it works, but I do see a hardfault error printed:

Init()
HardFault_Handler
CFSR = 0x00000000
HFSR = 0x80000000
DFSR = 0x0000000B
MMFAR = 0x00000000
BFAR = 0x00000000
AFSR = 0x00000000

So HFSR[31/]DEBUGEVT is active.
And DFSR/Debug Fault Status Register is non-zero. I did not find any documentation about this register for the Cortex-M7. In core_cm7.h I found this means the following bits are set to 1 (and in https://www.keil.com/dd/vtr/4143/7607.htm I found their meaning):

  • HALTED is set when the processor is halted.
  • BKPT is set when a software breakpoint is encountered.
  • VCATCH is set when a vector catch is triggered.

What this means exactly I don't know. I do have interrupts enabled at some points, maybe that is the cause?

 

 

In STM32CubeIDE after clicking debug the flash loader will properly flash the internal and external flash and start the debug session. So it works, but I do see a hardfault error printed:

STM32H735IGT6_MT25TL256.stldr flash loader V1.01 Beta 1
Init()
SectorErase
STM32H735IGT6_MT25TL256.stldr flash loader V1.01 Beta 1
Init()
Write
Write
Write
Write
Write
Write
Write
Write
Write
Write
Write
Write
Write
Write
Write
Write
STM32H735IGT6_MT25TL256.stldr flash loader V1.01 Beta 1
Init()
HardFault_Handler
CFSR = 0x00000000
HFSR = 0x80000000
DFSR = 0x0000000B
MMFAR = 0x00000000
BFAR = 0x000000

The hardfault occurs when either closing the connection in STM32CubeProgrammer or when "Run after programming is called".

Also flashing a second time in STM32CubeProgrammer I get errors if I don't disconnect and reconnect first:

11:30:06 : File download complete
11:30:06 : Time elapsed during download operation: 00:00:06.430
11:30:06 : Verifying ...
11:30:06 : Read progress:
11:30:08 : Download verified successfully
11:31:12 : Memory Programming ...
11:31:12 : Opening and parsing file: SKF-MF-Dismount-HMI.elf
11:31:12 : File : SKF-MF-Dismount-HMI.elf
11:31:12 : Size : 806.88 KB
11:31:12 : Address : 0x08000000
11:31:12 : Erasing memory corresponding to segment 0:
11:31:12 : Erasing internal memory sectors [0 1]
11:31:14 : Error: failed to erase memory
11:31:14 : Error: failed to erase memory

This problem occurs in the internal flash.

I use standalone STM32CubeProgrammer version 2.15.0. STM32CubeIDE uses STM32CubeProgrammer version 2.11.0.

Can someone tell me what causes the hardfault error? Is it a problem or is this actually desired behavior?

Can someone tell me what causes second flashing to fail?

 

Edit:
I discovered more. I have the same error in my application if I reinitialize OSPI. It crashes in HAL_OSPIM_Config().
Calling HAL_OSPI_DeInit() and then MX_OCTOSPI1_Init() causes a crash. I do reset the peripheral clocks at the bottom of OCTOSPI1_MspInit using __HAL_RCC_OSPI1_FORCE_RESET() and __HAL_RCC_OSPI1_RELEASE_RESET(). But I guess HAL_OSPIM_Config has to be de-initialized first.

It specifically crashes at:

 

 

 

    /***************** Deactivation of previous configuration *****************/
    CLEAR_BIT(OCTOSPIM->PCR[(IOM_cfg[instance].NCSPort-1U)], OCTOSPIM_PCR_NCSEN);

 

 

 

It appears the problem doesn't occur in my application if I initialize OSPI1 before OSPI2. But it still occurs in the flash loader. I found this topic that seems to be related: https://community.st.com/t5/stm32-mcus-products/stm32-cube-h7-hal-ospim-config-corrupts-previous-port/m-p/126073

Ospi2 is HyperRAM and it is memory mapped. If I initialize OSPI2 first, but do not enable memory mapping the error doesn't occur. So the problem occurs in HAL_OSPIM_Config after OSPI2 is memory mapped. I think a similar thing happens in the flash loader but in this case it is OSPI1 that is memory mapped when the error occurs. HAL_OSPIM_Config doesn't like to be called when at least one OSPI is memory mapped.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.
8 REPLIES 8
KDJEM.1
ST Employee

Hello @unsigned_char_array ,

Please make sure that both OSPI instance are disabled to configure OCTOSPI Manager. This behavior is mentioned in RM0468 Rev 3 section 26.4.2.

KDJEM1_0-1711444848911.png

So I advise you to avoid the OSPIM configuration issue to call HAL_OSPIM_Config only one time at boot. After this, HAL_OSPI_Init() and HAL_OSPI_DeInit() can be called at any time.

Before called a HAL_OSPI_DeInit() it is necessary have to be sure that no Rd/Wr access are ongoing, especially in Memory Mapped Mode where there is no feedback on this access inside OSPI block.

I hope this help you.

Kaouthar

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.

"Please make sure that both OSPI instance are disabled to configure OCTOSPI Manager."

HAL_OSPIM_Config does this automatically, but maybe it does it improperly. I will check if I can make some type of fix.
"So I advise you to avoid the OSPIM configuration issue to call HAL_OSPIM_Config only one time at boot."

As far as I know the flash loader doesn't really boot. It is loaded in RAM and then nothing happens. The debugger calls the Init function. The problem is that it does it repeatedly. I'll check if I can modify the Init function.

EDIT:

Adding the following check helps to detect if it is booted the first time or not:

firstTime = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_OSPI1EN) == 0;

I'm now trying to disable initialization of variables and explicitly doing it in code the first time. This should preserve the values in the handles and other states. Correct me if I'm wrong.

 

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.
KDJEM.1
ST Employee

Hi @unsigned_char_array ,

Could you please precise which STM32CubeMX version are you using?

Please try to use the latest version of STM32CubeMX 6.11.0 and let me know if the issue is solved or not?

Thank you.

Kaouthar

 

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.

I'm using 6.10.0. I am not able to download the newer version as the download page keeps crashing.

Edit: I've refactored my init function. I placed global variables (including handles) in no-init RAM. The first time I use memset to zero-initialize these variables and initialize the peripherals. Subsequent calls to init do not re-initialize peripherals. This works perfectly. However the hardfault error still occurs when the debugger disconnects, in STM32CubeIDE when starting a debug session it gets a hardfault after flashing and then starts the application (debugs and runs perfectly), and also in STM32CubeProgrammer after clicking disconnect.
It even occurs if I disable interrupts. I can mask the problem by setting VTOR to 0, but I assume a hardfault still occurs in that case, but it just doesn't call the hardfault handler of the flash loader.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.
KDJEM.1
ST Employee

Hi @unsigned_char_array ,

To check the issue could you please share your project?

Please make sure that you used Data Synchronization Barrier (DSB) followed by an Instruction Synchronization Barrier (ISB) after configuring the vector table.

because in Cortex-M processors, typically the location of the vector table is determined by the Vector Table Offset Register (VTOR). If you need to change the vector table base address, then a DSB instruction should be used after writing a new value to the VTOR register. This ensures that the Memory system write to the VTOR register is complete. An ISB followed by a DSB is required to ensure that any subsequent exceptions and interrupts use the new vector table base address.

I'm using 6.10.0. I am not able to download the newer version as the download page keeps crashing.

Could you please share a screenshot?

I hope this help you!

Kaouthar

 

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.

"To check the issue could you please share your project?"

I've attached the code. To clarify the loader works perfectly it only creates a hardfault after disconnect by STM32CubeProgrammer (standalone and the one from STM32CubeIDE). And I only noticed it because I print debug messages.

"Please make sure that you used Data Synchronization Barrier (DSB) followed by an Instruction Synchronization Barrier (ISB) after configuring the vector table."
Done. No difference.

"I'm using 6.10.0. I am not able to download the newer version as the download page keeps crashing. Could you please share a screenshot?"
I guess I was too impatient. After clicking download the website kept showing the loading icon for 20 seconds without progress. Then it downloaded.
Regenerating with 6.11.0 produces identical code and the same result. I always have to manually select my custom linker file after regenerating, it's no different in this version. I also modified the handles so they are put in no-init RAM, this is overwritten by regeneration too.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.
KDJEM.1
ST Employee

Hi @unsigned_char_array ,

Could you please try to completely reset peripheral in Loader_Src.c

   MX_GPIO_Init();
    __HAL_RCC_OSPI1_FORCE_RESET();  //completely reset peripheral
    __HAL_RCC_OSPI1_RELEASE_RESET();

Thank you.

Kaouthar

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.

I already reset the OSPI peripheral at the end of HAL_OSPI_MspInit() with those 2 lines. Adding it after GPIO init too made no difference.
This problem is hard to debug as I don't know what STM32CubeProgrammer does using the debugger when disconnecting and how that affects the MCU and how it should respond.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.