专题介绍:用FLASH来模拟EEPROM


基本信息

KQD系统一般需要一个外置的SPI FLASH或则外置EEPROM、外置铁电来保存数据。保存数据可能包含:

  • 系统块配置(如果在Fcc的配置中勾选了系统块文件,则系统块不和梯形图一起编译,而是单独下载,因此需要单独保存)。
  • IP地址,网络名称(一般通过系统块指定,如果配置了PNet或者Profinet,则需要单独保存)。
  • SMART系统的系统块、数据块、程序块。
  • 掉电保持数据。
  • 模拟量的出厂标定数据。
  • PLC项目文件,方便上载到电脑恢复梯形图。

KQD系统推荐使用外置的存储器来保存掉电数据,因为数据的保存一般来说是一个耗时操作,使用外置的存储器最大的优势就是不阻塞PLC的运行。对于常用的STM32或其兼容单片机,对内部FLASH进行擦除或编程操作时,内部FLASH对于CPU来说会短时变得不可用。在这种情况下,CPU会挂起一段时间,要么等待总线被释放,要么在RAM中运行等待操作完成标志。一般来说,这种系统的卡顿对于很多控制系统是不能忍受的。对于有些控制系统,可能只需要保存少量的参数数据,而且平时并不需要修改这些数据。或者是因为控制板的体积限制,外置存储器实在无法达成。或者是出于经济考虑,希望节约外置存储器的成本。针对这些情况,KQD也提供了一个Fee模块,可以用片内FLASH来模拟器EEPROM。

为什么要用FLASH来模拟EEPROM,而不是直接使用SPI FLASH的接口来直接操作内部FLASH呢?主要是出于以下考虑:

  • STM32F4的扇区太大了,大部分扇区的大小是128K。因为一个扇区编程前必须全擦,如果需要保存独立的多组数据,则每组数据要放在不同的扇区上。一方面空间过于浪费,另一方面STM32F4总共也没有多少个扇区。
  • FLASH的可擦写次数比EEPROM要小一个数量级,使用模拟方案可以使用磨损均衡算法,提高FLASH的使用寿命。

适合使用FLASH模拟EEPROM来保存的数据应该有以下特点:

  • 数据量不能太大,相对外置SPI FLASH,单片机内部的FLASH还是太小太宝贵了。
  • 数据不能频繁修改,因为修改数据需要操作单片机内部FLASH,会造成系统卡顿。

用户BANK需要直接跑代码,地址要固定,数据要连续,因此不能使用模拟EEPROM方案。同样的,因为SMART系统运行块需要直接跑代码,地址要固定,数据要连续,因此也不能使用模拟EEPROM方案。

FLASH模拟EEPROM的基本原理

要用FLASH模拟EEPROM,则需要至少两个可以独立擦除的扇区。我们将需要记录的数据,拆成更小的数据块:

然后将数据块按照顺序写入FLASH的某一个扇区:

此时,若需要修改数据块中的部分数据,且需要修改数据位于数据块1中。我们并不需要全擦整个扇区,而是将原来的数据块1标记为Garbage,在尾部创建一个新的数据块1即可:

随着旧的数据被标记为Garbage,新的数据在尾部追加,最终扇区0的空间将被消尽。此时如果仍然需要修改数据,则需要将扇区0中的有效数据拷贝到扇区1中去,并在扇区1中添加修改后的数据块:

最后将扇区1标记为Active,将扇区0标记为Garbage:

等到扇区1空间耗尽,则可以整个擦除扇区0,再将扇区1中的有效数据拷贝到扇区0中去,然后将扇区0标记为Active,将扇区1标记为Garbage。

结合上述原理,我们知道,不论是扇区还是数据块,都需要一个头部来保存若干状态:

  • Erased:表示此扇区或数据块刚被擦除。
  • Copy:表示此扇区或数据块正在被创建。
  • Active:表示此扇区或数据块为有效。
  • Garbage:表示此扇区或数据块被废弃。

不论是数据块,还是扇区,都只能进行如下的单向状态转换:

同时可以知道以下特性:

  • 至少需要两个扇区来实现EEPROM模拟。
  • 数据需要分块存储,在KQD系统中,为了管理方便,每个块固定为512字节。
  • 因为需要额外的保存头部,一个扇区实际可以保存的数据大小略小于扇区大小。
  • 如果实际保存的数据远小于扇区大小,则可以显著减少全扇区擦除和拷贝的操作次数,减少系统的卡顿。

在Designer中的配置实践

使用MemIf手动保存数据

因为需要使用内部FLASH,首先需要在Project中,分配User_Fls空间,这里以STM32F4举例:

如图所示,在User_Fls下面添加两个区间:User_FeeA、User_FeeB。这两个区间分别使用单片机的最后两个扇区,都是128K大小。

如果是STM32F1,配置的方式类似。因为STM32F1的擦写页很小(2K、1K),这里可以直接输入希望分配的大小:

整体的FLASH布局如下:

考虑到STM32H7一般为高规格PLC,STM32H7目前并不支持FLASH模拟EEPROM。

然后,需要添加MemIf蓝图,在蓝图中添加Fee和FLASH_Fls模块:

选择FLASH_Fls模块,在Chip下面添加两个芯片FeeA、FeeB,分别绑定Project中分配的FLASH空间User_FeeA、User_FeeB。

选择Fee模块,在Chip下面添加Chip0。首先,需要指定Chip的可用大小,对于F4来说,扇区是128K大小,为了留有余量,我们指定可用空间为64K。如果是F4,因为扇区是32K大小,我们指定可用空间为16K。然后在Chip0的Sector下面,添加SectorA、SectorB,分别指定FLASH_Fls模块中的芯片FeeA、FeeB:

选择MemIf_Fe模块,在Block下面添加一个手动读写块Block0。底层接口Lower选择Fee,模块选择Fee,芯片选择Chip0,大小选择1000个字节:

执行编译命令,MemIf_Fe会在MemIf中添加这个数据块,并自动分配空间,建立调用关系:

将此项目上传到服务器,并烧录固件到单片机。使用Application Editor上传PLC类型,固件指令中便提供了MemIf的读写指令,使用这些指令做简单的梯形图,便可手动对读写功能进行测试:

如图梯形图所示,闭合M0.1,则在上升沿将VB100开始的1000个字节保存到内部FLASH。闭合M0.0,则在上升沿将保存的数据恢复到VB100开始的100个字节。

使用NvM实现掉电保持

要实现自动掉电保存,首先需要添加NvM蓝图,并在NvM_Fe中添启用掉电保持:

选择NvM模块,在NvM_Fe_RetentiveBlock下面添加数据保存点R0,指定下级接口Lower为Fee,模块为Fee,芯片为Chip0:

执行编译命令,NvM会在MemIf中添加这个数据块,并自动分配空间,建立调用关系:

将此项目上传到服务器,并烧录固件到单片机。使用Application Editor上传PLC类型,在系统块中配置掉电保持范围

将此系统块下载到PLC,通过通讯的方式修改变量,观察重新上电后,变量值是否保持。

使用Fee保存项目文件

切换到PLC系统蓝图,选择Fcc模块,选择File节点,使能ArchiveBlockEnabled:

执行编译命令,NvM会在Fa中添加文件Fcc_Block_ArchiveBlock。指定下级接口Lower为Fee,模块为Fee,芯片为Chip0:

执行编译命令,Fa会在MemIf中添加这个数据块,并自动分配空间,建立调用关系:

将此项目上传到服务器,并烧录固件到单片机。使用Application Editor上传PLC类型。下载梯形图时,在下载对话框中可以选择是否下载项目文件。上载梯形图时,也可以选择从PLC恢复项目文件。