- 该功能可以实现数据掉电不丢失
1.准备数据
定义一个用户数据结构体,其中的数据要求掉电不丢失,可以在结构体中继续拓展需要存的数据类型。
typedef struct user_data{
data1_t data1;
data2_t data2;
...
datan_ta datan;
}user_data_t;
//定义变量保存用户数据
user_data_t user_data;
2.选择内存中的保存位置
确定数据保存在内存中的地址
//G0B0 flash大小 0x0800 0000-0x0807 FFFF
//size : 0x7ffff + 0x0001 --> 1000 0000 0000 0000 0000 = 2^19 = 512K
//定义一个用于存储用户数据的地址
#define USER_DATA_ADDRESS (0x0807D000UL)
3.写入数据
将全局变量 DataFlash
中的数据同步到 Flash 中的指定地址
int32_t DataSyncFlash(void)
{
int32_t ret = 0;
ret = coreFlashWrite((void*)USER_DATA_ADDRESS, (void*)&user_data_t, sizeof(user_data_t));
return ret;
}
4.读取数据
开机首先将FLASH中的数据读到声明的变量中
void DataReadFlash(void)
{
const volatile user_data_t* rawPtr = (const volatile user_data_t*)USER_DATA_ADDRESS;
if (DataIsActive())
{
memcpy(&user_data, (void*)rawPtr, sizeof(user_data_t));
}
}
5. 驱动函数
//定义一个缓冲区用于存放要写入FLASH的数据 注意字节对齐 why? 优化内存访问
__align(8) static uint8_t flashWriteBuf[2048];
1.1 coreFlashAcquireWriteBuffer
uint8_t* coreFlashAcquireWriteBuffer(void)
{
return flashWriteBuf;
}
1.2 getPage
static uint32_t getPage(uint32_t addr)
{
uint32_t page = 0;
/* Bank 1 */
page = (addr - FLASH_BASE) / FLASH_PAGE_SIZE;
return page;
}
页面号被计算为地址相对于基地址 FLASH_BASE
的偏移量除以页面大小 FLASH_PAGE_SIZE
。
1.3 coreFlashWrite
int32_t coreFlashWrite(void* dstAddr, const void* srcAddr, const uint32_t size)
{
//初始化FLASH_EraseInitTypeDef
FLASH_EraseInitTypeDef eraseInitStruct = {0x00};
int32_t ret = ERR_FLASHOP_OK; // 返回值
//1.判断入参正确
if (!srcAddr || !dstAddr || 0 == size)
{
return ERR_FLASHOP_PARAM_INVAL;
}
if (0 != ((uint32_t)srcAddr & 0x00000007))
{
return ERR_FLASHOP_SRCADDR_UNALIGN;
}
if (0 != ((uint32_t)dstAddr & 0x00000007))
{
return ERR_FLASHOP_DSTADDR_UNALIGN;
}
//2.写数据之前 要先擦除数据
//获取要擦除的第一页
firstPage = getPage((uint32_t)dstAddr);
//计算从第一页开始的 要擦除的页数
nbOfPages = size / FLASH_PAGE_SIZE + (size % FLASH_PAGE_SIZE ? 1 : 0);
//擦除数据初始化
eraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
eraseInitStruct.Page = firstPage; // 擦除起始页
eraseInitStruct.NbPages = nbOfPages; // 擦除页数
HAL_FLASH_Unlock(); // Flash解锁
__disable_irq(); // 擦除前需要关闭中断
if (HAL_FLASHEx_Erase(&eraseInitStruct, &pageError) != HAL_OK)
{
__enable_irq();
ret = -ERR_FLASHOP_FAIL_ERASE;
goto exit;
}
__enable_irq();
//3.开始写入Flash
flashAddress = (uint32_t)dstAddr;
nWriteAll = size;
while (nHasWrite < nWriteAll)
{
// 以64位为单位写入数据
srcDW = *(uint64_t*)((uint32_t)srcAddr + nHasWrite);
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flashAddress, srcDW) == HAL_OK)
{
flashAddress += 8;
nHasWrite += 8;
}
else
{
ret = ERR_FLASHOP_FAIL_PROG;
goto exit;
}
}
exit:
HAL_FLASH_Lock(); // Flash加锁
return ret;
}