cancel
Showing results for 
Search instead for 
Did you mean: 

Flash erase is unreliable on STM32H743 (Code Provided)

AAgar.2
Associate III

Hello All,

I am working with an STM32H743 and am having issues reliably erasing flash (unreliable in that it fails ~95% of the time). The code which erases flash runs from RAM (functions are allocated in RAM). I disable many of the interrupts before entering the code. I am also invalidating the data cache after erasing the application.

 

Essentially the code executes without any errors reported. However, afterwards when I connect to STLINK Utility and read the memory contents, some of the sectors are not erased, which were intended to be erased.

 

Couple of points and observations:

-> Erasing takes maybe 30 to 40 seconds

-> If I do not disable interrupts then while erase code is running I get a hard fault because the Systick interrupt fired.

What is going on here or what am I missing? Appreciate your insights on how to resolve this. A means of debugging the issue would be helpful as well. 

Reference manual for this MCU is linked at the bottom of the page.

--------------------------------------------------------------------------------

Below is the starting point for the erasing flash code.

Note I disable the interrupts with priority >= 1. 

Interrupt priority listing is available at the bottom of the page.

// Disable interrupts
__set_BASEPRI(0001 << __NVIC_PRIO_BITS);
 
// Erase flash
erase_flash();
 
// Invalidate data cache
SCB_InvalidateDCache();
 
// Enable interrupts
__set_BASEPRI(0);

--------------------------------------------------------------------------------

Here are the function calls which contain the erase code.

#define __RAM_FUNC __attribute__((section(".RamFunc")))
 
__RAM_FUNC tsb_err_t erase_flash()
{
	// Setup to erase last 5 sectors of bank 1
	uint32_t error_bank_1 = 0;
	FLASH_EraseInitTypeDef erase_conf_bank_1;
	erase_conf_bank_1.TypeErase = FLASH_TYPEERASE_SECTORS;
	erase_conf_bank_1.Banks     = FLASH_BANK_1;
	erase_conf_bank_1.Sector    = FLASH_SECTOR_3;
	erase_conf_bank_1.NbSectors = 5;
	erase_conf_bank_1.VoltageRange = FLASH_CR_PSIZE_1;
 
	// Setup to erase base 2
	uint32_t error_bank_2 = 0;
	FLASH_EraseInitTypeDef erase_conf_bank_2;
	erase_conf_bank_2.TypeErase = FLASH_TYPEERASE_SECTORS;
	erase_conf_bank_2.Banks     = FLASH_BANK_2;
	erase_conf_bank_2.Sector    = FLASH_SECTOR_0;
	erase_conf_bank_2.NbSectors = 8;
	erase_conf_bank_2.VoltageRange = FLASH_CR_PSIZE_1;
 
	// Unlock Flash
	if (RAM_FLASH_Unlock() != HAL_OK) { goto error; }
 
	// Erase flash
	if (RAM_FLASHEx_Erase(&erase_conf_bank_1, &error_bank_1) != HAL_OK) { goto error; }
	if (RAM_FLASHEx_Erase(&erase_conf_bank_2, &error_bank_2) != HAL_OK) { goto error; }
 
	// Lock Flash
	if (RAM_FLASH_Lock() != HAL_OK) { goto error; }
 
	return TSB_OK;
error:
	RAM_FLASH_Lock();
	return TSB_ERR_FLASH_ERASE;
}
 
 
__RAM_FUNC HAL_StatusTypeDef RAM_FLASH_Unlock(void)
{
	if(READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)
	{
		/* Authorize the FLASH Bank1 Registers access */
		WRITE_REG(FLASH->KEYR1, FLASH_KEY1);
		WRITE_REG(FLASH->KEYR1, FLASH_KEY2);
 
		/* Verify Flash Bank1 is unlocked */
		if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) != 0U)
			return HAL_ERROR;
	}
 
	if(READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
	{
		/* Authorize the FLASH Bank2 Registers access */
		WRITE_REG(FLASH->KEYR2, FLASH_KEY1);
		WRITE_REG(FLASH->KEYR2, FLASH_KEY2);
 
		/* Verify Flash Bank2 is unlocked */
		if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) != 0U)
			return HAL_ERROR;
	}
 
	return HAL_OK;
}
 
__RAM_FUNC HAL_StatusTypeDef RAM_FLASH_Lock(void)
{
	/* Set the LOCK Bit to lock the FLASH Bank1 Control Register access */
	SET_BIT(FLASH->CR1, FLASH_CR_LOCK);
 
	/* Verify Flash Bank1 is locked */
	if (READ_BIT(FLASH->CR1, FLASH_CR_LOCK) == 0U)
		return HAL_ERROR;
 
	/* Set the LOCK Bit to lock the FLASH Bank2 Control Register access */
	SET_BIT(FLASH->CR2, FLASH_CR_LOCK);
 
	/* Verify Flash Bank2 is locked */
	if (READ_BIT(FLASH->CR2, FLASH_CR_LOCK) == 0U)
		return HAL_ERROR;
 
	return HAL_OK;
}
 
__RAM_FUNC HAL_StatusTypeDef RAM_FLASH_WaitForLastOperation(uint32_t Timeout, uint32_t bank)
{
  if ((bank != FLASH_BANK_1) && (bank != FLASH_BANK_2)) { return HAL_ERROR; }
 
  if (bank == FLASH_BANK_1)
  {
	  uint32_t errorflag = FLASH->SR1 & FLASH_FLAG_ALL_ERRORS_BANK1;
 
 
	  while (FLASH->SR1 & FLASH_FLAG_QW_BANK1) {}
 
	  /* In case of error reported in Flash SR1 or SR2 register */
	  if((errorflag & 0x7FFFFFFFU) != 0U)
	  {
	    /*Save the error code*/
	    pFlash.ErrorCode |= errorflag;
 
	    /* Clear error programming flags */
	    FLASH->CCR1 = errorflag;
 
	    return HAL_ERROR;
	  }
 
	  if (FLASH->SR1 & FLASH_FLAG_EOP_BANK1)
	  {
		  FLASH->SR1 = FLASH_FLAG_EOP_BANK1;
	  }
  }
  else if (bank == FLASH_BANK_2)
  {
	  uint32_t errorflag = FLASH->SR2 & FLASH_FLAG_ALL_ERRORS_BANK2;
 
	  while (FLASH->SR2 & FLASH_FLAG_QW_BANK2) {}
 
	  /* In case of error reported in Flash SR1 or SR2 register */
	  if((errorflag & 0x7FFFFFFFU) != 0U)
	  {
	    /*Save the error code*/
	    pFlash.ErrorCode |= errorflag;
 
	    /* Clear error programming flags */
	    FLASH->CCR2 = errorflag;
 
	    return HAL_ERROR;
	  }
 
	  if (FLASH->SR2 & FLASH_FLAG_EOP_BANK2)
	  {
		  FLASH->SR2 = FLASH_FLAG_EOP_BANK2;
	  }
  }
 
  return HAL_OK;
}
 
 
__RAM_FUNC void RAM_FLASH_Erase_Sector(uint32_t Sector, uint32_t Banks, uint32_t VoltageRange)
{
  assert_param(IS_VOLTAGERANGE(VoltageRange));
 
  if((Banks & FLASH_BANK_1) == FLASH_BANK_1)
  {
    /* Reset Program/erase VoltageRange and Sector Number for Bank1 */
    FLASH->CR1 &= ~(FLASH_CR_PSIZE | FLASH_CR_SNB);
 
    FLASH->CR1 |= (FLASH_CR_SER | VoltageRange | (Sector << FLASH_CR_SNB_Pos) | FLASH_CR_START);
  }
 
  if((Banks & FLASH_BANK_2) == FLASH_BANK_2)
  {
    /* Reset Program/erase VoltageRange and Sector Number for Bank2 */
    FLASH->CR2 &= ~(FLASH_CR_PSIZE | FLASH_CR_SNB);
 
    FLASH->CR2 |= (FLASH_CR_SER | VoltageRange  | (Sector << FLASH_CR_SNB_Pos) | FLASH_CR_START);
  }
}
 
__RAM_FUNC HAL_StatusTypeDef RAM_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *SectorError)
{
  HAL_StatusTypeDef status = HAL_OK;
  uint32_t sector_index;
 
  /* Check the parameters */
  assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));
  assert_param(IS_FLASH_BANK(pEraseInit->Banks));
 
  /* Process Locked */
  __HAL_LOCK(&pFlash);
 
  /* Reset error code */
  pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
 
  /* Wait for last operation to be completed on Bank1 */
  if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
  {
    if(RAM_FLASH_WaitForLastOperation((uint32_t)50000U, FLASH_BANK_1) != HAL_OK)
    {
      status = HAL_ERROR;
    }
  }
 
#if defined (DUAL_BANK)
  /* Wait for last operation to be completed on Bank2 */
  if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
  {
    if(RAM_FLASH_WaitForLastOperation((uint32_t)50000U, FLASH_BANK_2) != HAL_OK)
    {
      status = HAL_ERROR;
    }
  }
#endif /* DUAL_BANK */
 
  if(status == HAL_OK)
  {
      /*Initialization of SectorError variable*/
      *SectorError = 0xFFFFFFFFU;
 
      /* Erase by sector by sector to be done*/
      for(sector_index = pEraseInit->Sector; sector_index < (pEraseInit->NbSectors + pEraseInit->Sector); sector_index++)
      {
        RAM_FLASH_Erase_Sector(sector_index, pEraseInit->Banks, pEraseInit->VoltageRange);
 
        if((pEraseInit->Banks & FLASH_BANK_1) == FLASH_BANK_1)
        {
          /* Wait for last operation to be completed */
          status = RAM_FLASH_WaitForLastOperation((uint32_t)50000U, FLASH_BANK_1);
 
          /* If the erase operation is completed, disable the SER Bit */
          FLASH->CR1 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
        }
#if defined (DUAL_BANK)
        if((pEraseInit->Banks & FLASH_BANK_2) == FLASH_BANK_2)
        {
          /* Wait for last operation to be completed */
          status = RAM_FLASH_WaitForLastOperation((uint32_t)50000U, FLASH_BANK_2);
 
          /* If the erase operation is completed, disable the SER Bit */
          FLASH->CR2 &= (~(FLASH_CR_SER | FLASH_CR_SNB));
        }
#endif /* DUAL_BANK */
 
        if(status != HAL_OK)
        {
          /* In case of error, stop erase procedure and return the faulty sector */
          *SectorError = sector_index;
          break;
        }
      }
  }
 
  /* Process Unlocked */
  __HAL_UNLOCK(&pFlash);
 
  return status;
}

 --------------------------------------------------------------------------------

Here is the listing of the NVIC:

0693W00000KaJoHQAV.png 

--------------------------------------------------------------------------------

Reference Manual:

https://www.st.com/resource/en/reference_manual/dm00314099-stm32h742-stm32h743-753-and-stm32h750-value-line-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf

11 REPLIES 11

0693W00000KagObQAJ.png 

Once I enabled WRP. I am getting the hard fault above on the SCB_CleanDCache() execution. Note the sectors which are being erased do not have WRP. But where this code is executing from does have WRP.

I would assume the next step is to use SCB_CleanDCache_by_Addr().

The function description for this method is below for reference.

/**
  \brief   D-Cache Clean by address
  \details Cleans D-Cache for the given address
           D-Cache is cleaned starting from a 32 byte aligned address in 32 byte granularity.
           D-Cache memory blocks which are part of given address + given size are cleaned.
  \param[in]   addr    address
  \param[in]   dsize   size of memory block (in number of bytes)
*/
__STATIC_FORCEINLINE void SCB_CleanDCache_by_Addr (uint32_t *addr, int32_t dsize)

 Suppose the sector I want to clean is defined as follows.

#define ADDR_FLASH_BANK_1_SECTOR_3_START ((uint32_t)0x8060000) /* Base @ of SECTOR 3, 128KByte */
#define ADDR_FLASH_BANK_1_SECTOR_3_END   ((uint32_t)0x807FFFF) /* Base @ of SECTOR 3, 128KByte */

If I wanted to use this SCB_CleanDCache_by_Addr method on an entire sector which starts at 0x8060000 would I use this method like so?

SCB_CleanDCache_by_Addr(0x8060000, 131071)

Where, 131071 = 0x807FFFF - 0x8060000

(1) For simplicity sake, just disable interrupts and do not tinker with the vectors at all.

(2) see this thread. last message from @piranha

(3) Just do not enable Dcache or Icache

>  Apart from disabling WRP are there any other considerations?

There can be some other complications such as proprietary code protected areas, but unlikely that you have that.