天天看点

在应用程序中实现对NandFlash的操作

以​​TC58NVG2S3ETA00​​ 为例:

下面是它的一些物理参数:

图一

​​

在应用程序中实现对NandFlash的操作

图二

在应用程序中实现对NandFlash的操作

图三

在应用程序中实现对NandFlash的操作

图四

在应用程序中实现对NandFlash的操作

图五

在应用程序中实现对NandFlash的操作

图6-0

在应用程序中实现对NandFlash的操作

图6-1

在应用程序中实现对NandFlash的操作

说明一下,在图6-1中中间的那个布局表可以看做是实际的NandFlash一页数据的布局,其中Data区域用于存放有效的数据,也就是我们可以通过类似read、write、pread、pwrite可以访问的区域,那每页中的64字节的OOB区域是无法通过前面的几个函数访问的,他们会自动跳过OOB区域,访问OOB区域需要借助特殊的命令。

简单说明一下:Data A(512B)对应的ECC校验码存放在ECC for Data A(4 byte)中,OOB A (8byte) 对应的ECC校验码存放在紧接着的下一个ECC for Data A(4 byte)中,虽然用4字节存放ECC,但是对于本例,ECC只占3个字节。在实际使用中如果解决方案中用不到OOB A/B/C/D,可以不用管他们对应的ECC,只需要关心Data区域对应的ECC。如果使能了硬件ECC,硬件会自动把计算生成的ECC写到OOB中。读NandFlash需要按页读,即一次读一页;写NandFlash需要按页写,即每次写一页;擦除NandFlash需要按块擦,即每次要擦除一块。

对与NandFlash等块设备的访问操作,mtd-utils工具集中提供了非常好的支持(可以到​​http://www.linux-mtd.infradead.org/​​​进行了解),要使用mtd-utils工具集首先需要搞到mtd-utils的源码,并且使用目标设备上的交叉工具编译链进行编译,具体方法可以参考:,其中介绍了如何生成可以再目标板上运行的mtd-utils工具。关于mtd-utils工具的使用可以参考其中介绍了mtd-utils中常用的工具。

我们可以参考mtd-utils中工具的实现,从而完成在自己的应用程序中实现对NandFlash的操作。常用的命令如下:

#define MEMGETINFO        _IOR('M', 1, struct mtd_info_user)

#define MEMERASE        _IOW('M', 2, struct erase_info_user)

#define MEMWRITEOOB        _IOWR('M', 3, struct mtd_oob_buf)

#define MEMREADOOB        _IOWR('M', 4, struct mtd_oob_buf)

#define MEMLOCK            _IOW('M', 5, struct erase_info_user)

#define MEMUNLOCK        _IOW('M', 6, struct erase_info_user)

#define MEMGETREGIONCOUNT    _IOR('M', 7, int)

#define MEMGETREGIONINFO    _IOWR('M', 8, struct region_info_user)

#define MEMSETOOBSEL        _IOW('M', 9, struct nand_oobinfo)

#define MEMGETOOBSEL        _IOR('M', 10, struct nand_oobinfo)

#define MEMGETBADBLOCK        _IOW('M', 11, __kernel_loff_t)

#define MEMSETBADBLOCK        _IOW('M', 12, __kernel_loff_t)

#define OTPSELECT        _IOR('M', 13, int)

#define OTPGETREGIONCOUNT    _IOW('M', 14, int)

#define OTPGETREGIONINFO    _IOW('M', 15, struct otp_info)

#define OTPLOCK            _IOR('M', 16, struct otp_info)

#define ECCGETLAYOUT        _IOR('M', 17, struct nand_ecclayout_user)

#define ECCGETSTATS        _IOR('M', 18, struct mtd_ecc_stats)

#define MTDFILEMODE        _IO('M', 19)

#define MEMERASE64        _IOW('M', 20, struct erase_info_user64)

#define MEMWRITEOOB64        _IOWR('M', 21, struct mtd_oob_buf64)

#define MEMREADOOB64        _IOWR('M', 22, struct mtd_oob_buf64)

#define MEMISLOCKED        _IOR('M', 23, struct erase_info_user)

打开设备

这里需要注意的是,打开的设备结点是/dev/mtd?,而不是/dec/mtdblock?,原因可以参考:其中介绍了mtd与mtdblock的区别。

fd = open ("/dev/mtd0", O_SYNC | O_RDWR);

获取设备信息

#include <linux/types.h>

structmtd_info_user {

__u8 type;

__u32 flags;

__u32 size; // Total size of the MTD

The below two fields are obsolete and broken, do not use them * (TODO: remove at some point) */

ioctl(fd, MEMGETINFO,&mtd) ;

其中type可以用来区分是NorFlash还是NandFlash。

擦除NandFlash

写NandFlash

这里分为写数据区和写OOB区

写数据区,对于本例一次要写一页,也就是2KB,写OOB区,对于本例可以操作的只有32字节,剩下的32字节用于存放ECC。

对于写NandFlash,有的设备支持一次性把data和oob一块写进去。代码如下:

#define MEMEWRITEPAGE _IOWR('M', 23, struct mtd_epage_buf)

#define MAX_PAGE_SIZE 8192

#define MAX_OOB_SIZE 512

/*

* Buffer array used for writing data

*/

unsigned char writebuf[MAX_PAGE_SIZE];

char oobbuf[MAX_OOB_SIZE];

读OOB

读OOB跟写OOB类似,只不过使用的命令是MEMREADOOB。

以上只是本人在工作中遇到的,仅供参考。