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各个参数的过程的详细解析