1. 程式人生 > >linux 對MTD分區nand flash的燒寫和讀取

linux 對MTD分區nand flash的燒寫和讀取

大小寫 error: null 分開 itl tin app struct util

使用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 \n",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 \n",write_eb_num); continue; } }else if(ret <0){ printf("get bad blocks error: %d\n",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 \n",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\n",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 \n",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 \n",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 \n",read_eb_num);
                continue;
            }
        }else if(ret <0){
            printf("get bad blocks error: %d\n",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 \n",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 \n",seek,sekOffs);
            ret = mtd_read_oob(desc,mtd,fd,seek,mtd->oob_size,oobAddr);
            if(ret < 0){
                printf("read oob error: %d \n",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\n",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 \n",mtdDev2);
        ret =-1;
        goto out_close;
    }
    mtd_desc = libmtd_open();
    if(mtd_desc == NULL){
        _SEND_DBUG_MSG("can not initlize mtd lib \n");
        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!\n");
    }
    printf("size:%#x \n",mtd.size);
    printf("eb_size:%#x \n",mtd.eb_size);
    printf("name:%s \n",mtd.name);
    printf("subpage size: %#x \n",mtd.subpage_size);
    printf("oob size: %#x \n",mtd.oob_size);
    printf("eb_cnt: %#x \n",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 \n",i);
            continue;
        }
        if(0 != mtd_erase(mtd_desc,&mtd,mtdDevFd1,i)){//擦除!
            _SEND_DBUG_MSG("ersae error \n");
            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 \n");
        ret = -1;
    }
out_close:
    libmtd_close(mtd_desc);
    close(mtdDevFd1);
    //write end!!!

?

linux 對MTD分區nand flash的燒寫和讀取