针对 F429 内部 Flash 扇区大小不一致的特点做了适配,可以读写任意扇区、地址。
本驱动中使用了内部 SRAM 做为读写缓冲区,占用内存较大,实际项目中推荐使用 SDRAM 做为读写缓冲区,并搭配动态内存管理机制使用。本驱动已经通过了充分验证,可以直接在项目中使用。
头文件
/*********************************************************************************************************
* 模块名称:Flash.h
* 摘 要:Flash模块
* 当前版本:1.0.0
* 作 者:SZLY(COPYRIGHT 2018 - 2020 SZLY. All rights reserved.)
* 完成日期:2020年01月01日
* 内 容:
* 注 意:
**********************************************************************************************************
* 取代版本:
* 作 者:
* 完成日期:
* 修改内容:
* 修改文件:
*********************************************************************************************************/
#ifndef _FLASH_H_
#define _FLASH_H_
/*********************************************************************************************************
* 包含头文件
*********************************************************************************************************/
#include "DataType.h"
/*********************************************************************************************************
* 宏定义
*********************************************************************************************************/
//扇区大小为128K
#define FLASH_PAGE_SIZE ((u32)(128 * 1024))
/*********************************************************************************************************
* 枚举结构体定义
*********************************************************************************************************/
/*********************************************************************************************************
* API函数声明
*********************************************************************************************************/
void InitFlash(void); //初始化内部Flash模块
void FlashWriteWord(unsigned int startAddr, unsigned int* pBuf, unsigned int len); //向Flash中写入字
void FlashReadWord(unsigned int startAddr, unsigned int* pBuf, unsigned int len); //从Flash读取字
#endif
源文件
/*********************************************************************************************************
* 模块名称:Flash.c
* 摘 要:Flash模块
* 当前版本:1.0.0
* 作 者:SZLY(COPYRIGHT 2018 - 2020 SZLY. All rights reserved.)
* 完成日期:2020年01月01日
* 内 容:
* 注 意:
**********************************************************************************************************
* 取代版本:
* 作 者:
* 完成日期:
* 修改内容:
* 修改文件:
*********************************************************************************************************/
/*********************************************************************************************************
* 包含头文件
*********************************************************************************************************/
#include "Flash.h"
#include "stm32f4xx_conf.h"
#include "UART1.h"
/*********************************************************************************************************
* 宏定义
*********************************************************************************************************/
/*********************************************************************************************************
* 枚举结构体定义
*********************************************************************************************************/
typedef struct
{
unsigned int sectorNumber; //扇区编号
unsigned int sectorSize; //扇区大小
unsigned int sectorBaseAddr; //扇区起始地址
}StructSectorInfo;
/*********************************************************************************************************
* 内部变量
*********************************************************************************************************/
//Flash 写入缓冲区
static unsigned int s_arrFlashBuf[FLASH_PAGE_SIZE / 4];
//扇区信息
static const StructSectorInfo s_arrSectorInfo[24] =
{
{FLASH_Sector_0 , 16 * 1024, 0x08000000},
{FLASH_Sector_1 , 16 * 1024, 0x08004000},
{FLASH_Sector_2 , 16 * 1024, 0x08008000},
{FLASH_Sector_3 , 16 * 1024, 0x0800C000},
{FLASH_Sector_4 , 64 * 1024, 0x08010000},
{FLASH_Sector_5 , 128 * 1024, 0x08020000},
{FLASH_Sector_6 , 128 * 1024, 0x08040000},
{FLASH_Sector_7 , 128 * 1024, 0x08060000},
{FLASH_Sector_8 , 128 * 1024, 0x08080000},
{FLASH_Sector_9 , 128 * 1024, 0x080A0000},
{FLASH_Sector_10, 128 * 1024, 0x080C0000},
{FLASH_Sector_11, 128 * 1024, 0x080E0000},
{FLASH_Sector_12, 16 * 1024, 0x08100000},
{FLASH_Sector_13, 16 * 1024, 0x08104000},
{FLASH_Sector_14, 16 * 1024, 0x08108000},
{FLASH_Sector_15, 16 * 1024, 0x0810C000},
{FLASH_Sector_16, 64 * 1024, 0x08110000},
{FLASH_Sector_17, 128 * 1024, 0x08120000},
{FLASH_Sector_18, 128 * 1024, 0x08140000},
{FLASH_Sector_19, 128 * 1024, 0x08160000},
{FLASH_Sector_20, 128 * 1024, 0x08180000},
{FLASH_Sector_21, 128 * 1024, 0x081A0000},
{FLASH_Sector_22, 128 * 1024, 0x081C0000},
{FLASH_Sector_23, 128 * 1024, 0x081E0000},
};
/*********************************************************************************************************
* 内部函数声明
*********************************************************************************************************/
static unsigned int GetSectorSize(unsigned int sector); //根据扇区编号获取扇区大小
static unsigned int GetSectorBaseAddr(unsigned int sector); //根据扇区编号获取扇区起始地址
static unsigned int GetSectorNumber(unsigned int addr); //根据地址获取扇区编号
/*********************************************************************************************************
* 内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称: GetSectorSize
* 函数功能: 根据扇区编号获取扇区大小
* 输入参数: sector:扇区编号
* 输出参数: void
* 返 回 值: 扇区大小(字节)
* 创建日期: 2023年02月03日
* 注 意:
*********************************************************************************************************/
static unsigned int GetSectorSize(unsigned int sector)
{
unsigned int i;
for(i = 0; i < sizeof(s_arrSectorInfo) / sizeof(StructSectorInfo); i++)
{
if(sector == s_arrSectorInfo[i].sectorNumber)
{
return s_arrSectorInfo[i].sectorSize;
}
}
return 0;
}
/*********************************************************************************************************
* 函数名称: GetSectorBaseAddr
* 函数功能: 根据扇区编号获取扇区起始地址
* 输入参数: sector:扇区编号
* 输出参数: void
* 返 回 值: 扇区起始地址
* 创建日期: 2023年02月03日
* 注 意:
*********************************************************************************************************/
static unsigned int GetSectorBaseAddr(unsigned int sector)
{
unsigned int i;
for(i = 0; i < sizeof(s_arrSectorInfo) / sizeof(StructSectorInfo); i++)
{
if(sector == s_arrSectorInfo[i].sectorNumber)
{
return s_arrSectorInfo[i].sectorBaseAddr;
}
}
return s_arrSectorInfo[0].sectorBaseAddr;
}
/*********************************************************************************************************
* 函数名称: GetSectorNumber
* 函数功能: 根据地址获取扇区编号
* 输入参数: addr:地址
* 输出参数: void
* 返 回 值: 扇区编号
* 创建日期: 2023年02月03日
* 注 意:
*********************************************************************************************************/
static unsigned int GetSectorNumber(unsigned int addr)
{
unsigned int i;
for(i = 0; i < sizeof(s_arrSectorInfo) / sizeof(StructSectorInfo); i++)
{
if((addr >= s_arrSectorInfo[i].sectorBaseAddr) && (addr < (s_arrSectorInfo[i].sectorBaseAddr + s_arrSectorInfo[i].sectorSize)))
{
return s_arrSectorInfo[i].sectorNumber;
}
}
return s_arrSectorInfo[0].sectorNumber;
}
/*********************************************************************************************************
* API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitFlash
* 函数功能:初始化Flash模块
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注 意:
*********************************************************************************************************/
void InitFlash(void)
{
}
/*********************************************************************************************************
* 函数名称:FlashWriteWord
* 函数功能:向Flash中写入字
* 输入参数:startAddr-起始地址,pBuf-待写入数据指针,len-写入数据的数量
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注 意:输入数据一定是uint32_t的指针,即数据一定是按照4字节对齐写入的
* 写入数据时为保证之前写入的数据不被擦除,Flash读写以页为单位
*********************************************************************************************************/
void FlashWriteWord(unsigned int startAddr, unsigned int* pBuf, unsigned int len)
{
unsigned int i; //循环变量
unsigned int pageNumber; //页编号
unsigned int pageSize; //页大小,按字节
unsigned int pageAddr; //页地址,即起始地址 startAddr 所在的页地址
unsigned int pageOff; //页内偏移地址(32位计算),即起始地址 startAddr 所在的页的偏移地址
unsigned int rwAddr; //读写地址
unsigned int dataCnt; //已写入数据量
//获取页编号和页大小
pageNumber = GetSectorNumber(startAddr);
pageSize = GetSectorSize(pageNumber);
//计算页地址和页内偏移量
pageAddr = GetSectorBaseAddr(pageNumber);
pageOff = (startAddr - pageAddr) / 4;
//解锁Flash,准备写入
FLASH_Unlock();
//已写入数据量清零
dataCnt = 0;
//写入Flash时需要先读取整页的内容到缓冲区,然后擦除一整页,将缓冲区修改后再写回Flash
while(1)
{
//读取一整页的数据到缓冲区
rwAddr = pageAddr;
for(i = 0; i < pageSize / 4; i++)
{
s_arrFlashBuf[i] = *(u32*)rwAddr;
rwAddr = rwAddr + 4;
}
//擦除一整页
FLASH_EraseSector(pageNumber, VoltageRange_3);;
//修改缓冲区内的内容
while(pageOff < pageSize / 4)
{
//将数据保存到缓冲区
s_arrFlashBuf[pageOff] = pBuf[dataCnt];
//已写入数据加一
dataCnt++;
//页内偏移量加一
pageOff++;
//写入完成
if(dataCnt >= len)
{
break;
}
}
//页内偏移量清零
pageOff = 0;
//将修改后的缓冲区内容写回Flash
rwAddr = pageAddr;
for(i = 0; i < pageSize / 4; i++)
{
FLASH_ProgramWord(rwAddr, s_arrFlashBuf[i]);
rwAddr = rwAddr + 4;
}
//更新到下一页
pageAddr = pageAddr + pageSize;
pageNumber = GetSectorNumber(pageAddr);
//写入完成
if(dataCnt >= len)
{
break;
}
}
//Flash上锁
FLASH_Lock();
}
/*********************************************************************************************************
* 函数名称:FlashReadWord
* 函数功能:从Flash读取字
* 输入参数:startAddr-起始地址(由于是字(32位)读取,因此,此地址必须为4的倍数);pBuf-数据指针
* len-字(32位)数,即要读取的32位数据的个数
* 输出参数:void
* 返 回 值:void
* 创建日期:2021年07月01日
* 注 意:
*********************************************************************************************************/
void FlashReadWord(unsigned int startAddr, unsigned int* pBuf, unsigned int len)
{
u16 i;
u32 addr;
addr = startAddr;
for(i = 0; i < len; i++)
{
pBuf[i] = *(vu32*)(addr); //读取字(32位)
addr += 4; //由于是字(32位),故地址增加4
}
}
STM32F429IGT6 flash大小为1M,扇区11就达到上限了。为啥后面删除12~23还能读写呢?