2020-03-19 02:33 AM
Hello,
I tried to store data to flash on a STM32H742 (running at 480MHz) and I have some timing issues. Meanwhile I found myself a workaround that I also want to share here. Still I would like to ask some questions to better understand whats going on, or maybe get a better solution if someone knows one.
I have only ten int32-values, I want to store in flash. To keep the impact on timing as small as possible I defined an array "logging_array" where I store data while my code is running and when it is finished I send them over UART to a terminal. Mostly I store FLASH->SR2 because I store in bank2 and want to see which bits are set.
I use these defines:
#define SetBitMask(Var,BitMask) (Var|=(BitMask))
#define ClearBitMask(Var,BitMask) (Var&=~(BitMask))
#define BitMaskIsSet(Var,BitMask) ((Var&(BitMask))==(BitMask))
#define BitMaskIsClear(Var,BitMask) ((Var&(BitMask))==0)
Here is my code:
int32_t* var_ptr;
int32_t* flash_ptr;
int32_t n;
int32_t k;
uint32_t logging_array [50];
uint32_t* array_ptr = &logging_array [0];
if (BitMaskIsSet (FLASH->SR2, FLASH_SR_BSY))
{ // return error, when write or erase is still ongoing
return (error_case);
}
// sector erase of sector 0 in bank 2:
// clear all error bits in case one is set:
SetBitMask (FLASH->CCR2, FLASH_CCR_CLR_WRPERR | FLASH_CCR_CLR_PGSERR | FLASH_CCR_CLR_STRBERR | FLASH_CCR_CLR_INCERR
| FLASH_CCR_CLR_OPERR| FLASH_CCR_CLR_RDPERR | FLASH_CCR_CLR_RDSERR | FLASH_CCR_CLR_SNECCERR
| FLASH_CCR_CLR_DBECCERR | FLASH_CCR_CLR_CRCEND | FLASH_CCR_CLR_CRCRDERR);
// check if FLASH-CR2 is locked and unlock it
if (BitMaskIsSet (FLASH->CR2, FLASH_CR_LOCK))
{ // then unlock it:
FLASH->KEYR2 = 0x45670123;
FLASH->KEYR2 = 0xCDEF89AB;
}
// select an erase of sector 0 in bank 2 and start it
FLASH->CR2 = FLASH_CR_PSIZE; // select max parallelism, clear all other bits, = esp select sector 0
SetBitMask (FLASH->CR2, FLASH_CR_SER); // select sector erase
SetBitMask (FLASH->CR2, FLASH_CR_START);
while (BitMaskIsSet (FLASH->SR2, FLASH_SR_BSY))
{ // sector erase takes 1.8 to 4 sec
vTaskDelay (pdMS_TO_TICKS (50)); // using FreeRTOS
}
FLASH->CR2 = FLASH_CR_PSIZE; // select max parallelism, clear all other bits
SetBitMask (FLASH->CR2, FLASH_CR_PG); // select programming
flash_ptr = (int32_t*)(data_flash_start_address); // data_flash_start_address = 0x08100000 // start address of sector 0 of flash bank 2
for (n = 0; n < Task_IF_Rx_Flash_data_size; )
{
*array_ptr++ = FLASH->SR2; // #1
var_ptr = Task_IF_Rx_Flash_data [n].var_adr;
*flash_ptr = *var_ptr;
*array_ptr++ = FLASH->SR2; // #2
flash_ptr++;
n++;
if ((n % 8) == 0)
{ // write buffer is full => programming starts automatically, check QW is set, then wait till it is cleared
*array_ptr++ = FLASH->SR2; // #3
k = 0;
while (BitMaskIsClear (FLASH->SR2, FLASH_SR_QW))
{
k++;
if (k >= 1000000) break;
}
*array_ptr++ = k; // #4
*array_ptr++ = FLASH->SR2; // #5
k = 0;
while (BitMaskIsSet (FLASH->SR2, FLASH_SR_QW))
{
k++;
if (k >= 1000000) break;
}
*array_ptr++ = k; // #6
*array_ptr++ = FLASH->SR2; // #7
if (check_program_success (n - 8, 8) == -1)
{
SetBitMask (FLASH->CR2, FLASH_CR_LOCK);
return (error_case);
}
}
}
*array_ptr++ = FLASH->SR2; // #8
if ((n % 8) != 0)
{ // then less than 8 int32 have been given => fill the rest with 0xFFFFFFFF
int32_t m = n;
while ((m % 8) != 0)
{
*array_ptr++ = FLASH->SR2; // #9
*flash_ptr = 0xFFFFFFFF;
flash_ptr++;
m++;
*array_ptr++ = FLASH->SR2; // #10
}
// here: (n % 8) == 0 ie.write buffer is full => programming starts automatically, check QW is set, then wait till it is cleared
*array_ptr++ = FLASH->SR2; // #11
k = 0;
while (BitMaskIsClear (FLASH->SR2, FLASH_SR_QW))
{
k++;
if (k >= 1000000) break;
}
*array_ptr++ = k; // #12
*array_ptr++ = FLASH->SR2; // #13
k = 0;
while (BitMaskIsSet (FLASH->SR2, FLASH_SR_QW))
{
k++;
if (k >= 1000000) break;
}
*array_ptr++ = k; // #14
*array_ptr++ = FLASH->SR2; // #15
if (check_program_success (n - (n % 8), n % 8) == -1)
{
SetBitMask (FLASH->CR2, FLASH_CR_LOCK);
return (error_case);
}
}
*array_ptr++ = FLASH->SR2; // #16
SetBitMask (FLASH->CR2, FLASH_CR_LOCK);
*array_ptr++ = FLASH->SR2; // #17
array_ptr = &logging_array [0];
vTaskDelay (pdMS_TO_TICKS (10));
while (array_ptr < &logging_array [50])
{
Sende_uint32_Hex_to_UART (UART_DBG, *array_ptr++, output_with_0x);
Sende_Zeichen_to_UART (UART_DBG, '\r');
Sende_Zeichen_to_UART (UART_DBG, '\n');
vTaskDelay (pdMS_TO_TICKS (1));
}
Here are the results from logging_array:
position current data stored variable value bits set in SR2
#1 1 FLASH->SR2 0x010000 EOP
#2 1 FLASH->SR2 0x010000 EOP
#1 2 FLASH->SR2 0x010000 EOP
#2 2 FLASH->SR2 0x010000 EOP
#1 3 FLASH->SR2 0x010000 EOP
#2 3 FLASH->SR2 0x010002 EOP, WBNE
#1 4 FLASH->SR2 0x010002 EOP, WBNE
#2 4 FLASH->SR2 0x010002 EOP, WBNE
#1 5 FLASH->SR2 0x010002 EOP, WBNE
#2 5 FLASH->SR2 0x010002 EOP, WBNE
#1 6 FLASH->SR2 0x010002 EOP, WBNE
#2 6 FLASH->SR2 0x010002 EOP, WBNE
#1 7 FLASH->SR2 0x010002 EOP, WBNE
#2 7 FLASH->SR2 0x010002 EOP, WBNE
#1 8 FLASH->SR2 0x010002 EOP, WBNE
#2 8 FLASH->SR2 0x010002 EOP, WBNE
#3 FLASH->SR2 0x010002 EOP, WBNE
#4 k 0x04 = 4d
#5 FLASH->SR2 0x010005 EOP, QW, BSY
#6 k 0x0B0F = 2831d
#7 FLASH->SR2 0x010000 EOP
#1 9 FLASH->SR2 0x010000 EOP
#2 9 FLASH->SR2 0x010000 EOP
#1 10 FLASH->SR2 0x010000 EOP
#2 10 FLASH->SR2 0x010000 EOP
#8 FLASH->SR2 0x010000 EOP
#9 11 FLASH->SR2 0x010000 EOP
#10 11 FLASH->SR2 0x010000 EOP
#9 12 FLASH->SR2 0x010002 EOP, WBNE
#10 12 FLASH->SR2 0x010002 EOP, WBNE
#9 13 FLASH->SR2 0x010002 EOP, WBNE
#10 13 FLASH->SR2 0x010002 EOP, WBNE
#9 14 FLASH->SR2 0x010002 EOP, WBNE
#10 14 FLASH->SR2 0x010002 EOP, WBNE
#9 15 FLASH->SR2 0x010002 EOP, WBNE
#10 15 FLASH->SR2 0x010002 EOP, WBNE
#9 16 FLASH->SR2 0x010002 EOP, WBNE
#10 16 FLASH->SR2 0x010002 EOP, WBNE
#11 FLASH->SR2 0x010005 EOP, QW, BSY
#12 k 0x00
#13 FLASH->SR2 0x010005 EOP, QW, BSY
#14 k 0x0463 = 1123d
#15 FLASH->SR2 0x010000 EOP
#16 FLASH->SR2 0x010000 EOP
#17 FLASH->SR2 0x010000 EOP
You can see two timing issues:
Questions:
Are there any reasons for these latencies? What can I do to surely see WBNE set when it should be there.
Hope this helps and thanks for any answers
Martin
2020-03-19 02:36 AM
kindly pushing this up again
Martin
2020-03-19 09:52 AM
What is WBNE and how is it calculated?
It's possible things are held in the cache and only flushed to flash when necessary.