cancel
Showing results for 
Search instead for 
Did you mean: 

Error Code Writing to FLASH On STM32L496

jvavra
Associate III

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?

11 REPLIES 11

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

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

> 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.

If you feel a post has answered your question, please click "Accept as Solution".
jvavra
Associate III

I should clarify: I am performing an erase before the subsequent write to FLASH.

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
She the full code relevant to your situation. Rehashing HAL code isn’t helpful, it’s the user code here which is unknown and more likely to be the issue. Do a check before writing to ensure all bytes are 0xFF.
If you feel a post has answered your question, please click "Accept as Solution".
jvavra
Associate III
/*******************************************************************************
* 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).

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

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

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 );
}

jvavra
Associate III

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).