首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

FLASH 模拟 EEPROM

FLASH 模拟 EEPROM

STM32 本身没有自带 EEPROM,但是 STM32 具有 IAP(在应用编程)功能,所以我们可以把它的 FLASH 当成 EEPROM 来使用

        STM32 FLASH 简介

        不同型号的 STM32,其 FLASH 容量也有所不同,最小的只有 16K 字节,最大的则达到了1024K 字节。战舰 STM32 开发板选择的 STM32F103ZET6 的 FLASH 容量为 512K 字节,属于大容量产品(另外还有中容量和小容量产品),

        STM32 的闪存模块由:主存储器、信息块和闪存存储器接口寄存器等 3 部分组成。

        主存储器该部分用来存放代码和数据常数(如 const 类型的数据)。对于大容量产品,其被划分为 256 页,每页 2K 字节。注意,小容量和中容量产品则每页只有 1K 字节。从上图可以看出主存储器的起始地址就是 0X08000000,  B0、B1 都接 GND 的时候,就是从 0X08000000开始运行代码的。

        信息块,该部分分为 2 个小部分,其中启动程序代码,是用来存储 ST 自带的启动程序,用于串口下载代码,当 B0 接 V3.3,B1 接 GND 的时候,运行的就是这部分代码。用户选择字节,则一般用于配置写保护、读保护等功能,

        闪存存储器接口寄存器,该部分用于控制闪存读写等,是整个闪存模块的控制机构。

        闪存的读取

        内置闪存模块可以在通用地址空间直接寻址任何 32 位数据的读操作都能访问闪存模块的内容并得到相应的数据。读接口在闪存端包含一个读控制器,还包含一个 AHB 接口与 CPU 衔接。这个接口的主要工作是产生读闪存的控制信号并预取 CPU 要求的指令块,预取指令块仅用于在 I-Code 总线上的取指操作,数据常量是通过 D-Code 总线访问的。这两条总线的访问目标是相同的闪存模块,访问 D-Code 将比预取指令优先级高

        这里要特别留意一个闪存等待时间,因为 CPU 运行速度比 FLASH 快得多,STM32F103的 FLASH 最快访问速度≤24Mhz,如果 CPU 频率超过这个速度,那么必须加入等待时间,比如我们一般使用 72Mhz 的主频,那么 FLASH 等待周期就必须设置为 2,该设置通过 FLASH_ACR寄存器设置。

        使用 STM32 的官方固件库操作 FLASH 的几个常用函数。这些函数和定义分布在文件 stm32f10x_flash.c 以及 stm32f10x_flash.h 文件中。

        1.  锁定解锁函数

        在对 FLASH 进行写操作前必须先解锁,解锁操作也就是必须在 FLASH_KEYR 寄存器写入特定的序列(KEY1 和 KEY2),固件库函数实现很简单:

        void FLASH_Unlock(void);

        同样的道理,在对 FLASH 写操作完成之后,我们要锁定 FLASH,使用的库函数是:

        void FLASH_Lock(void);

        2.  写操作函数

        固件库提供了三个 FLASH 写函数:

        FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);

        FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);

        FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);

        顾名思义分别为:FLASH_ProgramWord 为  32 位字写入函数其他分别为 16 位半字写入和用户选择字节写入函数。这里需要说明,32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2,这与我们前面讲解的 STM32 闪存的编程每次必须写入 16 位并不矛盾。写入 8位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。

        3.  擦除函数

        固件库提供三个 FLASH 擦除函数:

        FLASH_Status FLASH_ErasePage(uint32_t Page_Address);

        FLASH_Status FLASH_EraseAllPages(void);

        FLASH_Status FLASH_EraseOptionBytes(void);

        这三个函数可以顾名思义了,非常简单。

        4.  获取 FLASH 状态

        主要是用的函数是:

        FLASH_Status FLASH_GetStatus(void);

        返回值是通过枚举类型定义的:

        typedef enum

        {

          FLASH_BUSY =
1,//忙

          FLASH_ERROR_PG,//编程错误

          FLASH_ERROR_WRP,//写保护错误

          FLASH_COMPLETE,//操作完成

          FLASH_TIMEOUT//操作超时

        }FLASH_Status;

        从这里面我们可以看到 FLASH 操作的 5 个状态,每个代表的意思我们在后面注释了。

        5.  等待操作完成函数

        在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。所以在每次操作之前,我们都要等待上一次操作完成这次操作才能开始。使用的函数是:

        FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)

        入口参数为等待时间,返回值是 FLASH 的状态,这个很容易理解,这个函数本身我们在固件库中使用得不多,但是在固件库函数体中间可以多次看到。

        6.  读 FLASH 特定地址数据函数

        有写就必定有读,而读取 FLASH 指定地址的半字的函数固件库并没有给出来,这里我们自己写的一个函数:

        u16 STMFLASH_ReadHalfWord(u32 faddr)

        {

        return *(vu16*)faddr;

        }
       

                                                                        点击(此处)折叠或打开                       
               
                                       
  •                                         //读取指定地址的半字(16位数据)
  •                                         //faddr:读地址(此地址必须为2的倍数!!)
  •                                         //返回值:对应数据.
  •                                         u16 STMFLASH_ReadHalfWord(u32 faddr)
  •                                         {
  •                                             return *(vu16*)faddr;
  •                                         }
  •                                         #if STM32_FLASH_WREN    //如果使能了写
  •                                         //不检查的写入
  •                                         //WriteAddr:起始地址
  •                                         //pBuffer:数据指针
  •                                         //NumToWrite:半字(16位)数
  •                                         void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
  •                                         {
  •                                             u16 i;
  •                                             for(i=0;i<NumToWrite;i++)
  •                                             {
  •                                                 FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
  •                                                 WriteAddr+=2;//地址增加2.
  •                                             }
  •                                         }
  •                                         //从指定地址开始写入指定长度的数据
  •                                         //WriteAddr:起始地址(此地址必须为2的倍数!!)
  •                                         //pBuffer:数据指针
  •                                         //NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
  •                                         #if STM32_FLASH_SIZE<256
  •                                         #define STM_SECTOR_SIZE 1024 //字节
  •                                         #else
继承事业,薪火相传
返回列表