STM32F1系列HAL库读写内部FLASH
测试环境:
- STM32F103RB
- 20KBytes RAM
- 128KBytes FLASH
注:本章节代码只适合STM32F1系列!
头文件
/**
* @brief Create by AnKun on 2019/10/10
*/
#ifndef __FLASH_H
#define __FLASH_H
#include "main.h"
///
///
/// 移植修改区
///
///
/* FLASH起始地址 */
#define STM32FLASH_BASE FLASH_BASE
/* FLASH页大小:1K */
#define STM32FLASH_PAGE_SIZE FLASH_PAGE_SIZE
///
///
/// 导出函数声明
///
///
void FLASH_Init(void);
void FLASH_Read(uint32_t Address, uint16_t* Buffer, uint32_t NumToRead);
void FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages);
void FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
void FLASH_SetReadProtectionState(int state);
#endif // !__FLASH_H
源文件
/**
* @file flash.c
*
* @brief Create by AnKun on 2019/10/10
*
*/
#include "flash.h"
#include <string.h>
static uint16_t FlashBuffer[STM32FLASH_PAGE_SIZE >> 1];
/// 初始化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 存放读取的数据
* @param NumToRead 要读取的数据量,单位:半字
*/
void FLASH_Read(uint32_t Address, uint16_t* Buffer, uint32_t NumToRead)
{
while(NumToRead != 0)
{
*Buffer = (*(volatile uint16_t *)Address);
Buffer++;
NumToRead--;
Address += 2;
}
}
/**
* 写FLASH
* @param Address 写入起始地址,!!!要求2字节对齐!!!
* @param Buffer 待写入的数据,!!!要求2字节对齐!!!
* @param NumToWrite 要写入的数据量,单位:半字
*/
void 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; // 记录剩余要写入的数据量
const uint16_t *pBuffer = (const uint16_t *)Buffer;
/* 解锁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)
{
/* 读取一页 */
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 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) = *(pBuffer + index);
}
/* 写回FLASH */
FLASH_WriteNotCheck(STM32FLASH_BASE + pagepos * STM32FLASH_PAGE_SIZE, FlashBuffer, STM32FLASH_PAGE_SIZE >> 1);
}
else
{
/* 无需擦除,直接写 */
FLASH_WriteNotCheck(Address, Buffer, pagefre);
}
pBuffer += pagefre; /* 读取地址递增 */
Address += (pagefre << 1); /* 写入地址递增 */
nwrite -= pagefre; /* 更新剩余未写入数据量 */
pagepos++; /* 下一页 */
pageoff = 0; /* 页内偏移地址置零 */
/* 根据剩余量计算下次写入数据量 */
pagefre = nwrite >= (STM32FLASH_PAGE_SIZE >> 1) ? (STM32FLASH_PAGE_SIZE >> 1) : nwrite;
}
/* 加锁FLASH */
HAL_FLASH_Lock();
}
void FLASH_WriteNotCheck(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
{
while (NumToWrite != 0)
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, *Buffer) != HAL_OK)
break;
NumToWrite--;
Buffer++;
Address += 2;
}
}
int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages)
{
uint32_t PageError = 0;
FLASH_EraseInitTypeDef pEraseInit;
pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
pEraseInit.PageAddress = PageAddress;
pEraseInit.Banks = FLASH_BANK_1;
pEraseInit.NbPages = 1;
if(HAL_FLASHEx_Erase(&pEraseInit, &PageError) != HAL_OK)
{
return -1;
}
return 0;
}
void FLASH_SetReadProtectionState(int state)
{
FLASH_OBProgramInitTypeDef OptionsBytesStruct;
HAL_FLASHEx_OBGetConfig(&OptionsBytesStruct);
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
if(state)
{
if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL0)
{
OptionsBytesStruct.OptionType = OPTIONBYTE_RDP;
OptionsBytesStruct.RDPLevel = OB_RDP_LEVEL1;
HAL_FLASHEx_OBProgram(&OptionsBytesStruct);
}
}
else
{
if(OptionsBytesStruct.RDPLevel == OB_RDP_LEVEL1)
{
OptionsBytesStruct.OptionType = OPTIONBYTE_RDP;
OptionsBytesStruct.RDPLevel = OB_RDP_LEVEL0;
HAL_FLASHEx_OBProgram(&OptionsBytesStruct);
}
}
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
}