Flash Write and Read on STM32G0
前言
近期客戶開始研究STM32G031 Flash讀寫,因客戶在寫入Flash使用官網給的Sample code然後再加入Timer 中斷後會持續跑入HardFault_Handler(),我開始研究Flash狀態與HardFault_Handler檢查程序
HardFault_Handler檢查程序
首先這邊和網路上不同使用的是STM32cudeIDE非MDK,因此網站上所建立的偵錯方法可能不完全適用。這邊先介紹會進入HardFault原因
- 記憶體溢位或則訪問越界。
- 堆疊溢位。
檢查方法
- 使用STM32內建檢查
- 單步執行尋找
使用內建檢查如下圖可以直接初步檢查問題所在,結果如下方所顯示
第二種方法是使用單步執行或設定斷點(最原始方法)
Flash Operating
Flash Write
- HAL_FLASH_Unlock()
- 檢查FLASH_SR 中的 BSY 位
- FLASH_CR 寄存器中的 PG 位置 1
- 寫入
- HAL_FLASH_Lock();
官方的宣告涵式
/* 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
/* 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;
}
}
演示結果
這邊使用STM32CubeProgrammer 去看內部Flash的數值可以看到全部寫入了12345678
注意事項
由上面演示結果來看Flash可以在指定位置寫入你要的數值,但這邊要注意可以看一下,下面圖程式執行前後內部Flash結果
可以看到在一開始程式執行時候就有固定區域存有資料,因此如果把固定區域覆寫其他資料就會造成執行錯誤進入HardFault_Handler(下圖程式裡面加入Timer中斷程式因此紀錄的原始位置比起純粹的寫入還要多)
這邊請參考stm32g0 reference manual P70 來把起始寫入位置做改動才能正常運行
如果要單純在指定位置寫入資料請參考STM32GO中Flash充当EEPROM的操作