查看其它库函数说明请点击此处跳转到SeanLib主页1. 本篇内容本篇提供了一个适用于STM32F429的片内Flash操作库支持读一般不使用、扇区擦除、写按字节形式三个方法相比于HAL库中的函数本函数库操作更简单方便。本库不依赖HAL库等其它库文件。其它的单片机型号暂不支持但F4系列可能都支持如果有更新会更新此篇文章。2. 使用说明本库包含 MyFlash.lib 和 MyFlash.h 两个文件头文件内容如下#includeSeanLib.h/******************************************************************************* *本库适用于 STM32F429 其它型号未经测试 扇区划分如下 | Secotor Size | BANK1 | ADDRESS | BANK2 | ADDRESS | | 16K | 0 | 0x08000000 | 12 | 0x08100000 | | 16K | 1 | 0x08004000 | 13 | 0x08104000 | | 16K | 2 | 0x08008000 | 14 | 0x08108000 | | 16K | 3 | 0x0800C000 | 15 | 0x0810C000 | | 64K | 4 | 0x08010000 | 16 | 0x08110000 | | 128K | 5 | 0x08020000 | 17 | 0x08120000 | | 128K | 6 | 0x08040000 | 18 | 0x08140000 | | 128K | 7 | 0x08060000 | 19 | 0x08160000 | | 128K | 8 | 0x08080000 | 20 | 0x08180000 | | 128K | 9 | 0x080A0000 | 21 | 0x081A0000 | | 128K | 10 | 0x080C0000 | 22 | 0x081C0000 | | 128K | 11 | 0x080E0000 | 23 | 0x081E0000 | *******************************************************************************/typedefstruct{/*************************************************************************** 功能读字节函数一般用不上读Flash的函数 ***************************************************************************/void(*Read)(unsignedintAddr,unsignedchar*Data,unsignedintLength);/*************************************************************************** 功能擦除指定编号的扇区如0、1、2...23 ***************************************************************************/Sean_Result_t(*Erase)(unsignedcharSector);/*************************************************************************** 功能写入一组字节数据 参数 AddrFlash地址必须是4字节对齐地址 Data要写入的数据指针 Length要写入的数据长度允许不是4的倍数 返回值操作完成状态或错误代码 ***************************************************************************/Sean_Result_t(*Write)(unsignedintAddr,unsignedchar*Data,unsignedintLength);}MyFlash_t;//系统已经创建一个Flash对象应用程序中不需要再定义可以直接使用MyFlash其中封装了一些支持的方法externMyFlash_t MyFlash;使用Write方法写入可以确保写入成功因为该方法在写入后会回读校验。2.1 扇区擦除Flash在写之前需要先擦除因为Flash的存储单元仅允许由1写为0若要由0改写为1仅能通过擦除操作完成。而Flash的寿命与擦除次数有关一般为10000次因此项目中应谨慎擦除采用合理的Flash存储策略比如存储log应先擦除1个扇区之后开始逐条存储在此扇区存满之前都不需要再擦除。擦除是以扇区为单位的单片机的扇区大小并不都是相同的具体请看头文件开头部分的表格列出了每个扇区的大小。2.2 实例代码以下是从SD卡读文件写入到Flash的代码//根据固件大小计算需要擦除的扇区数量unsignedcharCalc_Erase_Count(unsignedintSize){constunsignedintSector_Size[16]{131072,// 0: 128KB262144,// 1: 256KB393216,// 2: 384KB524288,// 3: 512KB540672,// 4: 528KB557056,// 5: 544KB573440,// 6: 560KB589824,// 7: 576KB655360,// 8: 640KB786432,// 9: 768KB917504,// 10: 896KB1048576,// 11: 1MB1179648,// 12: 1.125MB1310720,// 13: 1.25MB1441792,// 14: 1.375MB1572864};// 15: 1.5MBunsignedcharcount;for(count0;count16;count){if(SizeSector_Size[count]){returncount1;}}return0;}//从指定的起始扇区号开始擦除指定数量的扇区Sean_Result_tFlash_Erase_Sectors(unsignedcharSector_Start,unsignedcharCount){unsignedchari;Sean_Result_t ret;for(i0;iCount;i){retMyFlash.Erase(Sector_Starti);if(ret!Sean_PASS){returnSean_FAIL;}}returnSean_PASS;}unsignedcharbuf[1024]__attribute__((aligned(4)));//打开指定的固件文件返回文件大小若文件存在则保持文件开启unsignedintOpen_File(constchar*Path){FRESULT ret;unsignedintFW_Size;retf_open(File,Path,FA_OPEN_EXISTING|FA_READ);//打开文件if(retFR_OK)//打开成功时返回文件大小{FW_Sizef_size(File);//读取固件大小if(FW_Size0)//若固件文件异常则删除该文件{printf(Size of file is 0, delete file\r\n);f_close(File);f_unlink(Path);return0;}returnFW_Size;}printf(Failed to open file %s:%s\r\n,Path,File_Err[ret]);return0;}//更新MCU的固件Sean_Result_tUpdate_MCU(constchar*FW_Path){FRESULT ret;unsignedintFW_Size;unsignedintRem_Count,Finish_Count;floatProcess;FW_SizeOpen_File(FW_Path);//打开文件并读取固件大小if(FW_Size0){returnSean_FAIL;}unsignedcharErase_Count;Erase_CountCalc_Erase_Count(FW_Size);//计算要擦除的Flash扇区数量if(Flash_Erase_Sectors(8,Erase_Count)!Sean_PASS)//从第8个扇区开始擦除需要擦除的所有扇区{printf(Failed to erase sector:%hhu\r\n,8Erase_Count);f_close(File);returnSean_FAIL;}unsignedintWrite_Addr0x08080000;//固件起始地址unsignedintReadLen;unsignedshortPackage;Rem_CountFW_Size;Finish_Count0;while(Rem_Count0)//读取固件写入Flash{PackageRem_Count1024?1024:Rem_Count;//每包大小1024字节retf_read(File,buf,Package,ReadLen);//从文件中读一包数据if(ret!FR_OK||Package!ReadLen)//读取失败关闭文件{printf(Read file error: %s\r\n,File_Err[ret]);f_close(File);returnSean_FAIL;}if(MyFlash.Write(Write_Addr,buf,Package)!Sean_PASS){printf(Failed to write flash\r\n);f_close(File);returnSean_FAIL;}Rem_Count-Package;Finish_CountPackage;Process(float)Finish_Count;Process*100.0f;Process/(float)FW_Size;printf(Download process: %.1f%%\r\n,Process);if(Rem_Count0)//更新完成关闭文件{f_close(File);returnSean_PASS;}Write_AddrPackage;}returnSean_FAIL;}这里演示了擦除、写入的完整过程Calc_Erase_Count函数用于计算要擦除的扇区数量因为擦除操作耗时较长扇区越大耗时越长所以要采用最少化擦除原则。