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

原创 2016年06月01日 22:08:58

使用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 nand flash常用命令

使用命令前用cat /proc/mtd 查看一下mtdchar字符设备;或者用ls -l /dev/mtd* #cat /proc/mtd dev:    size   erasesize  na...

关于NAND flash的MTD分区与uboot中分区的理解

今天做内核移植,准备添加NAND flash的驱动,做到MTD分区时,想起在一本书上看到的一句话,说的是分区时每个区之间没有间隙,前一个区的结束地址是后一个区的起始地址。可是当我看我的开发板的教程时,...

linux下的mtd

通过/proc虚拟文件系统读取MTD分区表:cat /proc/mtd 具体由linux/drivers/mtd下的mtdcore.c文件中的mtd_read_proc函数来实现。 读出来的结果类...

Linux MTD系统剖析

MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储...

【Linux】【驱动】MTD分区表信息解析方法分析

static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL}; 这个说明MTD分区参数的分析有两种方法,...

df、mtd查看嵌入式系统的分区情况

命令:cat  proc/mtd dev:    size   erasesize  name mtd0: 01000000 00010000 "ALL" mtd1: 00030000 000100...

mtd-utils工具的编译和使用

一、下载源码包并解压 root@:/home/# wget ftp://ftp.infradead.org/pub/mtd-utils/mtd-utils-1.0.0.tar.bz2 root@:...

linux kernel系列四:嵌入式系统中的文件系统以及MTD

本节介绍File System和MTD技术一 FS熟知的FS有ext2,3,4.但是这些都是针对磁盘设备的。而ES中一般的存储设备为Flash,由于Flash的特殊性:Flash存储按照Block s...
  • Innost
  • Innost
  • 2011年09月22日 10:00
  • 11983

linux kernel mtd 分区

在移植linux kernel时遇到分区问题。有一点想法,不一定正确,错误请大家指出。 这里基于linux2.6.28.6来说的,其他的位置有可能不同。 linux对flash的分区在结构体str...
  • cbffyx
  • cbffyx
  • 2013年03月28日 11:02
  • 5773

Linux MTD 源代码分析

Linux MTD 源代码分析           by Jim Zeus Version 0.1 2002/4/29             Copyright ©...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux 对MTD分区nand flash的烧写和读取
举报原因:
原因补充:

(最多只允许输入30个字)