OpenEdv-开源电子网

 找回密码
 立即注册

扫一扫,访问微社区

正点原子全套STM32开发资料,上千讲STM32视频教程,RT1052教程免费下载啦...
查看: 859|回复: 4

STM32 片内FLASH模拟EEPROM的优化方法

[复制链接]

  离线 

16

主题

216

帖子

1

精华

高级会员

Rank: 4

积分
970
金钱
970
注册时间
2016-11-24
在线时间
156 小时
发表于 2017-7-28 14:54:14 | 显示全部楼层 |阅读模式
芯片:STM32F407,1M片内FLASH。首先要知道STM32F407的FLASH的每个扇区的大小并不都一样,第0-3扇区每个扇区是16K,第4扇区是64K,后面的 每个扇区是128K。而出于某些方面的考虑,我们需要把某些数据存储到FLASH中,也就是把FLASH当作EEPROM来使用,这时就有个问题,STM32F407的FLASH在写操作之前,必须保证写入地址的数据为OXFF,否则无法写入。如果数据为非0XFF,则需要先把该扇区擦除后才能操作。而STM32F407的固件库只提供了四个 FLASH擦除函数:
FLASH_Status FLASH_EraseSector(uint32_t FLASH_Sector,uint8_t VoltageRange);
FLASH_Status FLASH_EraseAllSectors(uint8_tVoltageRange);
FLASH_Status FLASH_EraseAllBank1Sectors(uint8_tVoltageRange);
FLASH_Status FLASH_EraseAllBank2Sectors(uint8_tVoltageRange);   
对于前面两个函数比较好理解,一个是用来擦除某个Sector,一个使用来擦除全部的 sectors。对于第三个和第四个函数,这里的话主要是针对STM32F42X 系列和 STM32F43X 系列芯片而言的,因为它们将所有的sectors 分为两个 bank。所以这两个函数用来擦除 2 bank 下的sectors的。 好,为FLASH_Sector_0~FLASH_Sector_11(对于我们使用的 STM32F407 最大是FLASH_Sector_11),对于这些函数的第二个参数,我们这里电源电压范围是 3.3V,所以选择 VoltageRange_3 即可。也就是说STM32F407FLASH不支持其他型号的芯片那种所谓的页擦除,如果我们存储数据在FLASH_Sector_11,那么在写入之前就要擦除整个128K的扇区,然后再往里面写数据,但这将需要1-2秒,如果在这段时间内突然就断电,那么写入FLASH中的数据将是不正确的。而且芯片的FLASH是有寿命的,如果我们不断的擦除,并且频率比较高,那芯片有可能就挂掉了。为此我们需要对FLASH模拟EEPROM进行优化。首先,为了提高安全性,直接使用FLASH_Sector_10FLASH_Sector_11这两个扇区,每个扇区是128K,加起来就是用了256K,那还剩下768K来给程序运行使用,这个是足够的。为了方便使用数据,建议将需要存储的数据做成结构体,比如
typedef struct
{
      U8saved[128];
      U8data[128];
      U32 total;
}savedinfo;
结构体的大小最好是4字节对齐。
对于FLASH操作的普通思路是先擦除扇区,然后再写数据,但如果要写入的数据也就几百个字节,那这128K的扇区是真浪费了,但不擦除又写不进去。事实上,只要对扇区擦除过一次之后,扇区内的数据每位都是1,这个才是写入数据的前提。那么可以理解为,只要我们要写入的地址的数据不是0,那就可以往里面写数据。这样一来,我们就可以把128K扇区分成N块,每次写一块,然后下次再写下一块。但有个问题,比如我们存储数据的结构体大小为400字节,那是不是可以把128K扇区分成256块,每块512字节?理论上可行,但实际上STM32F407的FLASH貌似是以2K为一块来操作,也就是说你往FLASH_Sector_10的起始地址0x080C0000写400个字节的数据,而0x080C0800(0x080C0000+2048)以内的数据都被改变了,400字节以外的地址的数据从OXFF变成了0!所以128K最少要分成64块,每块2K。我们从FLASH_Sector_10开始存储,存满了64块之后,接着从FLASH_Sector_11开始存(这时就把FLASH_Sector_10给擦除掉),等FLASH_Sector_11存满之后又从FLASH_Sector_10开始存(这时就把FLASH_Sector_11给擦除掉)。在存储的过程中,需要先按照分好的块来查找需要写入的地址的数据是否是0XFF,不是则继续查找下一块,如此循环下去。
       FLASH中读出数据的思路就是一个逆向的过程,先从FLASH_Sector_11的最后一块开始从后往FLASH_Sector_10地址开始查找,只要找到那个块的数据是非0XFF,就把数据读出来,而这个数据就是最新存储进去的数据。
       为了方便从FLASH中读取数据和写数据,在结构体中最好记录下当前所在的扇区和块。思路给出了,程序就不贴了,目前这个方法在使用中比较稳定,FLASH的写入操作由于不用频繁进行扇区擦除而加快了很多。

回复

使用道具 举报

  离线 

3

主题

53

帖子

0

精华

初级会员

Rank: 2

积分
145
金钱
145
注册时间
2017-7-29
在线时间
18 小时
发表于 2017-7-29 10:35:40 | 显示全部楼层
强,学习了
回复 支持 反对

使用道具 举报

  离线 

38

主题

267

帖子

0

精华

高级会员

Rank: 4

积分
723
金钱
723
注册时间
2016-7-22
在线时间
234 小时
发表于 2017-12-13 12:51:19 | 显示全部楼层
只要我们要写入的地址的数据不是0,那就可以往里面写数据。这样一来,我们就可以把128K扇区分成N块  ??

这句话实在不理解。既然扇区都规定了只能按扇区操作,又怎么能把扇区分成块来操作呢? 如果可以的话 那flash就没必要说成按扇区操作了

还有 flash模拟eep,eep是可以按位操作的,但是flash不行

这个跟spi flash操作应该是类似的,spi flash是按块操作的,比如是4k,那我会用一个4k的buff去保存块的数据,有需要修改的地方在buff里面进行修改,然后在把这个buff写进去。但是flash模拟却不行了,因为这个扇区太大,128k,我没办法去做一个128k的缓存。但是我有想过使用第一个扇区 16k 让程序从第二扇区开始存储,这样代码和模拟的flash就不冲突了
回复 支持 反对

使用道具 举报

  离线 

0

主题

17

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
292
金钱
292
注册时间
2017-11-24
在线时间
36 小时
发表于 2018-1-13 10:20:32 | 显示全部楼层
本帖最后由 枫天2017 于 2018-1-13 11:05 编辑
hi我歌月徘徊 发表于 2017-12-13 12:51
只要我们要写入的地址的数据不是0,那就可以往里面写数据。这样一来,我们就可以把128K扇区分成N块  ??
...

扇区0: IAP过渡代码,扇区1:eeprom,扇区2开始用户应用代码。不过这样要设置不少东西,类似于简化IAP功能。
回复 支持 反对

使用道具 举报

  离线 

38

主题

267

帖子

0

精华

高级会员

Rank: 4

积分
723
金钱
723
注册时间
2016-7-22
在线时间
234 小时
发表于 2018-1-13 10:42:07 | 显示全部楼层
枫天2017 发表于 2018-1-13 10:20
从扇区1开始放代码,扇区0就可以做eeprom了。不过这样要设置不少东西,类似于IAP功能

嗯嗯 就是修改起来麻烦~~ 有做过的 贡献一下代码啊
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则




关闭

报名原子哥新品发布会&粉丝见面会上一条 /1 下一条

正点原子公众号

QQ|联系我们|手机版|官方淘宝店|微信公众平台|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2018-10-18 08:56

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表
/* */