STM32使用HAL庫讀寫內部FLASH

STM32使用HAL庫讀寫內部FLASH


測試環境:

  • STM32F103RB
  • 20KBytes RAM
  • 128KBytes FLASH

頭文件:

////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * @brief Create by AnKun on 2019/10/10
 */

#ifndef __FLASH_H
#define __FLASH_H

#include "main.h"

//////////////////////////////////////////// 移植修改區 ///////////////////////////////////////////////

/* FLASH大小:128K */
#define STM32FLASH_SIZE  0x00020000UL

/* FLASH起始地址 */
#define STM32FLASH_BASE  FLASH_BASE

/* FLASH結束地址 */
#define STM32FLASH_END   (STM32FLASH_BASE | STM32FLASH_SIZE)

/* FLASH頁大小:1K */
#define STM32FLASH_PAGE_SIZE FLASH_PAGE_SIZE

/* FLASH總頁數 */
#define STM32FLASH_PAGE_NUM  (STM32FLASH_SIZE / STM32FLASH_PAGE_SIZE)

/* 獲取頁地址,X=0~STM32FLASH_PAGE_NUM */
#define ADDR_FLASH_PAGE_X(X)    (STM32FLASH_BASE | (X * STM32FLASH_PAGE_SIZE))


/////////////////////////////////////////// 導出函數聲明 ////////////////////////////////////////////
void FLASH_Init(void);
uint32_t FLASH_Read(uint32_t Address, uint16_t *Buffer, uint32_t NumToRead);
uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);

#endif // !__FLASH_H

//////////////////////////////////////////////////////// end of file ////////////////////////////////////////////////////////////////

源文件:

////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * @brief Create by AnKun on 2019/10/10
 */

#include "flash.h"

static uint16_t FlashBuffer[STM32FLASH_PAGE_SIZE >> 1];
static uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);

/// 初始化FLASH
void FLASH_Init(void)
{
	HAL_FLASH_Unlock();
	__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | \
	                       FLASH_FLAG_PGERR | \
	                       FLASH_FLAG_WRPERR);
	HAL_FLASH_Lock();
}

/**
 * 讀FLASH
 * @param  Address   要讀的起始地址,!!!要求2字節對齊!!!
 * @param  Buffer    存放讀取的數據,!!!要求2字節對齊!!!
 * @param  NumToRead 要讀取的數據量,單位:半字,!!!要求2字節對齊!!!
 * @return           實際讀取到的數據量,單位:字節
 */
uint32_t FLASH_Read(uint32_t Address, uint16_t *Buffer, uint32_t NumToRead)
{
	uint32_t nread = NumToRead;
	uint32_t AddrMax = STM32FLASH_END - 2;

	if (NumToRead == 0 || Buffer == NULL || Address > AddrMax)
		return 0;

	while (Address <= AddrMax && nread)
	{
		*Buffer++ = *(__IO uint16_t *)Address;
		Address += 2;
		nread--;
	}

	return ((NumToRead - nread) << 1);
}

/**
 * 寫FLASH
 * @param  Address    寫入起始地址,!!!要求2字節對齊!!!
 * @param  Buffer     待寫入的數據,!!!要求2字節對齊!!!
 * @param  NumToWrite 要寫入的數據量,單位:半字,!!!要求2字節對齊!!!
 * @return            實際寫入的數據量,單位:字節
 */
uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
{
	uint32_t i = 0;
	uint32_t pagepos = 0;         // 頁位置
	uint32_t pageoff = 0;         // 頁內偏移地址
	uint32_t pagefre = 0;         // 頁內空餘空間
	uint32_t offset = 0;          // Address在FLASH中的偏移
	uint32_t nwrite = NumToWrite; // 記錄剩餘要寫入的數據量

	/* 非法地址 */
	if (Address < STM32FLASH_BASE || Address > (STM32FLASH_END - 2) || NumToWrite == 0 || Buffer == NULL)
		return 0;

	/* 解鎖FLASH */
	HAL_FLASH_Unlock();

	/* 計算偏移地址 */
	offset = Address - STM32FLASH_BASE;

	/* 計算當前頁位置 */
	pagepos = offset / STM32FLASH_PAGE_SIZE;

	/* 計算要寫數據的起始地址在當前頁內的偏移地址 */
	pageoff = ((offset % STM32FLASH_PAGE_SIZE) >> 1);

	/* 計算當前頁內空餘空間 */
	pagefre = ((STM32FLASH_PAGE_SIZE >> 1) - pageoff);

	/* 要寫入的數據量低於當前頁空餘量 */
	if (nwrite <= pagefre)
		pagefre = nwrite;

	while (nwrite != 0)
	{
		/* 檢查是否超頁 */
		if (pagepos >= STM32FLASH_PAGE_NUM)
			break;

		/* 讀取一頁 */
		FLASH_Read(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE >> 1);

		/* 檢查是否需要擦除 */
		for (i = 0; i < pagefre; i++)
		{
			if (*(FlashBuffer + pageoff + i) != 0xFFFF) /* FLASH擦出後默認內容全爲0xFF */
				break;
		}

		if (i < pagefre)
		{
			uint32_t count = 0;
			uint32_t index = 0;
			uint32_t PageError = 0;
			FLASH_EraseInitTypeDef pEraseInit;

			/* 擦除一頁 */
			pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
			pEraseInit.PageAddress = STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE;
			pEraseInit.Banks = FLASH_BANK_1;
			pEraseInit.NbPages = 1;
			if (HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)
				break;

			/* 複製到緩存 */
			for (index = 0; index < pagefre; index++)
			{
				*(FlashBuffer + pageoff + index) = *(Buffer + index);
			}

			/* 寫回FLASH */
			count = FLASH_WriteNotCheck(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE >> 1);
			if (count != (STM32FLASH_PAGE_SIZE >> 1))
			{
				nwrite -= count;
				break;
			}
		}
		else
		{
			/* 無需擦除,直接寫 */
			uint32_t count = FLASH_WriteNotCheck(Address, Buffer, pagefre);
			if (count != pagefre)
			{
				nwrite -= count;
				break;
			}
		}

		Buffer += pagefre;         /* 讀取地址遞增         */
		Address += (pagefre << 1); /* 寫入地址遞增         */
		nwrite -= pagefre;         /* 更新剩餘未寫入數據量 */

		pagepos++;   /* 下一頁               */
		pageoff = 0; /* 頁內偏移地址置零     */

		/* 根據剩餘量計算下次寫入數據量 */
		pagefre = nwrite >= (STM32FLASH_PAGE_SIZE >> 1) ? (STM32FLASH_PAGE_SIZE >> 1) : nwrite;
	}

	/* 加鎖FLASH */
	HAL_FLASH_Lock();

	return ((NumToWrite - nwrite) << 1);
}

static uint32_t FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
{
	uint32_t nwrite = NumToWrite;
	uint32_t addrmax = STM32FLASH_END - 2;

	while (nwrite)
	{
		if (Address > addrmax)
			break;

		HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, *Buffer);
		if ( (*(__IO uint16_t *)Address) != *Buffer )
			break;

		nwrite--;
		Buffer++;
		Address += 2;
	}
	return (NumToWrite - nwrite);
}


//////////////////////////////////////////////////////// end of file ////////////////////////////////////////////////////////////////

測試:


uint16_t rbuffer[512];
uint16_t wbuffer[512];

#define DEBUG
#define ARRAY_SIZE(X)  (sizeof(X)/sizeof(X[0]))

#ifdef DEBUG
#define debug(fmt, ...) do{printf(fmt, ##__VA_ARGS__);}while(0)
#else
#define debug(fmt, ...) do{}while(0)
#endif

int main(void)
{
	int i = 0;
	uint32_t nwrite = 0, nread = 0;
	
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    FLASH_Init();

	debug("\r\n\n");
	debug("\r\n=====================================================");
	debug("\r\n=              STM32Cube - Version 5.6              =");
	debug("\r\n=              Libary    - Version 1.8              =");
	debug("\r\n=====================================================");
	debug("\r\n\n");
	
	memset(wbuffer, 0xAA, sizeof(wbuffer));
	memset(rbuffer, 0x00, sizeof(rbuffer));
	
	for(i = 64; i < STM32FLASH_PAGE_NUM; i++)
	{
		printf("\r\n\r\n");
		printf("\r\n###################  FLASH PAGE %0.3d  ###################", i);
		nwrite = FLASH_Write(ADDR_FLASH_PAGE_X(127), wbuffer, ARRAY_SIZE(wbuffer));
		nread  = FLASH_Read(ADDR_FLASH_PAGE_X(127), rbuffer, ARRAY_SIZE(wbuffer));
		debug("\r\n write %0.8d bytes to falsh.", nwrite);
		debug("\r\n read  %0.8d bytes on falsh.", nread);
		debug("\r\n falsh read & write test %s.", memcmp(wbuffer, rbuffer, sizeof(wbuffer)) == 0 ? "success" : "failed");
	}
	
	for(;;){}
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章