linux 对MTD分区nand flash的烧写和读取

Posted liqinghan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux 对MTD分区nand flash的烧写和读取相关的知识,希望对你有一定的参考价值。

使用mtd-utils工具实现对flash的升级分区的烧写yaffs2

yaffs2的格式是根据所使用的nandflash来制作的,不同的nandflash,得到的yaffs2是不一样的,具体可以参考自己所用的nandflash,以及生成yaffs2文件系统的工具mkyaffs2image。
yaffs2包含了oob数据,所以写flash的时候要分开,本文所使用的是256M oob是64bit,page是2048byte-2kByte,block=64page制作的yaffs2的大小是(2048+64)的倍数!
每次写入是按页(page)的大小写入,而擦除是按照块来的,坏块也是按照块来的,如果当前块是坏的就必须跳过该块!
下载mtd-utils源码!

yaffs2的写入函数

?
int mtd_write_yaffs2_skip_bad(libmtd_t desc,const struct mtd_dev_info *mtd, int fd, int eb, int offs,
          const char *img_name)函数用来烧写flash,如下:
{
    int tmp, ret, in_fd, len, written = 0;
    int write_eb_num,i;
    int data_length,left_to_write,writesize;
    off_t seek;
    struct stat st;
    char *buf,*temp,*dataAddr,*oobAddr;
    
    if (offs < 0 || offs >= mtd->eb_size) {
        errmsg("bad offset %d, mtd%d eraseblock size is %d",
                   offs, mtd->mtd_num, mtd->eb_size);
        errno = EINVAL;
        return -1;
    }
    if (offs % mtd->subpage_size) {
        //start address must align to page (2048)0x800
        errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
            offs, mtd->mtd_num, mtd->subpage_size);
        errno = EINVAL;
        return -1;
    }
    in_fd = open(img_name, O_RDONLY | O_CLOEXEC);
    if (in_fd == -1)
            return sys_errmsg("cannot open "%s"", img_name);
    
    if (fstat(in_fd, &st)){
            sys_errmsg("cannot stat %s", img_name);
            goto out_close;
    }
    
    len = st.st_size;
    if (len % (mtd->subpage_size + mtd->oob_size)){
        errmsg("size of "%s" is %d byte, which is not aligned to "
               "mtd%d min. I/O size %d, it is not a yaffs2 file ", img_name, len, mtd->mtd_num,
               mtd->subpage_size + mtd->oob_size);
        errno = EINVAL;
        goto out_close;
    }
    data_length = len / (mtd->subpage_size + mtd->oob_size) * mtd->subpage_size;
    
    tmp = (offs + data_length + mtd->eb_size - 1) / mtd->eb_size;
    if (eb + tmp > mtd->eb_cnt) {
        errmsg(""%s" image size(except oob size) is %d bytes, mtd%d size is %d "
               "eraseblocks, the image does not fit if we write it "
               "starting from eraseblock %d, offset %d",
               img_name, data_length, mtd->mtd_num, mtd->eb_cnt, eb, offs);
        errno = EINVAL;
        goto out_close;
    }
    
    /* Seek to the beginning of the eraseblock */
    seek = (off_t)eb * mtd->eb_size + offs;
    if (lseek(fd, seek, SEEK_SET) != seek) {
        sys_errmsg("cannot seek mtd%d to offset %llu",
                mtd->mtd_num, (unsigned long long)seek);
        goto out_close;
    }
    writesize = (mtd->eb_size / mtd->subpage_size) *( mtd->subpage_size + mtd->oob_size);
    printf("write size with oob size is: %d 
",writesize);
    buf = xmalloc(writesize);
    
    left_to_write = len;
    write_eb_num = eb;
    ///writeoffs = eb*mtd->eb_size + offs;
    
    while (left_to_write > 0) {
        int rd = 0;

        ret = mtd_is_bad(mtd,fd,write_eb_num);//判断当前块是否是坏块!
        if(ret >0){ //是坏块!
            write_eb_num = write_eb_num + 1;
            if(write_eb_num >= mtd->eb_cnt)
            {
                if(left_to_write < 1){ 
                    goto out_free;
                }
            }                
            else {
                printf("skip bad blocks at offset: %d 
",write_eb_num);
                continue;
            }
        }else if(ret <0){
            printf("get bad blocks error: %d
",errno);
        }

        if(left_to_write < (mtd->eb_size +mtd->oob_size)){
            writesize = left_to_write;
        }
        else{
            writesize = (mtd->eb_size / mtd->subpage_size) *( mtd->subpage_size + mtd->oob_size);
        }

        ret = read(in_fd, buf, writesize);
        if(ret == -1) {
            sys_errmsg("cannot read "%s"", img_name);
            goto out_free;
        }
        
        temp = buf;
        
        dataAddr = temp;
        oobAddr = temp + mtd->subpage_size;

        for(i=0;i< mtd->eb_size/mtd->subpage_size;i++){ //完成一个块的写入!
            ret = mtd_write(desc,mtd,fd,write_eb_num,i*mtd->subpage_size,dataAddr,mtd->subpage_size,oobAddr,mtd->oob_size,MTD_OPS_RAW);
            if(ret < 0){
                printf("write data witd oob error : %d 
",errno);
            }
            temp = oobAddr + mtd->oob_size; 
            dataAddr = temp;
            oobAddr = temp + mtd->subpage_size;
        }
        write_eb_num = write_eb_num +1;
        left_to_write -= writesize;
        printf("left_to_write :%d write_eb_num: %d,writesize:%d
",left_to_write,write_eb_num,writesize);
        
    }

    free(buf);
    close(in_fd);
    return 0;

out_free:
    free(buf);
out_close:
    close(in_fd);
    return -1;
    
}

?

yaffs2的读取函数

?
int mtd_read_yaffs2_skip_bad(libmtd_t desc,const struct mtd_dev_info *mtd, int fd, int eb, int offs,
    const char *img_name)
{
    int tmp, ret, out_fd, len, written = 0;
    int read_eb_num,i,sekOffs;
    int data_length,left_to_read,readsize;
    off_t seek;
    struct stat st;
    char *buf,*dataAddr,*oobAddr;
    
    if (offs < 0 || offs >= mtd->eb_size) {
        errmsg("bad offset %d, mtd%d eraseblock size is %d",
                   offs, mtd->mtd_num, mtd->eb_size);
        errno = EINVAL;
        return -1;
    }
    if (offs % mtd->subpage_size) {
        //start address must align to page (2048)0x800
        errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
            offs, mtd->mtd_num, mtd->subpage_size);
        errno = EINVAL;
        return -1;
    }
    len = 0x193b3c0;//for test‘s length, you can read nand flash frome straddr to endaddr!!!
    //also can read all mtdx device!
    if (len % (mtd->subpage_size + mtd->oob_size)){
        errmsg("size of "%s" is %d byte, which is not aligned to "
               "mtd%d min. I/O size %d, it is not a yaffs2 file ", img_name, len, mtd->mtd_num,
               mtd->subpage_size + mtd->oob_size);
        errno = EINVAL;
        goto out_close;
    }
    data_length = len / (mtd->subpage_size + mtd->oob_size) * mtd->subpage_size;
    
    tmp = (offs + data_length + mtd->eb_size - 1) / mtd->eb_size;
    if (eb + tmp > mtd->eb_cnt) {
        errmsg(""%s" image size(except oob size) is %d bytes, mtd%d size is %d "
               "eraseblocks, the image does not fit if we write it "
               "starting from eraseblock %d, offset %d",
               img_name, data_length, mtd->mtd_num, mtd->eb_cnt, eb, offs);
        errno = EINVAL;
        goto out_close;
    }
    /* Seek to the beginning of the eraseblock */
    seek = (off_t)eb * mtd->eb_size + offs;
    if (lseek(fd, seek, SEEK_SET) != seek) {
        sys_errmsg("cannot seek mtd%d to offset %llu",
                mtd->mtd_num, (unsigned long long)seek);
        goto out_close;
    }
    
    readsize = mtd->subpage_size + mtd->oob_size;
    printf("read size with oob size is: %d 
",readsize);
    
    buf = xmalloc(readsize);
    
    dataAddr = buf;
    oobAddr = buf + mtd->subpage_size;
    
    left_to_read = len;
    read_eb_num = eb;

    out_fd = open(img_name,O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, S_IRUSR | S_IWUSR);
    if(out_fd < 0){
        printf("open write file error: %d 
",errno);
        return -1;
    }
    
    while (left_to_read > 0) {
        int rd = 0;

        ret = mtd_is_bad(mtd,fd,read_eb_num);
        if(ret >0){
            read_eb_num = read_eb_num + 1;
            if(read_eb_num >= mtd->eb_cnt)
            {
                if(left_to_read < 1){ 
                    goto out_free;
                }
            }                
            else {
                printf("skip bad blocks at offset: %d 
",read_eb_num);
                continue;
            }
        }else if(ret <0){
            printf("get bad blocks error: %d
",errno);
        }

        if(left_to_read < (mtd->eb_size +mtd->oob_size)){
            readsize = left_to_read;
        }
        else{
            readsize = (mtd->eb_size / mtd->subpage_size) *( mtd->subpage_size + mtd->oob_size);
        }
    
        for(i=0;i< mtd->eb_size/mtd->subpage_size;i++){

            ret = mtd_read(mtd,fd,read_eb_num,i*mtd->subpage_size,dataAddr,mtd->subpage_size);
            if(ret < 0){
                printf("read data error: %d 
",errno);
                goto out_free;
            }
            
            sekOffs = read_eb_num * mtd->eb_size + i*mtd->subpage_size;
            seek = (off_t)sekOffs;
            //printf("seek %#llx sek offs %#x 
",seek,sekOffs);
            ret = mtd_read_oob(desc,mtd,fd,seek,mtd->oob_size,oobAddr);
            if(ret < 0){
                printf("read oob error: %d 
",errno);
                goto out_free;
            }
            
            ret = write(out_fd, dataAddr, mtd->subpage_size);
            if(ret == -1) {
                sys_errmsg("cannot write data "%s"", img_name);
                goto out_free;
            }
            ret = write(out_fd, oobAddr, mtd->oob_size);
            if(ret == -1) {
                sys_errmsg("cannot write oob "%s"", img_name);
                goto out_free;
            }
        }
        read_eb_num = read_eb_num +1;
        left_to_read -= readsize;
        printf("left_to_read :%-7d write_eb_num: %-3d,readsize:%-6d
",left_to_read,read_eb_num,readsize);
    }
    free(buf);
    close(out_fd);
    return 0;
out_free:
    free(buf);
out_close:
    close(out_fd);
    return -1;
    
}

?

测试烧写;

?
具体如下:
    int mtdDevFd1 =0,ret =0,i;
    libmtd_t mtd_desc;    
    char* image_file = FILE_NAME;
    struct mtd_dev_info mtd;
    //open mtd device, see it at /dev/mtdX
    //get mtd message : cat /proc/mtd
    if ((mtdDevFd1 = open(mtdDev1, O_RDWR)) < 0){
        _SEND_DBUG_MSG("open %s error 
",mtdDev2);
        ret =-1;
        goto out_close;
    }
    mtd_desc = libmtd_open();
    if(mtd_desc == NULL){
        _SEND_DBUG_MSG("can not initlize mtd lib 
");
        ret =-1;
        goto out_close;
    }
        
    if (mtd_get_dev_info(mtd_desc,mtdDev1,&mtd) < 0){
        ret =-1;
        goto out_close;;
        _SEND_DBUG_MSG("get dev info error!
");
    }
    printf("size:%#x 
",mtd.size);
    printf("eb_size:%#x 
",mtd.eb_size);
    printf("name:%s 
",mtd.name);
    printf("subpage size: %#x 
",mtd.subpage_size);
    printf("oob size: %#x 
",mtd.oob_size);
    printf("eb_cnt: %#x 
",mtd.eb_cnt);

    for(i = 0; i< mtd.eb_cnt;i++){
        if(mtd_is_bad(&mtd, mtdDevFd1, i))
        {
            printf("erase skip bad block num: %d 
",i);
            continue;
        }
        if(0 != mtd_erase(mtd_desc,&mtd,mtdDevFd1,i)){//擦除!
            _SEND_DBUG_MSG("ersae error 
");
            ret =-1;
            goto out_close;
        }
    }
    if(0 != mtd_write_yaffs2_skip_bad(mtd_desc,&mtd,mtdDevFd1,0,0,image_file)){
        _SEND_DBUG_MSG("write yaffs2 error 
");
        ret = -1;
    }
out_close:
    libmtd_close(mtd_desc);
    close(mtdDevFd1);
    //write end!!!

?

 




以上是关于linux 对MTD分区nand flash的烧写和读取的主要内容,如果未能解决你的问题,请参考以下文章

Linux MTD下获取Nand flash各个参数的过程的详细解析

Linux-Nand Flash驱动(分析MTD层并制作NAND驱动)

板载 SPI-FLASH 的烧写方法

linux中MTDflash设备驱动大概

linux下怎样写数据到nandflash

MTD下的Nand驱动