Flash Write and Read on STM32G0

Preface

Recently, a customer started researching STM32G031 Flash read and write. When the customer used the sample code provided by the official website to write to Flash and added a Timer interrupt, the system kept entering the HardFault_Handler(). I started researching the Flash status and the HardFault_Handler() checking program.

HardFault_Handler Check Procedure

First of all, we are using STM32cudeIDE instead of MDK, so the debugging methods established on the website may not be completely applicable. Here are the reasons for entering HardFault:

  1. Memory overflow or access out of bounds.
  2. Stack overflow.

Checking methods:

  1. Use the built-in check of STM32.
  2. Step-by-step execution to locate the problem.

Using the built-in check, as shown in the figure below, you can initially check where the problem is. The result is shown below.

Second method is to use single-step execution or set breakpoints (the most primitive method)

Flash Operating

Flash Write

  1. HAL_FLASH_Unlock()
  2. Check FLASH_SR –> BSY
  3. Set the PG bit in the FLASH_CR register
  4. Write
  5. HAL_FLASH_Lock();
Official declaration function
/* USER CODE BEGIN PD */
#define FLASH_USER_START_ADDR   (FLASH_BASE + (3 * FLASH_PAGE_SIZE))   /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR     (FLASH_BASE + FLASH_SIZE - 1)   /* End @ of user Flash area */

#define DATA_64                 ((uint64_t)0x1234567812345678)
#define DATA_32                 ((uint32_t)0x12345678</mark>)

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;

/* USER CODE BEGIN PV */
uint32_t FirstPage = 0, NbOfPages = 0;
uint32_t Address = 0, PageError = 0;
__IO uint32_t data32 = 0 , MemoryProgramStatus = 0;


/*Variable used for Erase procedure*/
static FLASH_EraseInitTypeDef EraseInitStruct = {0};

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_TIM2_Init(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
static uint32_t GetPage(uint32_t Address);

/* USER CODE END PFP */
Sample code from official
  /* Unlock the Flash to enable the flash control register access *************/
  HAL_FLASH_Unlock();
  

  /* Erase the user Flash area
    (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/


  /* Get the 1st page to erase */
  FirstPage = GetPage(FLASH_USER_START_ADDR);

  /* Get the number of pages to erase from 1st page */
  NbOfPages = GetPage(FLASH_USER_END_ADDR) - FirstPage + 1;

  /* Fill EraseInit structure*/
  EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
  EraseInitStruct.Page        = FirstPage;
  EraseInitStruct.NbPages     = NbOfPages;

  /* Note: If an erase operation in Flash memory also concerns data in the data or instruction cache,
     you have to make sure that these data are rewritten before they are accessed during code
     execution. If this cannot be done safely, it is recommended to flush the caches by setting the
     DCRST and ICRST bits in the FLASH_CR register. */
  if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
  {
    /*
      Error occurred while page erase.
      User can add here some code to deal with this error.
      PageError will contain the faulty page and then to know the code error on this page,
      user can call function 'HAL_FLASH_GetError()'
    */
    /* Infinite loop */
    while (1)
    {
      /* Make LED3 blink (100ms on, 2s off) to indicate error in Erase operation */
      //BSP_LED_On(LED3);
      HAL_Delay(100);
      //BSP_LED_Off(LED3);
      HAL_Delay(2000);
    }
  }

  /* Program the user Flash area word by word
    (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/

  Address = FLASH_USER_START_ADDR;

 while (Address < FLASH_USER_END_ADDR)
  {
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, DATA_64) == HAL_OK)
    {
      Address = Address + 8;
    }

   else
    {
      /* Error occurred while writing data in Flash memory.
         User can add here some code to deal with this error */
      while (1)
      {
        /* Make LED3 blink (100ms on, 2s off) to indicate error in Write operation */
        //BSP_LED_On(LED3);
        HAL_Delay(100);
        //BSP_LED_Off(LED3);
        HAL_Delay(2000);
      }
    }
    FLASH_WaitForLastOperation(500);
  }

  /* Lock the Flash to disable the flash control register access (recommended
     to protect the FLASH memory against possible unwanted operation) *********/
  HAL_FLASH_Lock();

  /* Check if the programmed data is OK
      MemoryProgramStatus = 0: data programmed correctly
      MemoryProgramStatus != 0: number of words not programmed correctly ******/
  Address = FLASH_USER_START_ADDR;
  MemoryProgramStatus = 0x0;

  while (Address < FLASH_USER_END_ADDR)
  {
    data32 = *(__IO uint32_t *)Address;

    if (data32 != DATA_32)
    {
      MemoryProgramStatus++;
    }
    Address = Address + 4;
  }

  /*Check if there is an issue to program data*/
  if (MemoryProgramStatus == 0)
  {
    /* No error detected. Switch on LED3*/
    //BSP_LED_On(LED3);
	  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
  }
  else
  {
    /* Error detected. LED3 will blink with 1s period */
    while (1)
    {
      //BSP_LED_On(LED3);
      HAL_Delay(1000);
      //BSP_LED_Off(LED3);
      HAL_Delay(1000);
    }

Flash Read

void Flash_Read_Data (uint32_t StartPageAddress, uint32_t *RxBuf, uint16_t numberofwords)
{
	while (1)
	{

		*RxBuf = *(__IO uint32_t *)StartPageAddress;
		StartPageAddress += 4;
		RxBuf++;
		if (!(numberofwords--)) break;
	}
}

Result

Here, we use STM32CubeProgrammer to check the value of the internal Flash, and we can see that it has been completely written with 12345678.

Note

From the demonstration results above, it can be seen that Flash can write the desired value to the specified location. However, it should be noted that there is a fixed area that contains data at the beginning of program execution, as shown in the figure below for the internal Flash result before and after program execution.

It can be seen that if the fixed area is overwritten with other data, it will cause execution errors and enter the HardFault_Handler. (The figure below shows the added Timer interrupt program in the code, so the original location recorded is more than just the pure writing.)

Please refer to the STM32G0 reference manual P70 to make changes to the initial write position to ensure normal operation.

If you simply want to write data to a specific location, please refer to the operation of using Flash as EEPROM in STM32GO.

Leave a Comment

Your email address will not be published. Required fields are marked *

Shopping Cart