【原创】飞思卡尔Kinetis系列Flash烧写数据需要注意的问题
0赞话说自打落脚AET开始写技术体博客2年多以来,上个月还真是第一次断了更,想起来很惭愧也有点自责,但是也是无可奈何(咳咳,怎么搞地还有点押韵了),上个月还真是自己工作以来最忙的一个月(黑色八月啊有木有,呵呵),几乎全身心投入到工作中了,真是一丝时间也抽不出来,不过再忙总算也是挺过来了,哈哈,趁着九月份还没有结束,赶紧趁着夜深人也静的时候更新一篇再说,呵呵,走起…
废话不多说了,直接上正题了哈。话说,重要和敏感数据的掉电保存和可靠读写一直是嵌入式系统中比较常见到的需求,比如说产品校准数据的保存、工作参数的存储和产品Firmware信息及产品序列号的写入等等,而对这些类似的无需频繁操作的数据,无论从成本考虑还是资源利用率上来说,随着MCU自带的Flash空间越来越大,很多工程师们倾向于使用内部冗余的Flash作为这些数据的存储介质而无须使用传统的EEPROM,毕竟大多情况下代码空间并没有充分的占用整个芯片的Flash空间,所以剩余的Flash空间(必须大于一个Sector)则可以作为一个数据备份空间来用。不过相比于传统的EEPROM存储数据,Flash空间存储数据的方法的确是有一些其局限性和特别注意的地方。下面我就以飞思卡尔公司的Kinetis系列为例,列出一些我们在使用Flash烧写数据时需要特别注意的问题:
1. 同一地址的Flash空间不能连续写两次数据,而必须遵守先擦除再写入的原则,这是由Flash的工作机制决定的,即Flash的每一位只能由1写成0而不能由0写成1(具体原理,google一下就了然了),所以如果想向某一个地址的Flash空间写入数据则必须先将其擦写成全1然后再写入数据(是1的位不动,是0的位则写0)。不过Flash的最小擦除单位不是字节而是扇区(Sector),而不同的芯片其Sector的大小也不一样,比如Kinetis K系列,其Sector Size为2048个字节,L系列为1024个字节,而E系列则为512个字节。既然原理搞懂了,那我可以举个例子,如果我们往同一地址的Flash空间连续写数据则需要每次写入前先将该地址所在的扇区擦除然后再写入,而如果我们往同一个扇区不同地址的Flash空间写入数据则不需要每次擦除扇区而是等整个扇区写满后再执行一次擦除操作即可。当然,读操作是不受上述条件限制的,这个可以放心,哈哈;
2. 如果想选择Flash作为数据保存的空间,建议数据烧写的首地址为扇区Size的整数倍以避免空间的浪费,另外该数据所要烧写地址所在的扇区也建议选择整片Flash空间的最后面的扇区,防止代码空间对这部分数据空间的覆盖,做好保护工作;
3. 这一点需要特别注意,Flash读写操作都是由MCU自己通过其内部Flash Controller来实现的,这就会出现一个问题,就是擦写Flash的指令会与程序正常执行的读指令操作会冲突(因为FlashController只有一个),从而导致CPU Lock错误复位的现象。解决这个问题的方法就是将擦写Flash的指令Copy到RAM中执行同时期间关掉中断响应从而避免冲突的发生,另外,飞思卡尔Kinetis系列也针对此类冲突的发生增加了一个stall机制(通过配置MCM_PLACR寄存器中的ESFC位),即在Flash被其他资源占用而外部再次发生读写请求的时候芯片自动将CPU stall住避免错误复位,不过通常的建议是这两者同时都用起来以提高系统的可靠性。至于怎么实现这两种操作,下面我就给出KE系列相关处理的底层代码(基于IAR),如下图1,只需要将Flash_LaunchCMD这个启动擦写函数声明成__ramfunc类型,然后在系统的启动代码部分会有一个对ramfunction代码copy到ram中的一个操作,如图2:
好了,今晚搞的有点晚了,看来搁置了一个多月手感仍在啊,哈哈,赶紧洗漱睡觉了。未完待续~