纠正几个NANDFLASH很容易犯的错误【转】
转自:https://blog.csdn.net/pengrui18/article/details/32337297
今天在看别人如何根据物理地址计算NANDFLASH的列地址(column addres)和页地址(page address),结果看到这篇文章时,感觉有点不对劲。http://blog.csdn.net/feihuxiaozi/article/details/6943124。我在u-boot下根据代码计算,不管怎么计算都和他的例子对不上:
0xBB8CCB8 = 00001011 1011 1000 1100 1100 1011 1000,分别分配到5个地址周期就是:
B B 8 C C B 8
第一个周期:A[0:7] 也就是B8
第二个周期:A[8:11] 取四位 1100, 再添4位0,也就是0000 1100 即0C
第三个周期:A[12:19] 取八位 1000 1100 即8C
第四个周期:A[20:27] 取八位 1011 1011 即BB
第五个周期:A[28] 取一位 0,补齐八位 即 0000 0000 也就是00
看一下K9F2G08X0A的寻址图:
Column address=addr%2048
ROW Address =addr/2048
在此处,A0-A11代表Column address,A12-A28代表ROW Address,此处的A11还是column address,不需要我们确定,因此对于输入的addr=0xBB8CCB8,其中每周期的数据输入如下:
第一个周期:A[0:7] 也就是B8
第二个周期:A[8:11] 取addr[8:10]=100, 再添5位0,也就是0000 0100 即04
第三个周期:A[12:19] 取addr[11:18]=000 11001 即19
第四个周期:A[20:27] 取addr[11:18]=0111 0111 即77
第五个周期:A[28] 取一位addr[19] =1,补齐八位 即 0000 0001 也就是01
同时我研究了下page =(512+16)byte的NANDFLASH,发现它与(2K+64)字节的NANDFLASH的又不同,这里借用这位博主的博客说明下:http://www.cnblogs.com/hnrainll/archive/2011/06/01/2065508.html
关于NANDFLASH地址 A8寻址
在NAND Flash中有8个I/O引脚(IO0—IO7)、5个全能信号(nWE ALE CLE nCE nRE)、一个引脚,1个写保护引脚。操作NAND Flash时,先传输命令,然后传输地址,最后读写数据。对于64MB的NAND Flash,需要一个26位的地址。只能8个I/O引脚充当地址、数据、命令的复用端口,所以每次传地址只能传8位。这样就需要4个地址序列。因此读写一次nand flash需要传送4次(A[7:0] A[16:9] A[24:17] A[25])。64M的NAND Flash的地址范围为0x00000000—0x03FFFFFF。128M的NAND Flash的地址范围为0x00000000---0x07FFFFFF。1KB = 0x000-0x3FF.128字节=0x00H--7FH。
一页有528个字节,而在前512B中存放着用户的数据。在后面的16字节中(OOB)中存放着执行命令后的状态信息。主要是ECC校验的标识。列地址A0-A7可以寻址的范围是256个字节,要寻址528字节的话,将一页分为了A.(1half array)B(2 half array) C(spare array)。A区0—255字节,B区 256-511 字节C区512—527字节。访问某页时必须选定特定的区。这可以使地址指针指向特定的区实现。
在NAND Flash 中存在三类地址,分别为Block Address 、Column Address Page Address.。(实际就是块地址和页地址)
Column Address 用来选择是在上半页寻址还是在下半页寻址A[0]—A[7].也就相当于页内的偏移地址。在进行擦除时不需要列地址,因为擦除是以块为单位擦除。32个Page需要5bit来表示。也就是A[13:9];也就是页在块内的相对地址。A8这一位用来设置512字节的上半页,还是下半页,1表示是在上半页,而2表示是在下半页。Block的地址有A[25:14]组成.
一个容量为64M(512Mbit)的NAND Flash,分为131072页,528列。(实际中由于存在spare area,故都大于这个值),有4096块,需要12bit来表示即A[25:14].如果是128M(1Gbit)的话,blodk Address为A[26:14].由于地址只能在IO0—IO7上传送。编程时通常通过移位来实现地址的传送。传送过程如下:
第1个地址序列:传递column address,也就是NAND Flash[7:0],这一周期不需要移位即可传递到I/O[7:0]上,而half page pointer 即A8是由操作指令决定,00h,在A区,01h在B区,指令决定在哪个half page上进行读写,而真正A8的值是不需要程序员关心的;
第2个地址序列:就是将NAND_ADDR 右移9位,而不是8位,将NAND_ADDR[16:9]传递到I/O[7:0]上;
第3个地址序列:将NAND_ADDR[24:17] 传递到I/O[7:0]上;
第4个地址序列:将NAND_ADDR[25]传送到I/O上。
整个地址的传送过程需要4步才能完成。如果NAND Flash 的大小是32MB的以下的话,那么block address 最高位只到bit24,因此寻址只需要3步,就可以完成。
在进行擦除操作时由于是以块进行擦除,所以只需要3个地址序列,也就是只传递块的地址,即A[14:25]。
NAND Flash地址的计算:
Column Address 翻译过来是列地址,也就是在一页里的偏移地址。其实是指定Page上的某个Byte,指定这个Byte,其实也就是指定此页的读写起始地址。
Page Address:页地址。页的地址总是以512Bytes对齐的,所以它的低9位问题0,确定读写操作在NAND Flash中的哪个页进行。
当我们得到一个Nand Flash地址addr时,我们可以这样分解出Column Address和Page Address。
Columnaddr = addr % 512 // column address
Pageaddr = addr>>9 // page address
实际上A0~A7是页内地址,比如从第2个开始读起。不过一般都从0开始读起,呵呵。
也就是一个Nand Flash地址的A0-A7是它的column address ,A9—A25是它的Page Address,地址A8被忽略。
现在假设我要从Nand Flash中的第5000字节处开始读取1024个字节到内存的0x30000000处,我们这样调用read函数
NF_Read(5000, 0x30000000,1024);
我们来分析5000这个src_addr.
根据:
column_addr=src_addr%512;
page_address=(src_addr>>9);
我们可得出column_addr=5000%512=392
page_address=(5000>>9)=9
于是我们可以知道5000这个地址是在第9页的第392个字节处,于是我们的NF_read函数将这样发送命令和参数
column_addr=5000%512;
page_address=(5000>>9);
NF_CMD=0x01; //要从2nd half开始读取 所以要发送命令0x01
NF_ADDR= column_addr &0xff; //1st Cycle A[7:0]
NF_ADDR=page_address& 0xff
NF_ADDR=(page_address>>8)&0xff; //3rd.Cycle A[24:17]
NF_ADDR=(page_address>>16)&0xff; //4th.Cycle A[25]
向NandFlash的命令寄存器和地址寄存器发送完以上命令和参数之后,我们就可以从rNFDATA寄存器(NandFlash数据寄存器)读取数据了.
我用下面的代码进行数据的读取.
for(i=column_addr;i<512;i++)
*buf++=NF_RDDATA();
每当读取完一个Page之后,数据指针会落在下一个Page的0号Column(0号Byte).
//========================下面是另外一篇,差不多=====================
http://blog.csdn.net/intint/archive/2009/10/13/4664659.aspx
一、NAND flash的物理组成
NAND Flash 的数据是以bit的方式保存在memory cell,一般来说,一个cell 中只能存储一个bit。这些cell
以8个或者16个为单位,连成bit line,形成所谓的byte(x8)/word(x16),这就是NAND
Device的位宽。这些Line会再组成Page,(NAND Flash 有多种结构,我使用的NAND Flash
是K9F1208,下面内容针对三星的K9F1208U0M),每页528Bytes(512byte(Main Area)+16byte(Spare
Area)),每32个page形成一个Block(32*528B)。具体一片flash上有多少个Block视需要所定。我所使用的三星k9f1208U0M具有4096个block,故总容量为4096*(32*528B)=66MB,但是其中的2MB是用来保存ECC校验码等额外数据的,故实际中可使用的为64MB。
NAND flash以页为单位读写数据,而以块为单位擦除数据。按照这样的组织方式可以形成所谓的三类地址:
Column Address:Starting Address of the Register. 翻成中文为列地址,地址的低8位
Page Address :页地址
Block Address :块地址
对于NAND Flash来讲,地址和命令只能在I/O[7:0]上传递,数据宽度是8位。
二、NAND Flash地址的表示
512byte需要9bit来表示,对于528byte系列的NAND,这512byte被分成1st half Page Register和2nd half Page Register,各自的访问由地址指针命令来选择,A[7:0]就是所谓的column address(列地址),在进行擦除操作时不需要它,why?因为以块为单位擦除。32个page需要5bit来表示,占用A[13:9],即该page在块内的相对地址。A8这一位地址被用来设置512byte的1st
half page还是2nd half page,0表示1st,1表示2nd。Block的地址是由A14以上的bit来表示。
例如64MB(512Mb)的NAND flash(实际中由于存在spare
area,故都大于这个值),共4096block,因此,需要12个bit来表示,即A[25:14],如果是128MB(1Gbit)
的528byte/page的NAND Flash,则block address用A[26:14]表示。而page address就是blcok
address|page address in block NAND Flash 的地址表示为: Block Address|Page
Address in block|halfpage
pointer|Column Address 地址传送顺序是Column Address,Page Address,Block Address。
由于地址只能在I/O[7:0]上传递,因此,必须采用移位的方式进行。 例如,对于512Mbit x8的NAND flash,地址范围是0~0x3FF_FFFF,只要是这个范围内的数值表示的地址都是有效的。 以NAND_ADDR 为例:
第1 步是传递column address,就是NAND_ADDR[7:0],不需移位即可传递到I/O[7:0]上,而halfpage pointer即A8 是由操作指令决定的,即指令决定在哪个halfpage 上进行读
写,而真正的A8 的值是不需程序员关心的。
第2 步就是将NAND_ADDR 右移9位,将NAND_ADDR[16:9]传到I/O[7:0]上;
第3 步将NAND_ADDR[24:17]放到I/O上;
第4步需要将NAND_ADDR[25]放到I/O上;
因此,整个地址传递过程需要4 步才能完成,即4-step addressing。 如果NAND Flash 的容量是32MB(256Mbit)以下,那么,block adress最高位只到bit24,因此寻址只需要3步。
下面,就x16 的NAND flash 器件稍微进行一下说明。 由于一个page 的main area 的容量为256word,仍相当于512byte。但是,这个时候没有所谓的1st halfpage 和2nd halfpage 之分了,所以,bit8就变得没有意义了,也就是这个时候 A8 完全不用管,地址传递仍然和x8 器件相同。除了,这一点之外,x16 的NAND使用方法和 x8 的使用方法完全相同
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
2017-06-21 掌握 Linux 调试技术【转】
2017-06-21 实现自己的系统调用(两种方式) 【转】
2017-06-21 实现自己的系统调用针对linux-2.6.34【转】
2016-06-21 Linux驱动修炼之道-SPI驱动框架源码分析(上)【转】
2016-06-21 Linux SPI总线和设备驱动架构之一:系统概述【转】
2016-06-21 从串口驱动的移植看linux2.6内核中的驱动模型 platform device & platform driver【转】
2016-06-21 Linux中tty框架与uart框架之间的调用关系剖析【转】