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-26 10:58 AM
My code comes from HAL lib examples. What could be less standard than the lib provided by ST for a 2020 microcontroller ?
I added this line because the HAL seems to forget to set this bit before to start programming in Flash.
SET_BIT(FLASH->SR, FLASH_SR_PGSERR);
I will try with the FLASH_x, functions, like you said... but where is the doc for them ?
What is the difference with the HAL_FLASH functions ?
EDIT:
HAL_FLASH_Program() calls internally FLASH_Program_DoubleWord()
So I don't have hope that will change something to my issue
EDIT EDIT :
FLASH_Program_DoubleWord() is private. So, try to call it is definitively not the right way to solve it
2021-01-26 11:30 AM
Something else to make the problem clearer :
If I try to call the following function (one line different from the first post), in my ISR, it works !
bool Config::saveConfigFlash(){
uint32_t pageError;
FLASH_EraseInitTypeDef pEraseInit;
pEraseInit.Banks = FLASH_BANK_2;
pEraseInit.NbPages = 1;
pEraseInit.Page = 127;
pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
//data is uint64_t array
//currentConfig is the struct I want to save in Flash
static uint64_t data[1 + sizeof(TerrariumConfig)/sizeof(uint64_t)];
//memcpy(data, (void*) ¤tConfig, sizeof(TerrariumConfig));
strcpy((char*)data, "my data");
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;
}
It is like a cannot retrieve my real data
2021-01-26 11:34 PM
I write you need add
if(status ...) not only fake status =
and locate what dont work. and in HAL
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP|FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR | FLASH_FLAG_PGPERR | FLASH_FLAG_BSY);
helps better.
EDIT:
and yes memcpy use with uint64 mayby is bad idea... your calculate size for data different as for memcopy, then memcopy check oversized copy over data and do nothing.
2021-01-27 03:17 AM
Hello,
Could you please develop what you said about memcpy ? I am not sure to understand what you wrote
2021-01-27 03:49 AM
static uint64_t data[1 + sizeof(TerrariumConfig)/sizeof(uint64_t)];
for example sizeof terrarium is 57 bytes , then this create aaray data with (1+57/8) eq 8 elements u64
then
memcpy(data, (void*) ¤tConfig, sizeof(TerrariumConfig));
determine type data and try copy 57 u64 from source, but dest is only 8 this i mean is compared in lib and func do nothing, return error.
2021-01-27 04:23 AM
Clearing FLASH_FLAG_BSY bit is again a nonsense. It cannot be cleared and it doesn't need to be cleared. A good example of why the reference manual must be read even if using the HAL bloatware.
As for array size:
https://stackoverflow.com/questions/2745074/fast-ceiling-of-an-integer-division-in-c-c
2021-01-27 08:44 AM
memcpy(destination, source, N);
N is a number of bytes, we don't care if destination is an uint64_t* or whatever
2021-01-27 09:57 AM
I am still stuck on this problem which drives me crazy.
The STM32 receives instructions from UART. One of these allows to save the data in Flash, just like I try to do :
//run in main context
void Communication::readFrames() {
//other stuff before
INSTRUCTION_SET cmd = (INSTRUCTION_SET) mListComFrame[mIndexListComFrame].cmd;
if(cmd == SAVE_STM32_CONFIG){
Config::saveConfigFlash();
}
//other stuf
}
It is exactly the same function as the first post, and it works. Unbelievable !
Why this does not work anymore from my interrupt ? (Or if I set a flag from the ISR triggered by ADC's watchdog, and then write in Flash from main)
According to your link @Piranha , I have changed the function to this, but without solving the problem :
bool Config::saveConfigFlash(){
uint32_t pageError;
FLASH_EraseInitTypeDef pEraseInit;
pEraseInit.Banks = FLASH_BANK_2;
pEraseInit.NbPages = 1;
pEraseInit.Page = 127;
pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
//data is uint64_t array
//currentConfig is the struct I want to save in Flash
const uint8_t lenData = sizeof(TerrariumConfig)/sizeof(uint64_t) + (sizeof(TerrariumConfig) % sizeof(uint64_t) != 0);
uint64_t* data = (uint64_t*) ¤tConfig;
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 < lenData; i++)
{
//write the data, with 64bit alignment
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addressDataFlash + i*8, *data);
data++;
}
HAL_FLASH_Lock();
return true;
}
2021-01-27 10:41 AM
To make it 100% clear: does this saveConfigFlash() function erase the flash page, or it does not?
If it still does erase, after all discussions above - this is self-inflicted trouble.
> What could be less standard than the lib provided by ST for a 2020 microcontroller ?
A lib provided by ST for a 2021 microcontroller =)
-- pa
2021-01-27 10:51 AM
Realy strange, sorry for memcpy i mean sizet is used here, but yes c++ say bytes here =)
Go back to scope where you place toggle pin. Try toggle before erase after erase and on every for write.
Too good is debug this with simulate power down without real power down and trace erase and flash func returned status.