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(;;){}
}