关于NandFlash在实际产品使用上的一些经验
自己从第一次接触Nandflash到现在也有将近两年的时间了,从刚开始的无从下手到现在的略知一二。
回过头来看自己的学习历程,积累了很多无论你如何Google和泡坛子都学习不到的经验。现在拿出来分享给大伙,算是对集体智慧的一种回馈吧。
首先说一下Nandflash本身的一些缺陷和优势:
优势:
1,速度快。这个貌似没啥可说的,对于现在动辄上G的芯片容量,速度是必要的基础。
2,便宜。虽然赶不上硬盘,但是在嵌入式设备里面绝对是性价比杠杠的。
3,没了。除了傻快傻便宜,真没嘛优势。
劣势:
1,可靠性不高。这里所说的可靠性分为两个方面,第一是芯片出厂的时候就伴随着一定概率的缺陷。你们懂得,我说的是坏块。这个缺陷会令很多初入此行的孩纸们丢掉工作,后面会详细说。第二个是芯片使用过程中的不稳定,当然还是在说会产生坏块的问题。。。
2,不能片上运行程序。由于无法直接寻址,所以就不可能做到片上运行程序。这是很多网络上文章经常提到的一点,实际上对生活影响不大。因为现在内存便宜的很,一般的家用嵌入式设备对内存没有这么苛刻的要求。
3,芯片操作复杂。不同于norflash,nandflash没有这么容易操作。我说的操作主要是指不通过驱动程序直接靠编程完成对于flash的存取。但是我还是要说上面的话:实际上对于生活影响不大。因为目前大部分的民用嵌入式设备都有操作系统,一般为linux。linux为flash设备提供了mtd驱动层,我们对于flash的操作都被抽象成了统一的接口甚至是设备符号,无需关心底层实现。
下面来说说实际使用时候的一些心得体会:
一,什么样nandflash分区大小是合理的?
考虑到业务的需要,一般我们不会将整个芯片完全当作一个整体来使用。就如同你使用电脑的时候不会只给硬盘分一个区一样。主要是为了防止对分区进行改动或者重新烧录的时候会丢失全部的数据。
而如何分区才是合理的呢?我归纳主要有以下几点需要注意:
1,任意一个分区的大小不要超过操作系统所能操作内存的2/3。比如你有128M内存,linux可以支配其中的96M,那请不要将nandflash的分区设计为大于64M。
这样的考虑主要是因为,如果未来你需要升级这个分区,尤其是通过网络升级这个分区。如果你的升级方式不是增量式的,那么你必须有一段与flash分区大小一致内存空间用来存放镜像。这个时候假设你的flash分区为96M,那么你将不可能完成更新。因为你没有足够的内存空间。除非实时解压缩实时烧录,风险很高。
2,分区一定要给坏块留出足够的空间。我最早接触到nandflash的时候就犯了这个错误,uboot大小200k,我给它划分的空间为256k,结果遭遇坏块,上下移动都没有空间,非常杯具。
拿目前嵌入式系统比较常用的128M nandflash,他没产生一个坏块,空间损失128k。也就是说,如果你设计分区大小为512k,遭遇两个坏块,实际空间只有256k了。
通过大量设备生产后所统计出来的结果,一般nandflash出厂的坏块基本不会超过4块。位置不固定。所以我的推荐是,如果你的某些分区容量较小,比如设计使用容量为512k,请划分该分区为1M以避免坏块。如果分区容量较大,比如60M,请划分64M。这样比较合理。
3,如果被划分的分区将会使用文件系统,比如Yaffs之类,请不要划分的过小。比如你有一个分区用来存储配置文件,你认为只需要3M就可以解决问题。但实际上你会发现,这个分区只要一mount上,就已经被占用了2M,因为文件系统自己会规划出来一部分区域。你自己能操作的空间只剩下1M了,与设计目标产生巨大的冲突。请适当调整大小,并同时参考2号建议。
二,如何对nandflash分区进行合理的规划?
这里所说的规划指flash要如何进行逻辑上的区分,比如要分几个区等。
这个问题说起来比较复杂,因为不同的应用有不同的设计目标。有些提供可能简单的分两个区甚至不分区就能解决问题,而有些可能会很复杂。
这里我拿我所经手的项目举例子:
项目为iptv机顶盒,使用linux操作系统,使用uboot作为引导程序。
我的分区如下:
1M,uboot
1M,uboot-config
3M,kernel
32M,rootfs
16M,backup-rootfs
64M,apps
5M,config
uboot如果升级失败,将会带来灾难性的后果。但是有些uboot启动的参数需要被动态的更改,所以必须要把uboot存储参数的部分与uboot分离。所以uboot被分为两个区分别存储。
kernel无需多说,由于附带的驱动较多3M是一个合理的数值。
rootfs指linux所依赖的根文件系统。包括busybox以及实现最小系统所必须的文件。
rootfs-backup为备份根文件系统,里面存放最小系统所必须的文件以及系统恢复用的程序。
apps为机顶盒程序以及对应驱动的存放分区,为flash中容量最大的部分。我们将所有自己编写的程序以及驱动都放置于这个分区,未来升级和维护都会变得很容易。
config分区存储应用程序所依赖的一些配置文件。单独一个分区存放是为了避免用户程序分区被升级时,每一个用户自己的设置以及信息不会丢失。
我这里要特别说一下uboot部分。
uboot是整个nandflash的灵魂,没有他系统就无法正常启动,甚至无法正常初始化内存。当然uboot只是一种程序,他开源,易于使用,大伙都爱用它。亲,支持哦~
在我们的项目中,uboot一直没给我们找什么麻烦。但是到了工厂生产的时候,却吃了大亏。100片nandflash烧录完有超过10片无法正常启动。为什么呢?原因如下:
nandflash在出厂的时候一定会保证第一个块不是坏块,在我们所使用的芯片里,就是前128K绝对可以使用。但是后面的块就无法保证了。我们为uboot划分了512K空间,本来觉得就算是有坏块也会跳过去,没有所谓。
但是我们忽略的一个雷人的问题……那就是uboot被烧录器烧录完以后,已经因为坏块导致自己被烧录的支离破碎。当cpu将第一块数据读取到内存中并运行的时候,这部分代码不具备跳坏块读取的能力,自然而然的uboot其余的部分就无法正常读取,自然系统将会无法启动……
如何解决呢?
方法说简单也简单,说复杂也复杂。我们需要首先编译一个小于128K什么功能都不带但是完整的uboot。通过这个uboot引导起来以后再从flash里面读取另外一个完整功能的uboot到内存,然后引导这个uboot然后再引导linux。这就是传说中的二段跳。
所以在我们的系统分区中,uboot的那1M分区,实际上包含了两个uboot。
前128k一个,后面也许紧贴着也许隔若干个坏块又是一个uboot。这样就避免在工厂生产出来的uboot无法启动问题。同学们一定要切记!
基本上就是这些,下一次有时间会说说如何通过uboot实现升级失败后的启动分区切换,来完成灾难拯救的任务。