Chinaunix首页 | 论坛 | 博客
  • 博客访问: 30628
  • 博文数量: 21
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 15
  • 用 户 组: 普通用户
  • 注册时间: 2015-07-24 17:09
文章分类
文章存档

2017年(14)

2015年(7)

我的朋友

分类: LINUX

2017-07-31 21:37:48

原文地址:裸奔之读nandflash 作者:草根老师

一、Flash存储器介绍

FLASH闪存的英文名称是"Flash Memory",一般简称为"Flash",它属于内存器件的一种,是一种不挥发性(Non-Volatile)闪存。闪存的物理特性与常见的内存有根本性的差异:目前各类DDR、SDRAM或者RDRAM都属于挥发性内存,只要停止电流供应内存中的数据便无法保持,因此每次电脑开机都需要把数据重新载入内存;闪存在没有电流供应的条件下也能够长久地保持数据,其存储特性相当于硬盘,这项特性正是闪存得以成为各类便携型数字设备的存储介质的基础。

二、Flash的种类

市面上主要有两种: NOR Flash 和 NAND Flash

Intel于1988年首先开发出NOR Flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面。紧接着,1989年,东芝公司发表了NAND Flash结构,强调低成本,更高性能,
并且象磁盘一样可以通过接口轻松升级。

三、NOR Flash 和 NAND Flash区别

NOR的特点是芯片内执行(XIP,eXecute In Place),这样应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中。NOR的传输效率很高,在1-4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。

NAND结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快。应用NAND的困难在在于flash的管理和需要特殊的系统接口。

主要差别:

A.接口差别

NOR Flash接口时序和SRAM一样
NAND使用的是地址和数据复用的I/O方式

B.其他差别

NAND Flash写入速度比NOR快的多
NOR Flash常见容量1-32M,而NAND为8-256M
NOR没有坏块,而NAND出厂时就可能带有坏块
寿命上NAND Flash每块最多可以擦写几百万次,而NOR Flash只有十万次数量级

四、本次研究方向s3c2410 NAND FLASH(K9F1208U0M)的读、写、擦除

1.先来看看K9F1208U0B NAND FLASH内部的物理结构

 
这幅图来自网络,画的实在太好了,感谢作者的奉献。

从上图可以知道,一块Nand Flash被分为若干Block,每个Block又被分为若干Page.
他们之间的关系是:

1Page = 512 Bytes Data Field  + 16 Bytes Spare Field
1 Block = 32 Pages

我们讨论的K9F1208U0B总共有4096个Blocks,故我们可以知道这块Flash的容量为
4096 * (32 * 528) = 69206016 Bytes = 66 MB

但事实上每个Page上的最后16Bytes是用于存储检验码用的,并不能存放实际的数据,所以实际上我们可以操作的芯片容量为:

4096 * (32 * 512) = 67108864 Bytes = 64 MB

2.nand flash 在fs2410上的接线方式
 
我们知道,我们对一块内存读取或写入时,都是通过地址线传送addr,通过数据线传送data。而这里的nandflash只有数据线,那我怎么知道这个数据写到那个地方或者是从那个地方读取的数据??不用着急,我们看一下nand flash datasheet自己怎么说的。
从这里我们可以知道,对nand flash的操作,是通过命令序列来进行的。命令、数据、地址的传送I/O端口是复用的,区分他们通过锁存器来进行。

在来看看每个pin是什么意思吧。
 
现在我们知道,nand flash的I/O端口只有8个,也就是说最大寻址范围是2^8 = 256.一页的大小是512 + 16 = 528。这样看来,对一个页进行操作,I/O端口不够呀?
还记的,刚开始的那幅图吗?我们把一页的Data Field分成了两部分,一半就是256,呵呵,那另一半怎么办呢?不要忘记了nand flash操作方式,我们可以通过不同的命令来区分操作的是nand  flash 页的哪一部分。
 
红色线条部分我想你懂的。
 
 
下面我们来看看对一个nand flash具体的读、写、擦除操作是怎么进行的吧。

A.对一个页读取

从命令表中,我们可以知道,读命令有两个,分别是Read1,Read2,其中Read1用于读取Data Field的数据,而Read2则是用于读取Spare Field的数据。对于Nand Flash来说,其操作的最小操作单位为Page,也就是说当我们给定了读取的起始位置后。读操作将从该位置开始,连续读取到本Page的最后一个Byte为止(可以包含spare field).
 
 
从时序图上我们可以看到,读操作时,先发命令,然后Column Address,最后Page Address.
发送地址需要通过4个周期来发,四个周期如下图
 
Nand Flash的寻址
Nand Flash的地址寄存器把一个完整的Nand Flash地址分解成Column Address与Page Address进行寻址。
Column Address : 列地址。Column Address其实就是指定Page上的某个Byte,指定找个Byte其实也就是指定此页的读写起始地址。
Page Address:页地址。由于页地址总是以512Bytes对齐的,所以它的低9位总是0,确定读写操作是在Flash上的哪个页进行的。

下面举个例子来说明,对于一个给定的地址(src_addr),如何读取:

column_addr = src_addr % 512;(A0~A7是列地址)
注意:A8由00h/01h决定
page_address = src_addr >> 9;(A9~A25是页地址)
/*page分为两部分,一部分是:0~255,一部分是:0~256*/
if(column_addr >= 256)
{
    NF_CMD=0x01;//后半页读取
}else{
    NF_CMD=0x00;//前半页读取
}

NF_ADDR = column_addr & 0xff;//1st Cycle
NF_ADDR = page_address & 0xff;//2nd Cycle
NF_ADDR = (page_address >> 8) & 0xff;//3rd Cycle
NF_ADDR = (page_address >> 16) & 0xff;//4th Cycle

案例(从nand flash的一个指定地址,读取数据):
我们读取nand flash时,只需要按照其datasheet提供的时序图即可,想要得到其时序,只需要设置一下nand flash的控制器即可。

s3c2410 nand flash控制器可以得到的时序图:
 
 

TACLS:表示CLT/ALE的建立时间(setup time)。tCLS/tALS

TWRPH0:表示CLE/ALE的持续时间。---twp

TWRPH1:表示CLE/ALE的维持时间(hold time)  tCLH/tALH

k9f1208U0M提供的时间的参数:
 
 
注意:我们s3c2410 nand flash控制器发出的时序要和k9f1208U0M要求的时序要一致。
 
 
按照以上提供的信息我们可以设置:TACLS : 0,TWRPH0 : 3,TWRPH1 : 0

源码:

//1.页开始的地址,cmd 0x00,size 512 
//2.半页开始的地址,cmd 0x01,size 256
int  read_page(int addr,unsigned char *dest_addr)
{
int column_addr,page_address;
int size,i;

column_addr = addr % PAGE_SIZE;
page_address = addr >> 9;

NFChipEn();
ResetNand();
#ifdef _DEBUG_
uart0_printf("column_addr = %d.\r\n",column_addr);
#endif
if(column_addr >= HALF_PAGE)
{
uart0_printf("Half page.\r\n");
WRITE_CMD(0x01);
size = 256;
}else{
WRITE_CMD(0x00);
size = 512;
}
WRITE_ADDR(column_addr & 0xff);//1st Cycle
WRITE_ADDR(page_address & 0xff);//2st Cycle
WRITE_ADDR((page_address >> 8)&0xff);//3rd Cycle
WRITE_ADDR((page_address >> 16)&0xff);//4th Cycle

//等待BUSY
while(!NFREADY());

uart0_printf("nand read ok.\r\n");

for(i = 0;i < size;i ++)
{
dest_addr[i] = READ_DATA();
}

NFChipDs();
return size;
}

/*把nand的内容读到内存中去,
 *dest_addr:内存地址,src_addr:nand flash地址
 *size : 大小 
 */
void nand_read(unsigned char *dest_addr,int src_addr,int size)
{
int i,nbytes;
unsigned char *new_addr = dest_addr;
int n = size / PAGE_SIZE;
//不够一页,按一页计算
if(n < 1) n= 1;

//判断是否是半页对齐的地址
if(src_addr % HALF_PAGE != 0)
{
uart0_printf("Invaild addr.\r\n");
return -1;
}
//n值表示需要读多少个页
for(i = 0;i < n;i ++)
{
nbytes = read_page(src_addr,new_addr);
//处理半页地址的情况
if(src_addr % HALF_PAGE == 0 && src_addr % PAGE_SIZE != 0)
{
src_addr = src_addr - HALF_PAGE;
}
src_addr = src_addr + PAGE_SIZE;
new_addr = new_addr + nbytes;
}
return;
}

阅读(517) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~