title: STM32 Flash Write causes multiple HardFault Errors
body: <p>I am trying to write several bytes of data onto the STM32F410CBT3 Flash Memory Sector 4 (size of 64KB), and I chose this sector and assume it is safe to use as the code is approximately 30KB (which would probably reside in sectors 1 and 2). The microcontroller's clock speed is clocked at 100MHz (through PLL).</p>
  <p>Here is my Flash Write code:</p>
  <pre><code>/* Programming in 16-bit words, so offset address of 0x04 should be enough */
  #define FLASH_SECTOR4_BASEADDRESS                       ((uint32_t)0x8011000)
  #define OFFSET                                          ((uint8_t)0x04)
  
  #define ADDR0               FLASH_SECTOR4_BASEADDRESS                                           
  #define ADDR1               ((uint32_t)(ADDR0 + OFFSET))
  #define ADDR2               ((uint32_t)(ADDR1 + OFFSET))
  #define ADDR3               ((uint32_t)(ADDR2 + OFFSET))
  /* and so on... */
  
  
  void FLASH_Init(void)
  {
      /* Only use FLASH Sector 4 for storing configuration/calibration data. s_EraseInit is stored as a static variable. This function called first because s_EraseInit needs to have values before any FLASH functions/routines are called. */
      s_EraseInit.TypeErase = TYPEERASE_SECTORS;
      s_EraseInit.Sector = FLASH_SECTOR_4;
      s_EraseInit.NbSectors = 1;
      s_EraseInit.VoltageRange = VOLTAGE_RANGE_4; /* Input voltage to mcu is around 3.3V */
  }
  
  
  void FLASH_Write(void)
  {
      /* Stop LPTIM1 interrupts prior to modifying FLASH region */
      HAL_LPTIM_Counter_Stop_IT(&amp;hlptim1);
  
      /* Assign temp_x values of struct members stored globally. temp_x will be the variable used for the FlashProgram function */
      uint16_t temp0 = GlobalStruct[0].Member1;
      uint16_t temp1 = GlobalStruct[0].Member2;
      uint16_t temp2 = GlobalStruct[0].Member3;
      uint16_t temp3 = GlobalStruct[1].Member1;
      uint16_t temp4 = GlobalStruct[1].Member2;
      uint16_t temp5 = GlobalStruct[1].Member3;
      uint16_t temp6 = GlobalStruct[2].Member1;
      uint16_t temp7 = GlobalStruct[2].Member2;
      uint16_t temp8 = GlobalStruct[2].Member3;
      uint16_t temp9 = GlobalStruct[3].Member1;
      uint16_t temp10 = GlobalStruct[3].Member2;
      uint16_t temp11 = GlobalStruct[3].Member3;
  
      /* Unlock FLASH peripheral and clear FLASH status register (error) flags */
      HAL_FLASH_Unlock();
      __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP|FLASH_FLAG_OPERR|FLASH_FLAG_WRPERR|FLASH_FLAG_PGAERR|FLASH_FLAG_PGSERR);
      
      /* Mass erase FLASH sector 4 */
      FlashStatus[12] = HAL_FLASHEx_Erase(&amp;s_EraseInit, &amp;s_SectorError);
  
      /* Write into FLASH sector 4 and lock the FLASH peripheral after using it */
      FlashStatus[0] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR0, temp0);
      FlashStatus[1] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR1, temp1);   
      FlashStatus[2] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR2, temp2);   
      FlashStatus[3] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR3, temp3);
      FlashStatus[4] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR4, temp4);
      FlashStatus[5] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR5, temp5);
      FlashStatus[6] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR6, temp6);
      FlashStatus[7] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR7, temp7);
      FlashStatus[8] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR8, temp8);
      FlashStatus[9] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR9, temp9);
      FlashStatus[10] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR10, temp10);
      FlashStatus[11] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR11, temp11);
  
      HAL_FLASH_Lock();
      
      /* Resume LPTIM1 interrupts after modifying FLASH region */
      HAL_LPTIM_Counter_Start_IT(&amp;hlptim1, LPTIM1_AUTORELOAD_NUMBER);     
  }
  
  /*********************** Relevant code from the HAL Library *******************************/
  
  /**
    * @brief  Program byte, halfword, word or double word at a specified address
    * @param  TypeProgram  Indicate the way to program at a specified address.
    *                           This parameter can be a value of @ref FLASH_Type_Program
    * @param  Address  specifies the address to be programmed.
    * @param  Data specifies the data to be programmed
    * 
    * @retval HAL_StatusTypeDef HAL Status
    */
  HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
  {
    HAL_StatusTypeDef status = HAL_ERROR;
    
    /* Process Locked */
    __HAL_LOCK(&amp;pFlash);
    
    /* Check the parameters */
    assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
    
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
    
    if(status == HAL_OK)
    {
      if(TypeProgram == FLASH_TYPEPROGRAM_BYTE)
      {
        /*Program byte (8-bit) at a specified address.*/
        FLASH_Program_Byte(Address, (uint8_t) Data);
      }
      else if(TypeProgram == FLASH_TYPEPROGRAM_HALFWORD)
      {
        /*Program halfword (16-bit) at a specified address.*/
        FLASH_Program_HalfWord(Address, (uint16_t) Data);
      }
      else if(TypeProgram == FLASH_TYPEPROGRAM_WORD)
      {
        /*Program word (32-bit) at a specified address.*/
        FLASH_Program_Word(Address, (uint32_t) Data);
      }
      else
      {
        /*Program double word (64-bit) at a specified address.*/
        FLASH_Program_DoubleWord(Address, Data);
      }
      
      /* Wait for last operation to be completed */
      status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
      
      /* If the program operation is completed, disable the PG Bit */
      FLASH-&gt;CR &amp;= (~FLASH_CR_PG);  
    }
    
    /* Process Unlocked */
    __HAL_UNLOCK(&amp;pFlash);
    
    return status;
  }
  </code></pre>
  <p>About the code above, the global struct's members' are either 8-bit or 16-bit. I stopped the LPTIM1 interrupts before going into the FLASH Write sequence because I thought that the LPTIM1 interrupts could cause issues if it occurs exactly when the microcontroller is overwritting its Flash memory.</p>
  <p><strong>The Issue</strong></p>
  <p>I have been having HardFault errors on this code even though a really similar code (with the difference being the data written) works on a different STM32F410CBT3 microcontroller. I also matched the Linker Settings on MDK-ARM <code>IROM1: Start 0x8000000, Size 0x1C000</code>, previously it was at <code>IROM1: Start 0x8000000, Size 0x20000</code>. The common pattern that I am observing is, based on MDK-ARM's Memory Viewer, the Flash gets erased where <code>??</code> appears on all the memory block. Afterwards, it goes to <code>0xFF</code> again indicating that none of the blocks/sections were written. At this point, the code is already in its HardFault Handler. If the code supposedly works, the sectors would turn from <code>??</code> to whatever value was written to the Flash memory.</p>
  <p>Regarding the HardFault Error, it sometimes shows as a <strong>Memory Manage Fault</strong>, where the <code>IACCVIOL</code> (Instruction access violation flag) was raised, and <code>SCB-&gt;MMFAR</code> not containing any address. On most times, it shows up as a <strong>Bus Fault</strong>, where <code>SCB-&gt;BFAR = 0xFFFFFFFF</code> with the <code>BFARVALID</code> flag high, and <code>PRECISERR</code> flag was also raised. I looked through the STM32F410 Memory Map and the address <code>0xFFFFFFFF</code> points to a 512-Mbyte block 7 Cortex-M4's internal peripherals. On rare occasions, it shows as a <strong>Usage Fault</strong>, where the <code>UNDEFINSTR</code> bit is high. Sometimes, the Flash Write sequence <em>does</em> work, but only if breakpoints were used.</p>
  <p><a href="https://i.stack.imgur.com/WQsQA.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/WQsQA.png" alt="One Example of Bus Fault Error" /></a></p>
  <p><strong>What I tried</strong></p>
  <ul>
  <li>Initially, I immediately placed the struct members inside the <code>HAL_FLASH_Program</code> APIs. Based on the UsageFault error, I thought that the struct member access was too slow, so I declared those unsigned 16-bit <code>tempX</code> variables to hold the struct members' values. The error still persists, and maybe, it is not the cause as the compiler would probably optimize that anyways. I also tried using delays and the error still persists.</li>
  <li>I changed the 16-bit <code>tempX</code> variable declarations to <code>uint32_t</code> because I read somewhere that the input needs to be either 32-bits or 64-bits. I changed it to <code>uint32_t</code> declarations and the error still persists.</li>
  <li>I also tried using <code>FLASH_TYPEPROGRAM_WORD</code> instead of <code>FLASH_TYPEPROGRAM_HALFWORD</code>, and the error still persists. On the different microcontroller, I noticed that this should not have much effect, because if I were to write a 16-bit value (for ex. <code>0xAAAA</code>), in the Flash section itself, it would either appear as <code>0x0000AAAA</code> if <code>FLASH_TYPEPROGRAM_WORD</code> was used, or <code>0xFFFFAAAA</code> if <code>FLASH_TYPEPROGRAM_HALFWORD</code> was used because the left 16-bits were cleared to <code>0xFFFF</code> but not re-written to <code>0x0000</code> since only the least 16-bits were overwritten.</li>
  <li>Initially, I thought that writing a <code>0xFFFF</code> would cause an issue, but after I ensured that all the struct members were nonzero or nonFFFF, the error still persists. On the different microcontroller, I could also still write <code>0xFFFF</code> to the Flash without causing any errors.</li>
  <li>I also tried using a different location (although still located in Sector 4), and the error still persists.</li>
  <li>I verified that whenever a HardFault error occurs, <code>FlashStatus[x], x = 0...12</code> contains only <code>HAL_OK</code>. The <code>FLASH-&gt;SR</code> register usually shows nothing too (no error status).</li>
  <li>The variable <code>s_SectorError</code> usually has <code>0xFFFFFFFF</code>, indicating that all the sectors (Sector 4) was successfully erased</li>
  </ul>
  <p><strong>Question</strong>
  What am I missing here? Any help would be greatly appreciated. I also don't know how to debug this issue deeper and any tips on debugging this problem would be appreciated too. <a href="https://www.keil.com/support/man/docs/uv4/uv4_cp_m347_faults.htm" rel="nofollow noreferrer">This is the Keil uVision's page on Fault Reporting Guide</a>, which I used as a reference for identifying the HardFault Errors. Thank you!</p>