嵌入式编程知识2 - 在应用层对NAND FLASH进行操作

前言:

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

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

#1.打开设备

这里需要注意的是,打开的设备结点是/dev/mtdN,而不是/dec/mtdblockN,原因可以参考: 

https://www.cnblogs.com/hnrainll/archive/2011/06/09/2076075.html   - 里面介绍了mtd与mtdblock的区别

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

#2.获取设备信息

#include <linux/types.h>

struct mtd_info_user {
     __u8 type;
    __u32 flags;
    __u32 size;     // Total size of the MTD

    __u32 erasesize;
    __u32 writesize;
    __u32 oobsize;// Amount of OOB data per block (e.g. 16)
    /*
 The below two fields are obsolete and broken, do not use them * (TODO: remove at some point) */

    __u32 ecctype;
    __u32 eccsize;
};


struct mtd_info_user mtd;

//The struct above is defined in <linux/types.h>. Not need redefine in our program.
ioctl(fd, MEMGETINFO,&mtd) ;
根据MEMGETINFO可以获得mtd的设备信息

 #3.擦除NAND FLASH

#include <mtd/mtd-abi.h>
#include <linux/types.h>

struct erase_info_user {
    __u32 start;
    __u32 length;
};

typedef struct erase_info_user erase_info_t;

erase_info_t erase;

//The struct above is defined in the above head file. Not need redefine in our pogram.
int isNAND, bbtest = 1;
ioctl(fd, MEMGETINFO,&mtd) ;
struct mtd_info_user *DevInfo = &mtd;
 
erase.length = DevInfo->erasesize;
// erase.length 表示的是擦除大小,也就是一块的大小,如128KB
// DevInfo->size 为某个/dev/mtdx的大小
// erasse.start应该是按块对齐递增
 
isNAND = (DevInfo->type == MTD_NANDFLASH) ? 1 : 0;

for (erase.start = 0; erase.start <  DevInfo->size; erase.start += DevInfo->erasesize) 
{
        if (bbtest) 
        {
            loff_t offset = erase.start;
            int ret = ioctl(DevInfo->fd, MEMGETBADBLOCK, &offset); //判断是不是坏块
            if (ret > 0) 
            {
                if (!quiet)
                    DEBUG ("\nSkipping bad block at 0x%08x\n", erase.start);
                continue;//发现是坏块,应该跳过
            } 
#if 0  //if not need this judge,disable it
            else if (ret < 0) 
            {
                if (errno == EOPNOTSUPP) 
                {
                    bbtest = 0;
                    if (isNAND) 
                    {
                        fprintf(stderr, "%s: Bad block check not available\n", DevInfo->dir);
                        return 1;
                    }
                } 
                else 
                {
                    fprintf(stderr, "\n%s: MTD get bad block failed: %s\n", DevInfo->dir, strerror(errno));
                    return 1;
                }
            }
#endif
        }

        if (!quiet)
        {
            fprintf(stderr, "\rErasing %d Kibyte @ %x -- %2llu %% complete.", \
                (DevInfo->erasesize) / 1024, erase.start,
                (unsigned long long) erase.start * 100 / (DevInfo->size));
        }
        if (ioctl(DevInfo->fd, MEMERASE, &erase) != 0) //执行擦除操作
        {
            fprintf(stderr, "\n%s: MTD Erase failure: %s\n", DevInfo->dir,strerror(errno));
            continue;
        }
}

#4.写NAND FLASH

    char IPLFile[] = "customer.jffs2";
    int readfd = 0;
    int readlen;
    printf("%s read\n",IPLFile);
    readfd = open(IPLFile, O_RDONLY);
    if(readfd == 0)
    {
        printf("OPEN %s ERROR, not to upgrade\n",IPLFile);
    }
    memset(Buffer , 0 , sizeof(Buffer));
    readlen = read(readfd, Buffer, sizeof(Buffer));
    printf("readlen = %d\n",readlen);
    if(readlen <= 0)
    {
        printf("buffer fread error \n");
        close(readfd);
        readfd = 0;
        return -1;
    }
    close(readfd);
    readfd = 0;  //清零
#if 1 //write
    {
        int num = (readlen + 2*1024-1)/(2*1024);
        int j = 0x0;
        int alwlen = 0x0;
        int cur_write_pos = 0;
        int write_ret = 0;
        int wlen = 0x0;
        int write_cnt = 0;
        printf("Start write\n");
        for(j=0x0; j<num; j++)
        {
            alwlen = 0x0;
            loff_t offset;
            cur_write_pos = 0;
            write_ret = 0;
            wlen = 0x0;
 
            offset = 0/*FlashDevice.MtdDevice[i].StartAddress*/ + j * 2*1024;
            lseek(fd, offset, 0);
            wlen = ((readlen - alwlen)>(2*1024)) ? (2*1024) : (readlen-alwlen);
            printf("+");
 
            while(cur_write_pos != wlen)
            {
#if 1
                //printf("wlen: %d,cur_write_pos: %d\n",wlen,cur_write_pos);
                write_ret = write(fd, Buffer + offset + cur_write_pos, wlen - cur_write_pos);
                if (write_ret < 0)
                {
                    printf("  (%d)\nFlashWrite failed, not erase?  (%d)\n", write_cnt, write_ret);
                    return -1;
                }
                else if (write_ret == 0)
                {
                    break;
                }
#endif
 
                cur_write_pos += write_ret;
            }
            write_cnt++;
        }
        printf("write  (%d)*2k\n", write_cnt);
        printf("finish write\n");
    }
#endif
    return 0;
}
 

#5.关于mtd的ioctl中更多的命令

#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)

#6.后言

这是在我在工作中所用到的对NAND FLASH的操作,如果想要跟多操作,可以参考mtd-util工具的源码。mtd-util工具开源,网上可以容易下载到。✧ (≖ ‿ ≖)✧ 

#7.参考博客

感谢:ヾ(*´▽‘*)ノ

[1]  在应用程序中实现对NandFlash的操作  - 摩斯电码

[2]  擦写linux分区 - Z-star

原创文章 103 获赞 158 访问量 8万+

猜你喜欢

转载自blog.csdn.net/csdnxmj/article/details/105761833