cancel
Showing results for 
Search instead for 
Did you mean: 

Write data to flash when power supply drops

ATurp.11
Associate II

Hello,

I am using a STM32G473VET6 on my board, and I want to save a few data bytes in Flash when the 24V power supply drops. I have more than 400ms available between the detection by the MCU and the 3.3V dropping.

When the ADC triggers this event, the associated ISR try to write the data in Flash. The HAL functions don't seem to return any kind of error, but the only thing I can see inside the memory is a set of 0x0 at the programmed addresses.

But there is something else strange : if my function is called in another way, from code, the write in Flash is working successfully.

If I manually set the content of my @data, it works

It is like a cannot retrieve the content of @data from the ISR.

@data is declared as a static uint64_t array of my class

Here, the function called from the ADC ISR when a power down event occurs :

bool Config::writeFlash(){
 
	uint32_t pageError;
	static FLASH_EraseInitTypeDef pEraseInit;
	pEraseInit.Banks = FLASH_BANK_2;
	pEraseInit.NbPages = 1;
	pEraseInit.Page = 3;
	pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
 
	//data is uint64_t array
	//currentConfig is the struct I want to save in Flash
	memcpy(data, (void*) &currentConfig, sizeof(TerrariumConfig));
 
	HAL_StatusTypeDef status = HAL_FLASH_Unlock();
	SET_BIT(FLASH->SR, FLASH_SR_PGSERR);
 
	status = HAL_FLASHEx_Erase(&pEraseInit, &pageError);
 
 
	for(unsigned int i = 0; i < 1 + sizeof(TerrariumConfig)/sizeof(uint64_t); i++)
	{
		//write the data, with 64bit alignment 
		status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addressDataFlash + i*8, data[i]);
 
	}
 
	FLASH_FlushCaches();
	HAL_FLASH_Lock();
 
	return true;
 
}

 The write attempt occurs only once. Once done, ADC ISR are disabled.

To sum up, I can use the function above to write in flash when it is called from main program, but from ADC ISR, it doesn't work

Do you have any idea of the problem ?

Thank you ! =)

22 REPLIES 22
MM..1
Chief

Why you dont write it in main loop and in ISR set only bool marker for example powerfail=1 ?

Seems as HAL_FLASh function need own isr use and cant be called simply in other isr.

ATurp.11
Associate II

I have just tried, and the problem is the same :tired_face:

If I short circuit the bottom resistor from the voltage divider used to measure the 24V power supply, the flash is written. It is like there is not enough time to write in it

Do you have to erase the flash or is it pre-erased. Erasing flash can take a significant amount of time. On some flash parts it takes 1 second per sector. I have no idea how long it takes on your particular processor. Just a thought.

ATurp.11
Associate II

Thanks for your answer. From my human flash memory, I remember I measured between​ 30 and 35ms to perform a page erasing and the writting.

The 3.3V was still here for the next 430ms​

Don't erase every time, journal the writes across the span of the sector so you don't have to erase frequently.

Interrupts have issues with SysTick priority, and dependency on HAL_Tick and timeouts.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
ATurp.11
Associate II

I will try to write directly on empty space. I agree with what you said. Writting in flash won't happen often, only when the board is power off. Should be almost never. It's just to prevent grid power cut​.

I don't use interrupt to erase or write in flash​

MM..1
Chief

I dont see unlock in your code and too check moment for your interrupt with gpio toggle. Too ADC is converter or comparator? When converter , how interrupt you use ???

Example code for virtual eeprom in flash:

EepromStatus_t EE_Format( void ) {
 
	EepromStatus_t status = EE_SUCCESS;
	
	FLASH_Unlock();
	if( FLASH_ErasePage( EEPROM_START_ADDRESS ) != FLASH_COMPLETE )
		status = EE_ERASE_FAILED;
	FLASH_Lock();
	
	return status;
	
}

ATurp.11
Associate II

As requested, here more details about the code. The ADC is configured with ADC watchdog and an interrupt is triggered only when a converted value is outside the defined window. This works very well.

Below, the interrupt part.

void ADC5_IRQHandler(void){
	HAL_ADC_IRQHandler(&UVLO::hadc5);
}
 
 
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef *hadc){
 
 
	if(hadc->Instance == ADC5)
	{
		HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_RESET);
		Interrupt::UVLO_ADC_Watchdog_ISR(); //will call the function shown in the first post
		HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET);
	}
}
 

My project is in C++, so there are some stuff to retrieve the initial context from the interrupt, but I finally call the function Config::writeFlash()

I used the GPIO to measure the elapsed time to write in Flash. It is pretty quick. I have much time left before BOR.

(yellow : VDD, purple: the GPIO voltage)

0693W000007CkWeQAK.png 

I have tried in two different way, with same issue :

  • write in flash from the ISR
  • Set a flag in the ISR and write in Flash from main loop

In both case, only 0x0 are written in Flash at the specified address

MM..1
Chief

Your code isnt standart , in my eeprom old lib is

if( FLASH_ProgramHalfWord( ( uint32_t )ptr, data16b ) != FLASH_COMPLETE )

then code check status is ok and report problem, too pointer to place is explicit uint32_t, you dont show addressDataFlash type or def

and too i in my code dont see

SET_BIT(FLASH->SR, FLASH_SR_PGSERR);

normal code do unlock ... erasepage ... lock ... prepare ... unlock ... write ...lock

and more better is use an append technique instead erase everytime.

Try if your code and for error toggle gpio, Then locate error in debug...