Skip to main content
Senior II
October 27, 2023
Question

HAL_FLASHEx_Erase HardFault_Handler STM32G030K8

  • October 27, 2023
  • 18 replies
  • 5452 views

Hello,

I have developed an application that saves accelerometer data when a machine starts up. This data is stored in the last page of the controller's memory (page 31).

I'm encountering a HardFault exception that occurs intermittently, roughly 1 in 20 to 50 times when running the code with the debugger attached. However, it consistently happens when flashing and running the application without the debugger.

I'm seeking guidance on how to effectively debug this issue. Here's a snippet of the relevant code:

The page parameter is 31, with a size of 1 when this function is called.

Any assistance in troubleshooting this problem would be greatly appreciated.

 

 

static _Bool flash_erase_pages(uint8_t page,uint8_t size)
{
	static FLASH_EraseInitTypeDef EraseInitStruct;
	uint8_t bResult=0;
	uint8_t retry=0;

	static volatile uint32_t flasherror;
	uint32_t PAGEError;

	do{
		/* Unlock the Flash to enable the flash control register access *************/
		HAL_FLASH_Unlock();

		 /* Clear OPTVERR bit set on virgin samples */
		__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);


		/* Fill EraseInit structure*/
		EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
		EraseInitStruct.Banks = FLASH_BANK_1 ;
		EraseInitStruct.Page = (uint32_t)page;
		//EraseInitStruct.NbPages = ((EndPage - StartPage)) +1;
		EraseInitStruct.NbPages = size;

		if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
		{
			/*Error occurred while page erase.*/
			flasherror = HAL_FLASH_GetError ();
		}
		else{
			bResult = 1;
		}

		HAL_FLASH_Lock();

		if(bResult) 	return true;
		HAL_Delay(1);
		if(++retry>5) 	return false;
	}while(1);
}

 

 



on the occasional times i was able to generate this while i was debuggin i got these data :

The HardFault happens in HAL_FLASH_Lock(); ->  SET_BIT(FLASH->CR, FLASH_CR_LOCK);

before we enter the HardFault  i see this data in the flash_erase_pages function.
PAGEError = 2103
PAGEError = 536876972 (another time)

Which seems to make no sense as there are only 32 pages.
flasherror =  0 

 

Upon a successful flash write, the value of PAGEError is consistently 0xFFFFFFFF. I'm perplexed by what might be causing this unexpected behavior.

Here's the structure of EraseInitStruct for your reference:

image.png


Thank you 

This topic has been closed for replies.

18 replies

Tesla DeLorean
Guru
October 27, 2023

Need to dump full fault context. Want to see what address it's touching or nature of fault. By the lock, assume the erase completed.

Most likely some attempt to execute code that's in the erased section, perhaps via interrupt.

https://github.com/cturvey/RandomNinjaChef/blob/main/KeilHardFault.c

On hardware side, that there's enough bulk capacitance on supply/vcap.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
TDK
October 27, 2023

Since it's not consistent, it's probably not an explicit bug in the code. Consider things like stack overflow or RTOS issues, if using one.

Could also be a power issue as Tesla suggests. Flash operations use more power and that can cause issues if your power rail is not stable or sufficient.

> SET_BIT(FLASH->CR, FLASH_CR_LOCK)

This line is harmless, shouldn't be causing any issues.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Tesla DeLorean
Guru
October 27, 2023

Something in interrupts using this data (Flash, EEPROM Emulation), and blank flash generates an ECC failure? Or this code called from interrupt/callback?

Perhaps add some interlocks around secondary access methods and this erase/initialize code. Zoom out a bit, look at the interactions, perhaps output diagnostic messages so you can see any patterns in the interactions and subsequent failure.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
sde c.1Author
Senior II
October 28, 2023

The hardware wasn't the culprit. Even after incorporating additional decoupling capacitors, the issue remained. The PCB is bustling with activity, and I utilize FreeRTOS for task management. My plan is to designate an exclusive task for erasing/writing a page, ensuring it's done when no other processes or interrupt codes are engaged. The page wipe lasts 20ms. Should I turn off interrupts during this period? It's plausible that the RS485 bus might attempt communication while the page is being wiped, and the PCB should respond.. So i prefer interrups on while wiping.

sde c.1Author
Senior II
October 29, 2023

I have stripped the code to a minimum and still got HardFault_Handler , i'm super confused about what's going on.
I removed RTOS, and run this code 4 seconds after startup, at that moment the application crashes:


	static FLASH_EraseInitTypeDef EraseInitStruct __attribute__((aligned(8)));;
	uint32_t PAGEError __attribute__((aligned(8)))=0xFFFFFFFFU;
	uint32_t StartPageAddress=0;
	volatile HAL_StatusTypeDef status;

	WritePin(ACTIVELED_OUT, 0);	// active led

	do{

	}while((FLASH->SR & FLASH_SR_BSY1));

	 /* Unlock the Flash to enable the flash control register access *************/
	 // __disable_irq();

	/* Fill EraseInit structure*/
	 EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
	 EraseInitStruct.Banks = FLASH_BANK_1 ;
	 EraseInitStruct.Page = 31;
	 EraseInitStruct.NbPages = 1;

	 /* Clear OPTVERR bit set on virgin samples */
	 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_MISERR | FLASH_FLAG_PGSERR | FLASH_FLAG_FASTERR);

	 HAL_FLASH_Unlock();
	 /* Erase the user Flash area*/

	 status = HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
	 FLASH_WaitForLastOperation(1000);
	 HAL_FLASH_Lock();
	 if (status != HAL_OK)
	 {
		 /*Error occurred while page erase.*/

		// __enable_irq();
		 return HAL_FLASH_GetError();
	 }

	 WritePin(ACTIVELED_OUT, 1);	// active led

The hardFault triggers at HAL_FLASH_Lock(); Line 31
I have captured some registers and see this :
image.png

pFlash.ErrorCode contains value = 0xe0 , and tripple checked all possible causes of the error bits (PGAERR , SIZEERR  and PGSERR ), but found nothing.

Any other idea's what i can do to find the problem?

TDK
October 29, 2023

Does it happen every time?

Does it happen when interrupts are disabled?

Look at the disassembly at and around 0x08006C8A to see the exact statement that causes the fault.

Look at other relevant registers to determine more information about the cause of the hard fault. STM32CubeIDE has a fault analyzer, would recommend using that if you are unfamiliar. See "7.2 Using the Fault Analyzer"

https://www.st.com/resource/en/user_manual/dm00629856-stm32cubeide-user-guide-stmicroelectronics.pdf

 

"If you feel a post has answered your question, please click ""Accept as Solution""."
sde c.1Author
Senior II
October 30, 2023

every time, also with irq disabled. i go trough the Fault Analyze part right now

 

Tesla DeLorean
Guru
October 29, 2023

Yes, does kind of seem like something is blocking, or breaking context in the background, and something is getting corrupted. Perhaps disable / enable interrupts at a level out here, see if you can move the failure

Have a fault handler that outputs the MCU register, both the general and those holding the faulting details. Interest to see the memory address it's failing on, not the code address, but the read/write memory address it's acting upon.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Shirley.Ye
ST Employee
October 30, 2023

please check if your program occupied the second bank of flash. If so you can not program the flash.

ShirleyYe_0-1698657776537.png

 

sde c.1Author
Senior II
October 30, 2023

The STM32G030K8 only have 1 bank

 

TDK
October 30, 2023

Hmm, I'm not sure I can help much more than what I'm writing here. I don't have a G030 board and I'll be gone for the next few weeks.

If you really need the problem solved, here's what I would do if it were my project:

  • When it hard faults, look at the hard fault to determine the root cause. STM32CubeIDE has a hard fault analyzer. You can attach a debugger to a chip in such a state without resetting it if you edit your debug/run configuration and set Startup ->Download -> False and Debugger -> Reset Behavior -> None.
  • Are you using that page of flash for anything? Consider removing that logic during debugging and see if the issue still remains. If not, it could be a program logic issue.
  • Remove all the "retry" logic from the code and only try once. Retrying multiple times should never be necessary and at worst it will mask bad behavior.
  • Consider implement a debug output that you can view without a debugger connected. I use a UART stream for this, but there are other options. This will give you better debug output than a simple LED being on/off. You can write things like "FLASH->SR=...".
  • Buy an ST board (known good hardware) and try to replicate the issue there. Perhaps the STM32G031K8T6 is the closest, but I didn't look in detail at the hardware differences. If you can't replicate it there, it could be a hardware issue. Perhaps power is insufficient or takes too long to come up. You're delaying a few seconds after startup which should eliminate this as an issue, but who knows.
"If you feel a post has answered your question, please click ""Accept as Solution""."
sde c.1Author
Senior II
October 30, 2023

Great advice ! 
1) "You can attach a debugger to a chip in such a state without resetting it".
This i did not know but can be a great help !
2) After removing the retry logic and introducing a brief delay post-initializing the SPI CS pin, I noticed the print started to work again. However, I'm puzzled as to why an SPI read attempt leads to a Hard Fault when erasing the last page, especially given that this fault appears several instructions later. I double checked the code that talks with the SPI chip, this seems oké.

// In main.c, I used this retry code to initialize the SPI interface.
// The initialization did not worked the first attempt because I attempted communication // too quickly after initializing the CS pin. After introducing a brief delay, the retry // became unnecessary, and the chip no longer enters a Hard Fault state.



 uint8_t retry=0;
 for (retry = 0; retry < 3; retry++) {
	 paccelero_handle = lis2dw12_init(&hspi2, SPI_CS) ;
		if (!paccelero_handle) {
			pApp_h->status.flags.bAcceleroError = 1;
			SetLedPattern(led_Error);
		} else {
			SetLedPattern(led_Alive);
			break;
		}
 }
lis2dw12_t *lis2dw12_init(SPI_HandleTypeDef *phspi,Pins_t cs_pin){
	lis2dw12.pSPIinterface = phspi;
	lis2dw12.cs_pin = cs_pin;
	WritePin(lis2dw12.cs_pin,1) ; //SPI mode disable
	HAL_Delay(2); // -> adding this delay solved the Hard fault at page wipe 

	if(!lis2dw12_read_device_info()){
		return 0;
	}
	return &lis2dw12;
}

3) I've incorporated USART output and added several printf statements in the code. These were the results I observed when the Hard Fault occurred. However, my limited knowledge of STM assembler and its inner mechanisms prevents me from comprehending the entire situation. I'll need more time to study and analyze this thoroughly.


R0 = 0xFFFFFFFF
R1 = 0xFFFFFFFF
R2 = 0xFFFFFFFF
R3 = 0xFFFFFFFF
R12 = 0x20000410
LR [R14] = 0x200003EC subroutine call return address
PC [R15] = 0x00000001 program counter
PSR = 0xFFFFFFF9
ICSR = 0x0440F003
AIRCR = 0xFA050000
SCR = 0x00000000
CCR = 0x00000208
SHCSR = 0x00000000





 

Pavel A.
October 30, 2023

LR [R14] = 0x200003EC subroutine call return address

Does your code run in the RAM?

 

sde c.1Author
Senior II
October 31, 2023

no