多云转晴 发表于 2022-4-14 17:51

【小白篇】如何操作FLASH的擦读写

本帖最后由 多云转晴 于 2022-4-14 17:51 编辑

         FLASH,全称为“FLASH Memory”,属于内存器件的一种,是一种不挥发性(Non-Volatile)内存。但由于它特殊的物理特性,导致它与其他常见内存有根本性的差异;比如像SDRAM、RDRAM都属于挥发性内存,只要掉电,内存里的数据就无法保持,但FLASH不同,它在无电流供应的条件下也可以长久地保存数据,相当于一个硬盘。         FLASH根据不同容量大小,闪存模块组织又有小容量、中容量、大容量等不同的分类,因此在使用之前需要先查看手册,了解当前所使用的FLASH为哪类产品,它的FLASH大小为多少,每一页共有多少个字节以及其他必要信息。    下面,将介绍如何进行FLASH的擦读写操作。          PS:将通过程序实例进行介绍,使用的芯片型号为APM32F103RBT6。          FLASH:128K每页1k   SRAM:20K

一、头文件包含和宏定义操作#ifndef __FLASH__H_#define __FLASH__H_
#include "apm32f10x.h"#include "Board.h"#include "apm32f10x_fmc.h"
/*FLASH 128KSRAM 20K*/#define Start_Addr                     ((uint32_t)0x08000000)      //FLASH的起始地址#define End_Addr                        ((uint32_t)0x08020000)      //FLASH的结束地址#define Flash_Page_Size            ((uint32_t)0x00000400)      //每页FLASH的大小#define FLASH_PASS                   1                                        //FLASH擦写成功标志#define FLASH_FAILED                0                                       //FLASH擦写失败标志
void Flash_Init(uint32_t start_addr,uint32_t end_addr);
#endif

二、定义一个函数(用于FLASH的初始化等操作)void Flash_Init(uint32_t start_addr,uint32_t end_addr)设置的两个形参用于向函数传入FLASH操作的起始地址和结束地址。

三、定义各类变量,以便后续使用 uint32_t Write_addr = 0,i = 0;//定义写入的起始地址 uint32_t Data_Input = {0x5a5a5a5a,0xa5a5a5a5};//定义写入的数据 uint32_t Data_counter = 0,Data_flag = 0;//定义写入数据的标志位 uint32_t Memory_Flag = FLASH_PASS;//定义写入数据状态标志位 uint32_t Flash_Page = ((end_addr - start_addr)/Flash_Page_Size);//页数计算
PS:          Write_addr作为一个局部变量,在每次需要对地址进行偏移时,可以操作该变量,保证传入的起始地址一直为同一个。          Data_Input是一个数组,存放写入FLASH的值。          Data_counter用来计数,Data_flag用来做标志位判断,使FLASH能写入不同的值。          Memory_Flag用来判定FLASH的操作是否成功。          Flash_Page是根据传入的起始地址和结束地址计算FLASH一共分为多少页。

四、对FLASH进行解锁操作(FLASH在锁定状态下无法擦写) FMC_Unlock();//FLASH解锁 FMC_ClearStatusFlag(FMC_FLAG_OC|FMC_FLAG_PE|FMC_FLAG_WPE);//清除标志位

五、对FLASH进行擦除操作Write_addr = start_addr;//将传输进来的起始地址赋给局部变量操作①全擦操作:/*先执行擦除操作*/FMC_EraseAllPage();//全片擦除②页擦操作:/*页擦*/for(i = 0;i < Flash_Page;i++){    FMC_ErasePage(Write_addr);    Write_addr += start_addr + (Flash_Page_Size * i);}PS:全擦即为FLASH的整片擦除;页擦是根据自己的需要,向页擦函数传入首地址,擦除指定的区域,上面的页擦函数是通过页擦,擦除整片FLASH的操作(每擦除一页进行一次地址偏移)。

六、对FLASH进行擦除验证Write_addr = start_addr;//将传输进来的起始地址赋给局部变量操作/*擦除校验*/while(Write_addr < end_addr){    if(*(uint32_t*)Write_addr != 0XFFFFFFFF)    {      Memory_Flag = FLASH_FAILED;    }    Write_addr += 4;}PS:在擦除操作结束后,通过判断每个位是否为FF,来判断程序是否擦除成功;若擦除失败或有部分擦除不成功,标志位会被置为FAILED状态(后续可通过自己的想法增加判断的方法,例如串口打印等)。

七、对FLASH进行写操作Write_addr = start_addr;//将传输进来的起始地址赋给局部变量操作/*进行写入数据操作*/while(Write_addr < end_addr){    FMC_ProgramWord(Write_addr,Data_Input);//数据写入对应地址    Data_counter++;//计数标志位开始累加    Write_addr += 4;//地址偏移    if(Data_counter == 256)    {      Data_counter = 0;//计数标志位清零      Data_flag = !Data_flag;//翻转标志位进行翻转    }    FMC_ClearStatusFlag(FMC_FLAG_OC|FMC_FLAG_PE|FMC_FLAG_WPE);//清除标志位}PS:从起始地址开始写入数据,每次写入一个字的大小,同时Data_counter开始计数,即每写入1k字节就换一个数据,直至写到结束地址。

八、对写入的数据进行校验 Write_addr = start_addr;//将传输进来的起始地址赋给局部变量操作/*写入数据验证*/Data_counter = 0;//计数标志位清零Data_flag = 0;//初始化翻转标志位while(Write_addr < end_addr){    if(*(uint32_t*)Write_addr != Data_Input)    {      Memory_Flag = FLASH_FAILED;    }    Data_counter++;//计数标志位开始累加    Write_addr += 4;//地址偏移    if(Data_counter == 256)    {      Data_counter = 0;//计数标志位清零      Data_flag = !Data_flag;//翻转标志位进行翻转    }}PS:校验方法与擦除校验的方法类似,通过地址偏移来判断每个位是否准确写入了预定的数据,若出现异常,则可以通过标志位判断出来。

九、重新上锁、并做最终判断 FMC_Lock();//给FLASH重新上锁 Data_counter = 0; Data_flag = 0;
if(Memory_Flag == FLASH_PASS) {   //FLASH擦写成功 } else {   //FLASH擦写失败 }

十、注意事项(1)若进行FLASH操作,那么存储和运行程序的工作就得交给SRAM执行,如何使用SRAM操作,可以查看我的上一篇帖子;(2)上面只说到FLASH的擦和写,读的方法是在debug调试状态时,通过memory来查看对应地址的信息,就可以知道FLASH是否操作成功;(3)上面已经提到过,在操作之前,要先知道自己使用的FLASH是多大容量,每页有多少字节,地址范围是多少以及使用的芯片的SRAM大小。

onemoren 发表于 2022-4-15 09:54

有参考意义。谢谢!

一个人破 发表于 2022-4-15 10:12

有用,适合我这种小白。如果有手册查找指南就好咯,懒如我,哈哈哈

duo点 发表于 2022-4-17 19:18

比较有参考意义
页: [1]
查看完整版本: 【小白篇】如何操作FLASH的擦读写