2021-01-25 10:38 AM
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*) ¤tConfig, 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 ! =)
2021-01-25 11:34 AM
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.
2021-01-25 12:03 PM
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
2021-01-25 01:29 PM
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.
2021-01-25 02:10 PM
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
2021-01-25 02:49 PM
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.
2021-01-25 03:07 PM
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
2021-01-25 10:47 PM
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;
}
2021-01-26 08:51 AM
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)
I have tried in two different way, with same issue :
In both case, only 0x0 are written in Flash at the specified address
2021-01-26 09:43 AM
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...