天天看點

在應用程式中實作對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。

以上隻是本人在工作中遇到的,僅供參考。