S34MS01G2 NAND Flash读写

NAND Flash 结构

  直接拿人家数据手册里的图,Flash的存储结构分三个层次,从低到高依次是Page,Block和Plane。图中一个Page是2048个字节,然后旁边还有64个字节是用来存放校验信息的。64个Page组成一个Block,也就是图里的一层;1024层Block组合成一个Plane。
  我用的主控是TI的C6678,它的EMIF支持NAND Flash读写,但是最多只支持512字节左右的ECC校验,而这个NAND Flash的一个Page已经超过了512字节,所以我在用的时候就没有ECC校验,虽然很有可能出问题,但是目前还没遇到。
在这里插入图片描述

接口

  我用的这个NAND Flash只有一个8bit的接口。地址,数据,指令复用。需要按照要求的指令格式来完成读,写,擦除等操作。ALE和CLE引脚可以用来把8个IO的数据锁存到地址寄存器或者指令寄存器中。

读写Page

  数据的读写是以Page为单位的,连续读一个Page里的内容的话,每次读一个数据,Flash内部的列地址(Col Addr)会自增,所以可以不需要额外的命令就能连续读一个Page的数据,就像一个FIFO一样。
  发起读指令后,Flash会把数据从Cell搬到data register里,全部搬完之后才可以读。这个时候可以通过Busy信号来判断数据是不是已经准备好,但是后来才发现这个Busy信号是开漏输出,我在电路上没有上拉,所以一直检测不到Busy释放。
  除了用Busy信号来判断,还可以通过寄存器查询的方式来判断数据是不是准备好了。当查到数据已经准备好了的时候,命令寄存器中保存的还是查询状态的命令,需要重新写一个读数据的命令再读数据,不然读到的都会是状态寄存器的值。
  写Page之前一定要先擦除!

查看状态

在这里插入图片描述
  主要通过查询IO6来判断是不是可以对Flash读写,IO0的状态会在IO5变成1的时候更新,IO1的状态会在IO6变成1的时候更新。所以在每次Flash退出Busy状态之后可以再去确认一下是不是有错误产生。

快速读写(通过Cache)

  通过Cache读,发起一般的读指令后,再发起一个Cache读指令。这时候原先读出来的在data register中的数据会搬到Cache中。用户可以读Cache中的数据,同时Flash会从Cell中将下一个Page的数据搬到data register中,类似流水线处理。这样每次读Page的间隔时间就很小。
  Cache写也是类似,数据先从Cache写入data register,当Cache准备好了之后又可以接收下一个Page的数据,在接收下一个Page的数据的同时,上一个Page的数据从data register搬到Cell中。

驱动代码

#include <nandflash.h>

static inline void WriteCmd(Uint8 cmd)
{
	*(Uint8 *)NAND_CLE_ADDR = cmd;
	return;
}

static inline void WriteAddr(Uint8 addr)
{
	*(Uint8 *)NAND_ALE_ADDR = addr;
	return;
}

static inline Bool isAnyError()
{
	WriteCmd(0x70);
	return (Bool)(*(Uint8 *)NAND_BASE_ADDR & 0x03);
}

static inline Bool isCacheReady()
{
	WriteCmd(0x70);
	return (Bool)(*(Uint8 *)NAND_BASE_ADDR & 0x40);
}

static inline Bool isProgramFinished()
{
	WriteCmd(0x70);
	return (*(Uint8 *)NAND_BASE_ADDR & 0x60) == 0x60 ;
}

Bool CheckS34MS01G2()
{
	int i;
	Uint8 tmp[4];
	WriteCmd(0x90);
	WriteAddr(0x00);
	for(i = 0; i<4; i++){
		tmp[i] = *(Uint8 *)NAND_BASE_ADDR;
	}
	if(tmp[0] == NAND_ID1 && tmp[1] == NAND_ID2 && tmp[2] == NAND_ID3 && tmp[3] == NAND_ID4){
		return TRUE;
	}
	else{
		return FALSE;
	}
}

Bool BlockErase(Uint16 blockAddr)
{
	if(blockAddr > PLANE_SIZE) return FALSE;

	Uint8 rowAddr1, rowAddr2;
	rowAddr1 = (Uint8)((blockAddr & 0x0003)<<6);
	rowAddr2 = (Uint8)(blockAddr>>2 & 0x00FF);

	WriteCmd(0x60);
	WriteAddr(rowAddr1);
	WriteAddr(rowAddr2);
	WriteCmd(0xD0);

	while(!isCacheReady());
	if(isAnyError()) return FALSE;
	else return TRUE;
}

Bool ProgramPage(
	Uint8 pageAddr,
	Uint16 blockAddr,
	const Uint8 *src,
	Uint16 len
){
	int i;
	Uint8 colAddr1, colAddr2, rowAddr1, rowAddr2;

	if(len > PAGE_SIZE || pageAddr > BLOCK_SIZE || blockAddr > PLANE_SIZE)
		return FALSE;

	colAddr1 = 0x00;
	colAddr2 = 0x00;
	rowAddr1 = pageAddr&(0x3F) | (Uint8)((blockAddr & 0x0003)<<6);
	rowAddr2 = (Uint8)(blockAddr>>2 & 0x00FF);

	WriteCmd(0x80);
	WriteAddr(colAddr1);
	WriteAddr(colAddr2);
	WriteAddr(rowAddr1);
	WriteAddr(rowAddr2);

	for(i = 0; i<len; i++){
		*(Uint8 *)NAND_BASE_ADDR = *src++;
	}

	WriteCmd(0x10);

	while(!isCacheReady());

	if(isAnyError()) return FALSE;
	else return TRUE;
}

Bool ProgramBlock(
	Uint16 blockAddr,
	const Uint8 *src,
	Uint32 pageNum
){
	int i;
	Uint8 pageAddr, rowAddr1, rowAddr2;

	if(blockAddr > PLANE_SIZE)
		return FALSE;

	rowAddr2 = (Uint8)(blockAddr>>2 & 0x00FF);

	for(pageAddr = 0; pageAddr < pageNum; pageAddr++){
		rowAddr1 = pageAddr&(0x3F) | (Uint8)((blockAddr & 0x0003)<<6);

		WriteCmd(0x80);
		WriteAddr(0x00);
		WriteAddr(0x00);
		WriteAddr(rowAddr1);
		WriteAddr(rowAddr2);

		for(i = 0; i<PAGE_SIZE; i++){
			*(Uint8 *)NAND_BASE_ADDR = *src++;
		}
		WriteCmd(0x15);

		while(!isCacheReady());
		if(isAnyError()) return FALSE;
		else continue;
	}

	while(!isProgramFinished());
	if(isAnyError()) return FALSE;
	else return TRUE;
}

Bool ReadPage(
	Uint8 pageAddr,
	Uint16 blockAddr,
	Uint8 *dst,
	Uint16 len
){
	int i;
	Uint8 colAddr1, colAddr2, rowAddr1, rowAddr2;

	if(len > PAGE_SIZE || pageAddr > BLOCK_SIZE || blockAddr > PLANE_SIZE)
		return FALSE;

	colAddr1 = 0x00;
	colAddr2 = 0x00;
	rowAddr1 = pageAddr&(0x3F) | (Uint8)((blockAddr & 0x0003)<<6);
	rowAddr2 = (Uint8)(blockAddr>>2 & 0x00FF);

	WriteCmd(0x00);
	WriteAddr(colAddr1);
	WriteAddr(colAddr2);
	WriteAddr(rowAddr1);
	WriteAddr(rowAddr2);
	WriteCmd(0x30);

	while(!isCacheReady());

	WriteCmd(0x00);
	for(i = 0; i<PAGE_SIZE; i++){
		*(dst+i) = *(Uint8 *)NAND_BASE_ADDR;
	}
	return TRUE;
}

Bool ReadBlock(
	Uint16 blockAddr,
	Uint8 *dst,
	Uint16 pageNum
){
	int i;
	Uint8 colAddr1, colAddr2, rowAddr1, rowAddr2, pageAddr;

	if(blockAddr > PLANE_SIZE || pageNum < 2 || pageNum > BLOCK_SIZE)
		return FALSE;

	colAddr1 = 0x00;
	colAddr2 = 0x00;
	rowAddr1 = (Uint8)((blockAddr & 0x0003)<<6);
	rowAddr2 = (Uint8)(blockAddr>>2 & 0x00FF);

	WriteCmd(0x00);
	WriteAddr(colAddr1);
	WriteAddr(colAddr2);
	WriteAddr(rowAddr1);
	WriteAddr(rowAddr2);
	WriteCmd(0x30);
	while(!isCacheReady());

	for(pageAddr = 0; pageAddr < pageNum - 1; pageAddr++){
		WriteCmd(0x31);
		while(!isCacheReady());
		WriteCmd(0x00);
		for(i = 0; i<PAGE_SIZE; i++){
			*dst++ = *(Uint8 *)NAND_BASE_ADDR;
		}
	}
	WriteCmd(0x3F);
	while(!isCacheReady());
	WriteCmd(0x00);
	for(i = 0; i<PAGE_SIZE; i++){
		*dst++ = *(Uint8 *)NAND_BASE_ADDR;
	}
	return TRUE;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小裘HUST

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值