加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

nand flash粗析(二)------NAND flash 读写

发布时间:2020-12-15 18:17:53 所属栏目:百科 来源:网络整理
导读:1、坏块检测 All device locations are erased(FFh) except locations where the initial invalid block(s) information is written prior to shipping. The initial invalid block(s) status is defined by the 6th byte in the spare area. Samsung makes

1、坏块检测

All device locations are erased(FFh) except locations where the initial invalid block(s) information is written prior to shipping. The
initial invalid block(s) status is defined by the 6th byte in the spare area. Samsung makes sure that either the 1st or 2nd page of every
initial invalid block has non-FFh data at the column address of 517.-------摘自K9F1208U0M的datasheet。


上图为数据手册中,检测有效块的流程图。它的大意是解释第一段英文的意思,一个block中前两页中的第517个字节是0xFF的话,这一个块就是有效的,否则这个块就是坏块。

在linux源码中快速检测有效块的代码(2.6.19)

/**
 * check_short_pattern - [GENERIC] check if a pattern is in the buffer
 * @buf:	the buffer to search
 * @td:		search pattern descriptor
 *
 * Check for a pattern at the given place. Used to search bad block
 * tables and good / bad block identifiers. Same as check_pattern,but
 * no optional empty check
 *
*/
static int check_short_pattern(uint8_t *buf,struct nand_bbt_descr *td)
{
	int i;
	uint8_t *p = buf;

	/* Compare the pattern */
	for (i = 0; i < td->len; i++) {
		if (p[td->offs + i] != td->pattern[i])
			return -1;
	}
	return 0;
}

以K9F1208U0M为例,上述代码中的td是这样的

static struct nand_bbt_descr smallpage_memorybased = {
	.options = NAND_BBT_SCAN2NDPAGE,.offs = 5,//刚好第517个字节,用来检测block是否invalid
	.len = 1,.pattern = scan_ff_pattern
};
结合datasheet中的描述,offs刚好为第517个字节,scan_ff_pattern是值为oxff的数组,也符合datasheet中的描述

2、写操作


写操作的流程图。

代码:

/**
 * nand_write_page - [REPLACEABLE] write one page
 * @mtd:	MTD device structure
 * @chip:	NAND chip descriptor
 * @buf:	the data to write
 * @page:	page number to write
 * @cached:	cached programming
 * @raw:	use _raw version of write_page
 */
static int nand_write_page(struct mtd_info *mtd,struct nand_chip *chip,const uint8_t *buf,int page,int cached,int raw)
{
	int status;

	chip->cmdfunc(mtd,NAND_CMD_SEQIN,0x00,page);	//0x80,发送命令

	if (unlikely(raw))
		chip->ecc.write_page_raw(mtd,chip,buf);
	else
		chip->ecc.write_page(mtd,buf);	//数据写入

	/*
	 * Cached progamming disabled for now,Not sure if its worth the
	 * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
	 */
	cached = 0;

	if (!cached || !(chip->options & NAND_CACHEPRG)) {

		chip->cmdfunc(mtd,NAND_CMD_PAGEPROG,-1,-1);	//0x10
		status = chip->waitfunc(mtd,chip);	//s3c2440_nand_devready,等NFSTAT第0位空闲
				//返回值为状态值,由flash芯片发送的
		/*
		 * See if operation failed and additional status checks are
		 * available
		 */
		if ((status & NAND_STATUS_FAIL) && (chip->errstat))
			status = chip->errstat(mtd,FL_WRITING,status,page);

		if (status & NAND_STATUS_FAIL)
			return -EIO;
	} else {
		chip->cmdfunc(mtd,NAND_CMD_CACHEDPROG,-1);	//0x15
		status = chip->waitfunc(mtd,chip);
	}

#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
	/* Send command to read back the data */
	chip->cmdfunc(mtd,NAND_CMD_READ0,page);

	if (chip->verify_buf(mtd,buf,mtd->writesize))
		return -EIO;
#endif
	return 0;
}

在chip->cmdfunc(nand_command)中已经写入了地址。

在chip->waitfunc中完成读状态寄存器,确保nand busy free,再判断是否是NAND_STATUS_FAIL(也就是I/O 0==0?)


chip-> ecc.write_page

/**
 * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
 * @mtd:	mtd info structure
 * @chip:	nand chip info structure
 * @buf:	data buffer
 */
static void nand_write_page_hwecc(struct mtd_info *mtd,const uint8_t *buf)
{
	int i,eccsize = chip->ecc.size;	//hardware的话是512
	int eccbytes = chip->ecc.bytes;		// 3
	int eccsteps = chip->ecc.steps;
	uint8_t *ecc_calc = chip->buffers->ecccalc;
	const uint8_t *p = buf;
	int *eccpos = chip->ecc.layout->eccpos;

	for (i = 0; eccsteps; eccsteps--,i += eccbytes,p += eccsize) {
		chip->ecc.hwctl(mtd,NAND_ECC_WRITE);	//Initialize ECC decoder/encoder
		chip->write_buf(mtd,p,eccsize);  //buf写入
		chip->ecc.calculate(mtd,&ecc_calc[i]);//计算buf的ecc
	}

	for (i = 0; i < chip->ecc.total; i++)
		chip->oob_poi[eccpos[i]] = ecc_calc[i];	

	chip->write_buf(mtd,chip->oob_poi,mtd->oobsize);	//ecc写入
}

chip->write_buf

static void s3c2440_nand_write_buf(struct mtd_info *mtd,const u_char *buf,int len)
{
	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
	writesl(info->regs + S3C2440_NFDATA,len / 4);   //2440的数据寄存器
	NAND_LED_STATUS = ~ NAND_LED_STATUS;
	s3c2410_gpio_setpin(S3C2410_GPF4,NAND_LED_STATUS);    //bank选择
}

3、读操作:


代码:

nand_do_read_ops中先发送0x00,再调用ret = chip->ecc.read_page(mtd,bufpoi);,这个函数可以是nand_read_page_hwecc,//将数据读取到bufopi里,且如果有错误ecc可矫正,两位以上ecc没法矫正

/**
 * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
 * @mtd:	mtd info structure
 * @chip:	nand chip info structure
 * @buf:	buffer to store read data
 *
 * Not for syndrome calculating ecc controllers which need a special oob layout
 */
static int nand_read_page_hwecc(struct mtd_info *mtd,uint8_t *buf)
{
	int i,eccsize = chip->ecc.size;
	int eccbytes = chip->ecc.bytes;
	int eccsteps = chip->ecc.steps;
	uint8_t *p = buf;
	uint8_t *ecc_calc = chip->buffers->ecccalc;
	uint8_t *ecc_code = chip->buffers->ecccode;
	int *eccpos = chip->ecc.layout->eccpos;

	for (i = 0; eccsteps; eccsteps--,NAND_ECC_READ);
		chip->read_buf(mtd,eccsize);  //将数据读出来
		chip->ecc.calculate(mtd,&ecc_calc[i]);		//根据读取数据,生成ecc
	}
	chip->read_buf(mtd,mtd->oobsize);  //读出oob	

	for (i = 0; i < chip->ecc.total; i++)
		ecc_code[i] = chip->oob_poi[eccpos[i]];	//硬件ecc

	eccsteps = chip->ecc.steps;
	p = buf;

	for (i = 0 ; eccsteps; eccsteps--,p += eccsize) {
		int stat;

		stat = chip->ecc.correct(mtd,&ecc_code[i],&ecc_calc[i]);	//ecc校验
		if (stat == -1)
			mtd->ecc_stats.failed++;	//-1表明是坏块
		else		//0 or 1
			mtd->ecc_stats.corrected += stat;  //如果是1的话,表明是纠错过的,更新
	}
	return 0;
}

chip->read_buf

static void s3c2410_nand_read_buf(struct mtd_info *mtd,u_char *buf,int len)
{
	struct nand_chip *this = mtd->priv;
	readsb(this->IO_ADDR_R,len);  //2440的数据寄存器
	NAND_LED_STATUS = ~ NAND_LED_STATUS;
	s3c2410_gpio_setpin(S3C2410_GPF4,NAND_LED_STATUS);
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读