AUTOSAR FEE学习

  • 前言

    FEE,即Flash EEPROM Emulation,指使用MCU片上的Flash来模拟EEPROM功能,实现数据的可掉电存储。相比于传统的外挂存储器,使用模拟EEPROM具有更快的访问速度、更简单的PCB设计、更强的抗干扰能力以及对OEM/TireN来说很重要的一点:更低的成本控制,毕竟能用一块芯片解决的问题就不会用两片。

    本文主要结合过往项目开发经验记录下自己用过的一种模拟EERPOM存储机制。该机制的核心思想为:将Flash划分为多个Sector,当剩余空间不足时,将最早写满的Sector内容拷贝到当前使用的Sector中,然后将最早的Sector擦除以释放空间。

    这种方法只会擦除已写满的Sector并且每个Sector机会相同,使整个存储空间保持一个比较均匀的擦写频率,避免了对局部地址/空间反复擦写,过早耗尽Flash寿命。

  • Sector

  • Sector State

    为了便于管理,Sector定义了五种工作状态UNDEF、ERASED、USED、FULL和REQUEST TO ERASE,各状态之间转换流程如下图所示:

AUTOSAR FEE学习_第1张图片

    UNDEF —— 未定义状态,比如MCU芯片首次使用Flash为空的时候,或者Flash被擦除的时候,准确来讲只要没有有效的sector header信息都认为是UNDEF;

    ERASED —— Sector已经成功擦除,准备好被写入;

    USED —— Sector已经写入了数据,并且后续可以正常写入;

    FULL —— Sector已经写不下新数据;

    REQUEST TO ERASE —— 请求擦除已满的Sector,如果擦除成功会变为ERASED状态,如果擦除异常,比如Sector只擦除一部分(头部)信息后被打断,就会进入UNDEF状态。

    为了记录上述这些状态信息,Sector在头部预留了一段空间专门用来存放头部信息(Sector Header)。

  • Sector Header

    Sector Header的定义如下:

AUTOSAR FEE学习_第2张图片

    Pattern —— 固定值0xCAFE;

    Ident —— 存放Sector State:

            0x00:UNDEF

            0x01:ERASED

            0x02:USED

            0x03:FULL

            0x04:REQUEST TO ERASE

            0x05:START(可以当作USED,只是Content域存放内容不同)

    Content —— Sector change counter,不同Sector取值不同(依次累加),可以表明Sector的使用次序,适用于ERASED、USED和FULL,REQUEST TO ERASE/START不适用,前者取值为0,后者存放地址信息(低三个字节),用来指明从Sector中何处开始可以写入数据块;

    Checksum —— 对前面六个字节(Pattern + Ident + Content)的CRC16校验值。

    在提到Flash擦写时,有一个关键参数需要注意:最小擦写单位。不同MCU可能不一样,具体可以参考数据手册,这里我们用的DFlash最小一次可写入8Bytes,而Sector Header长度刚好也是8Bytes,这样处理起来会简单很多。

AUTOSAR FEE学习_第3张图片

  • Block

    在Sector Header area之后就是数据存放空间,数据存储以Block为单位,每个Block由Block Header和User Data组成。

  • Block Header

    Block Header的定义如下:

AUTOSAR FEE学习_第4张图片

    Preamble —— 固定值0xA53C96,每半字节包含两位"1"和两位"0",用来标识是否为Block Header开始;

    Status —— Block的状态信息,比如安全等级等;

    PersistentID —— Block的身份标识,若无指定配置工具会自动根据Block名称及长度计算获得,不同Block该值不同;

    Length —— User Data数据部分的长度;

    HeaderCrc —— Block Header前8个字节(Preamble + Status + PersistentID + Length)的CRC16校验值;

    BlockCrc —— User Data数据部分的CRC32校验值,使用HeaderCrc作为Start value。

  • User Data

    User Data的长度是不定的,前面说过DFlash的最小编程单位(Page)为8Bytes,为了满足这个限制以及保证字节边界对齐,当整个Block的长度不是8的倍数时需要在User Data的最后增加填充字节。

AUTOSAR FEE学习_第5张图片

    因此,无论是短至1个字节的数据,还是长达几十上百个字节的数据,在Flash中它们的Block都是彼此紧挨着连续存储的。

  • Reorganization

    重组(Reorganization)是FEE存储管理的核心机制,当Sector快满或达到重组阈值时会触发重组动作,将只存在于最早写满(FULL)的Sector中的Block的最新条目拷贝到当前使用(USED)的Sector中,然后,擦除最早已满的Sector以释放其空间备用。

  • Reorganization thrshold

    重组有软(SSR)、硬(HSR)两种阈值:

    Soft Sector Reorganization threshold(SSR)特点:

        -在IDLE期间进行阈值检查

        -拷贝数据的过程可以被用户请求打断

        -可以接受和执行用户请求

    Hard Sector Reorganization threshold(HSR)特点:
        -执行写操作前进行阈值检查

        -拷贝数据的过程具有最高优先级不可打断

        -只有在重组完成后才可执行用户请求

    

下表给出了HSR和SSR的计算方法:

number of Sector

Layout Size

Threshold type

Algorithm

>2

Layout < smallest logical Sector

HSR

smallest Sector size[Bytes] + 1

SSR

HSR * 1.5

Layout >= smallest logical Sector

HSR

(smallest Sector size[Bytes] + 1) + (2 * biggest Block[Bytes])

SSR

HSR * 1.5

2

/

HSR

smallest Sector size[Bytes] + 1
/

SSR

HSR

Layout Size:NvM所有Block条目的总大小(包括每个Block的Header部分)。

注意:当HSR/SSR大小不为Page的整数倍时需要向上取整到Page的整数倍。

  • Reorganization demonstration

    下面以一个简单的示例看下重组过程,假设有4个Sector,每个Sector大小为10KB(10240Bytes),NvM的Block总大小小于10KB,根据上面的表格,可计算出HSR = 10KB + 1B = 10241Bytes,向上取整到10248Bytes,SSR = 10241B * 1.5 = 15361.5Bytes,向上取整到15368Bytes。

    我们为4个Sector进行逻辑编号Sector 0~Sector 3,之所以说是逻辑编号,是因为此编号和物理上的存储空间并不是绑定关系,按照编号顺序(也是Sector的擦除顺序)为每个Sector分配Sector change counter(ScCnt)。

AUTOSAR FEE学习_第6张图片

    初始从Sector 0开始写数据,首先在头部写入USED表明当前使用的是Sector 0,然后就是正常的数据写入操作,当Sector 0写满时会在头部写入FULL表明已满,接着切换到下一个Sector(即Sector 1)继续数据写入,当然在写入数据前会在Sector 1头部写入USED表明使用状态。

AUTOSAR FEE学习_第7张图片

    随着数据的不断写入,由Sector 1写到了Sector 2,前面我们计算过SSR = 15368Bytes,HSR = 10248Bytes,当前剩余一个空的Sector 3有10240Bytes,因此当Sector 2剩余空间低至15368B - 10240B = 5128Bytes时会达到SSR阈值,当剩余空间低至10248B - 10240B = 8Bytes时会达到HSR阈值。

AUTOSAR FEE学习_第8张图片

    达到SSR/HSR阈值后就会触发重组动作,会将最早(oldest)写满的Sector 0上的数据搬移到当前正在用的Sector 2内,并且只搬移Sector 0独有数据的最后一次有效存储,这里Sector 0上有A、B、C三个Block,B在Sector 1上有最新的存储,C在Sector 2上有最新的存储,只有A是Sector 0独有的,因此将Block A的最后一次存储拷贝到Sector 2中,拷贝完之后请求擦除Sector 0。

AUTOSAR FEE学习_第9张图片

    Sector 0擦除成功后,其ScCnt也会更新,新的数据会接着Sector 2拷贝完的Block A后继续写入,下一次阈值触发将会在Sector 3写入过程中发生。

AUTOSAR FEE学习_第10张图片

    你可能注意到SSR的触发总是早于HSR,那HSR岂不是不起作用了吗,不要忘了SSR的特点,SSR只在空闲时作判断而且是可被打断的,最坏情况下有可能SSR迟迟重组不了,HSR作为最后一道防线,一旦达到就必须重组完成才会执行其它动作。

  • Number of Sector

    上面的例子是Sector数量大于2时的情况,如果Sector数量只有2个相对来说会简单一些,首先,SSR和HSR相等,在Sector几乎写满的时候触发重组;其次,重组时只要把Sector内所有Block的最新数据拷贝到下一个Sector即可,不用判断Block是否是该Sector独有的、是否在其它Sector上有更新的存储。

    在DFlash总大小不变的情况下,Sector数量越多,每个Sector就会越小,Sector被写满的时间也就越快,从而触发重组的次数越多,也就是Sector的擦除次数越多,反之,Sector数量越少,每个Sector就会越大,Sector被写满的时间越长,触发重组的次数越少,擦除的次数也会越少。

    那么,为了减少擦除次数、延长DFlash寿命,是不是Sector数量越少越好呢?不尽然,这和诸多因素有关系:每个Sector大小是否相同、数据Block的总大小是否一样、数据写入速率是否相等。如果以上这些因素都一样,那么分2个Sector还是4个Sector(或者更多)对整个DFlash的擦除次数其实是一样的。

AUTOSAR FEE学习_第11张图片

  • Block Redundant

    通常NvM的Block配置会采用冗余(Redundant)方式,即每个Block在写入的时候会写两次,以消耗更多空间来换取数据存储的可靠性。Block还有其它的存储方式,具体可以参考NvM模块的规范描述。

  • Data Corruption

    虽然“谨慎能捕千秋蝉,小心驶得万年船”,但难免也会有捕空、翻船的事发生,当发生数据损坏(HeaderCrc/BlockCrc校验失败)的时候,FEE会进行修复处理,由于读取数据都是读取最后一次的存储,在此之后肯定不会有更新的存储,所以如果发现数据出错,那么只用反向往前查找过往数据即可,将查找到的第一个有效数据(最近一次的数据)重新写入Sector内。

AUTOSAR FEE学习_第12张图片

AUTOSAR FEE学习_第13张图片

  • Initialize

    初始化阶段除了做一些状态、变量设置外,还会检测当前活动的Sector以及为Block建立Cache。

  • Active Sector

    为了后续操作需要检测当前正在使用的是哪个Sector,并且将所有Sector按照ScCnt的从小到大排序,同时给每个Sector分配逻辑编号(从0开始),在前面的示例中有提过ScCnt间接反映了各Sector的先后使用次序,所以排好序之后,编号0的Sector就是最早(oldest)使用的Sector。

  • Cache

    为了加速数据存取,提高模块运作效率,在初始化阶段会为所有Block建立Cache,本质上就是记录每个Block的地址信息,这样在后续数据操作(如ReadAll)时可以快速定位、一发入魂。当然,正常操作期间(如Write Block)需要及时更新Cache信息,如果要读取的某个Block在Cache中没有记录,那么就会进行正常的查找操作。

你可能感兴趣的:(AUTOSAR学习,学习,中间件)