2022-04-11 09:03 AM
I have a project based on the L496. The application does a few writes to FLASH. The initial write works correctly, however subsequent writes fail. The code is directly from STCube:
/**
* @brief Wait for a FLASH operation to complete.
* @param Timeout maximum flash operation timeout
* @retval HAL_StatusTypeDef HAL Status
*/
HAL_StatusTypeDef FLASH_WaitForLastOperation(uint32_t Timeout)
{
/* Wait for the FLASH operation to complete by polling on BUSY flag to be reset.
Even if the FLASH operation fails, the BUSY flag will be reset and an error
flag will be set */
uint32_t tickstart = HAL_GetTick();
uint32_t error;
while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY))
{
if(Timeout != HAL_MAX_DELAY)
{
if((HAL_GetTick() - tickstart) >= Timeout)
{
return HAL_TIMEOUT;
}
}
}
error = (FLASH->SR & FLASH_FLAG_SR_ERRORS);
if(error != 0u) //Error code is 0xA8
{
/*Save the error code*/
pFlash.ErrorCode |= error;
/* Clear error programming flags */
__HAL_FLASH_CLEAR_FLAG(error);
return HAL_ERROR;
}
/* Check FLASH End of Operation flag */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP))
{
/* Clear FLASH End of Operation pending bit */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
}
/* If there is an error flag set */
return HAL_OK;
}
Some Googling mentions this error code may be related to trying to access a FLASH location that hasn't been cleared. However, in checking the contents at this address, memory shows it's filled with FFFFs as expected.
Anyone have any idea what the problem could be?
2022-04-11 09:21 AM
Correct needs to be erased, you get one shot at writing, can't rewrite even if you wrote 0xFFFFFFFF in the initial pass.
Check ALIGNMENT and WIDTH expectations of the array, as flash lines are wide and have ECC bits associated with them
2022-04-11 09:47 AM
> The initial write works correctly, however subsequent writes fail.
That's how flash works. You only get one shot. To write again, you need to erase first.
2022-04-11 10:15 AM
I should clarify: I am performing an erase before the subsequent write to FLASH.
2022-04-11 10:35 AM
Ok, but showing me library code imparts no actual detail of YOUR methods, and how it's failing.
Top of my head I can't tell you specific about the L496, but you might need to be doing 8-byte/64-bit aligned/wide operations.
Instrument your code to provide telemetry and diagnostic information about addresses, before content, error/status returns, etc. Run it without the debugger, or single-stepping, as that will just introduce a whole lot of it's own complications.
2022-04-11 10:57 AM
2022-04-11 01:11 PM
/*******************************************************************************
* Function Name : FlashWrite
* Description : Writes wordcnt words from rptr to StartAddr
* Input : src pointer, dest pointer, count (32).
* Output : None.
* Return : None.
*******************************************************************************/
u8 FlashWrite(u32 StartAddr, u32 wordcnt, u32* rptr32 )
{
u64 * wptr;
u64 * rptr;
u8 retval = TRUE;
u32 i;
u64 n;
wptr = (u64*)StartAddr;
rptr = (u64*) rptr32;
if ( wordcnt & 1 ) //even number
wordcnt++;
u32 dwordcnt = wordcnt / 2;
HAL_FLASH_Unlock();
for (i = 0; i < dwordcnt; i++ )
{
/* Clear pending flags (if any) */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |\
FLASH_FLAG_PGAERR | FLASH_SR_PGSERR);
n = rptr[i];
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, (u32)&wptr[i], n) != HAL_OK)
{
retval = FALSE;
break;
}
}
/* Check the correctness of written data */
if (retval == TRUE )
{
for (i = 0; i < dwordcnt; i++ )
{
if( wptr[i] != rptr[i])
{
retval = FALSE;
break;
}
}
}
HAL_FLASH_Lock();
return retval;
}
Here's my generic FLASH write routine, which then calls HAL_Flash_Program (which in turn calls FLASH_WaitForLastOperation where the error gets noted).
2022-04-11 01:46 PM
Addresses are NOT checked for 8-byte / 64-bit alignment
Nor if the target address is blank
Output diagnostic data so you can see progress/failure hands-free
I'd move the flag clearing outside of the loop
2022-04-12 07:41 AM
Sorry, I forgot an important function that does the alignment:
/*******************************************************************************
* Function Name : WriteParamBlock
* Description : Writes the params image struct to the params sector
* Input :
* Output : None.
* Return : None.
*******************************************************************************/
#pragma optimize=none
u8 WriteParamBlock( u8 block, u32 rev_and_sum)
{
u32 len32;
u32 pages;
u8 i;
//point to rom image
PARAM_BLOCK_IMAGE_STRUCT * romptr = (PARAM_BLOCK_IMAGE_STRUCT *)(PARAMS_BASE_ADDRESS);
//use a temp area for ram image
PARAM_BLOCK_IMAGE_STRUCT * image = (PARAM_BLOCK_IMAGE_STRUCT *)(&g_uSort);
// get an even 32bit length
len32 = sizeof(PARAM_BLOCK_IMAGE_STRUCT); //1649 bytes at last check
pages = len32/CODE_PAGE_SIZE;
if ( len32 % CODE_PAGE_SIZE )
pages++;
if ( len32 % 4)
{
len32 /= 4;
len32++;
}
else
{
len32 /= 4;
}
//copy existing flash image to temp param image
*image = *romptr;
//overlay image with new block data
switch (block)
{
case 1:
image->blk1 = g_blk1;
image->blk1_rev_and_sum = rev_and_sum;
break;
case 5:
image->blk5 = g_blk5;
image->blk5_rev_and_sum = rev_and_sum;
break;
case 6:
image->blk6 = g_blk6;
image->blk6_rev_and_sum = rev_and_sum;
break;
case 7:
//uses temp area for new block7
*((BLOCK7_STRUCT*)&image->blk7) = *((BLOCK7_STRUCT*)&g_uComp);
image->blk7_rev_and_sum = rev_and_sum;
break;
case 8:
//uses temp area for new block8
*((BLOCK8_STRUCT*)&image->blk8) = *((BLOCK8_STRUCT*)&g_uComp);
image->blk8_rev_and_sum = rev_and_sum;
break;
}
for ( i = 0; i < pages; i++ )
ErasePage( PARAMS_BASE_PAGE+i );
return FlashWrite( PARAMS_BASE_ADDRESS, len32, (u32*)image );
}
2022-04-12 09:38 AM
How untrustworthy would anyone categorize the Memory window in my compiler (IAR)? I finally noticed that the ErasePage function isn't actually erasing anything (or doesn't appear to be). I have another board that uses the STM32L432 (virtually identical FLASH), and it works fine: any previously written memory locations are written with 0xFFFFFFFF before trying to write the desired data. However, on the board in question, the memory doesn't appear to change. No flags are thrown during this section, only when I then try to write the new data to it (which makes the other error codes I reported make sense).