本帖最后由 hexbei 于 2023-11-13 17:31 编辑
背景
一些项目中,有数据存储的需求,且读写较为频繁,每次读写数据量不大(几个或几十个字节),这种情况使用EEPROM是比较方便的选择。但如果不**在硬件上多挂一个外置eeprom的时候,也可以用单片机内部flash模拟eeprom来使用。
原理
下面以极海APM32F103为例,简单介绍如何实现模拟eeprom驱动。
APM32F103的内部flash,读取和写入可以按半字为单位操作。但在写入之前,需要先进行擦除。擦除的单位是一个页大小,为1024字节。
因此,简单的擦除和写入不能模拟eeprom的随机读写功能,需要额外的驱动算法来实现。
存储结构
我们使用内部flash的两个页轮流擦写的方式,实现数据的随机读写。
1. 每个页的前4个字节用来存储该页状态标志位,有三种:已擦除、待传输、有效。
2. 同一时刻,两个页中只有一个是处于“有效”的状态,数据读写都发生在该页中。
3. 页内以4个字节为单位划分存储单元。每个单元前两个字节是虚拟地址,后两个字节为实际存储数据。
4. 第一次上电初始化时,先擦除两个页,并设置第一页为“有效”。
5. 当其中一页写满时,另一页状态设置为“待传输”,并把数据从有效页复制到待传输页。复制完毕,设置待传输页为有效页,原有效页进行擦除并设置为“已擦除”。
6. 后续上电初始化,检查两个页的标志位,如果不满足上述第2点的条件,进行第4点中的操作。如果一个是有效页另一个是待传输页,进行第5点中的操作。
写入
内部flash页擦除后,页内每个地址的数据只能单次写入。为了实现eeprom的随机写入,我们采取虚拟地址+数据的结构,按物理地址顺序存储每一次的写入操作,并以最新操作为准。类似日志文件系统。
1. 每次以2字节虚拟地址+2字节数据为单位写入数据。
2. 为了区分有效数据和无效数据,4字节数据不能全为0xFF。因此规定虚拟地址不能为0xFFFF。
3. 所有数据按物理地址递增的顺序写入,地址增量为4个字节。
4. 写入前需要搜索当前页下一个可写入物理地址,也就是找到第一个无效数据(0xFFFFFFFF)的物理地址。
5. 当前页满了之后,按上一节中的操作处理。
读取
内部flash本身可以实现随机读取,但在我们模拟eeprom驱动的存储结构之下,略有不同。
读取的时候,按物理地址顺序搜索所有有效数据,直到找到与需读取虚拟地址匹配的存储单元,即可读出该存储单元的2字节数据。
工程文件
在极海sdk的基础上,实现eeprom.c/.h文件即可。
接口
注意
* 虚拟地址与实际flash地址不对应
* 虚拟地址范围是0~0xFFFE
* 虚拟地址可以任意指定,与实际存储顺序不对应
* 每个虚拟地址存放16位的数据
* 写入和读取都按16位数据为单位操作
地址分配
* 修改 EE_BASE_ADDRESS 指定eeprom数据在flash中的起始地址
* 结束地址为 EE_BASE_ADDRESS + EE_PAGE_SIZE * 2
* 最多可以存放 EE_PARA_MAX_NUMBER 个16位数据
* 如果空间不够,可以修改 EE_SECTOR_NUM 使用更多的扇区
|