转自: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 的使用方法完全相同

纠正几个NANDFLASH很容易犯的错误【转】的更多相关文章

  1. css : 使用浮动实现左右各放一个元素时很容易犯的错误

    比如说,有一个div,我想在左侧和右侧各方一个元素. 如果不想用flex,那就只能用浮动了. ... <div class="up clearfix"> <h6& ...

  2. PHP二维数组的引用赋值容易犯的错误

    大家一起来分析一下下面这段代码: <?php $arr = array(); $arr["abc"] = array("sex" => 100, & ...

  3. 在CMMI推广过程中EPG常犯的错误(转)

    本文转自: http://developer.51cto.com/art/200807/86953.htm 仅用于个人收藏,学习.如有转载,请联系原作者. ---------------------- ...

  4. 总结下java经常犯的错误

    编写代码是一种艺术,认识错误是我们代码改进的重要途径之一.以下情况并非大家都能碰到过,但希望提高代码质量的人都引以为戒.以下各种情况,都是初学者经常犯的错误. 1.1       字符串没有判断是否为 ...

  5. 十个JAVA程序员容易犯的错误

    十个JAVA程序员容易犯的错误 1. Array 转 ArrayList 一般开发者喜欢用: List<String> list = Arrays.asList(arr); Arrays. ...

  6. C#中几个经常犯的错误总汇

    在我们平常编程中,时间久了有时候会形成一种习惯性的思维方式,形成固有的编程风格,但是有些地方是需要斟酌的,即使是一个很小的错误也可能会导致昂贵的代价,要学会善于总结,从错误中汲取教训,尽量不再犯同样错 ...

  7. 十个 PHP 开发者最容易犯的错误

    PHP 语言让 WEB 端程序设计变得简单,这也是它能流行起来的原因.但也是因为它的简单,PHP 也慢慢发展成一个相对复杂的语言,层出不穷的框架,各种语言特性和版本差异都时常让搞的我们头大,不得不浪费 ...

  8. 64位平台C/C++容易犯的错误

     64位平台的介绍 IA-64 is a 64-bit microprocessor architecture developed by Intel and Hewlett Packard compa ...

  9. javascript中易犯的错误有哪些

    javascript中易犯的错误有哪些 一.总结 一句话总结: 比如循环中函数的使用 函数中this的指向谁(函数中this的使用) 变量的作用域 1.this.timer = setTimeout( ...

随机推荐

  1. scrapy 爬虫怎么写入日志和保存信息

    写入日志: 首先我的爬虫 name= article scrapy crawl article -s LOG_FILE=wiki.log 输出为不同格式: scrapy crawl article - ...

  2. 从零开始学Kotlin-使用接口(7)

    从零开始学Kotlin基础篇系列文章 定义接口 使用关键字interface定义接口 interface InterfaceDemo7 { } 类或对象可以实现一个或者多个接口 class demo7 ...

  3. C语言入门:05.scanf函数

    一.变量的内存分析 1.字节和地址 为了更好地理解变量在内存中的存储细节,先来认识一下内存中的“字节”和“地址”. (1)内存以“字节为单位”

  4. Jenkins配置匿名用户拥有只读权限

    场景:查看cucumber reporting测试报告时需要登陆,比较麻烦 解决:允许匿名用户拥有只读权限 操作:Jenkins->系统管理->全局安全配置->授权策略,勾选“All ...

  5. BZOJ4628 BJOI2016IP地址(trie)

    离线,每次修改相当于对该规则的所有匹配点的值+1,考虑在trie上打加法标记和匹配标记,匹配标记不下传,加法标记下传遇到匹配标记时清空.注意是用b时刻前缀-a时刻前缀,而不是(a-1)时刻前缀,具体我 ...

  6. bzoj 1798: [Ahoi2009]Seq 维护序列seq (线段树 ,多重标记下放)

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 7773  Solved: 2792[Submit ...

  7. CodeForces - 707C

    C. Pythagorean Triples time limit per test 1 second memory limit per test 256 megabytes input standa ...

  8. 【刷题】LOJ 6003 「网络流 24 题」魔术球

    题目描述 假设有 \(n\) 根柱子,现要按下述规则在这 \(n\) 根柱子中依次放入编号为 \(1, 2, 3, 4, \cdots\) 的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任 ...

  9. MyEclipse创建WebService服务端和客户端

    1.新建立一个javaWeb项目,一个java类,如图: 2.接下来我们就要将项目中的TestService的这个类生成WebService服务端,选择new Web Service,如图: Next ...

  10. Python 内置变量

    Python 隐藏变量 __doc__ # 表示本文件的注释__file__ # 表示本文件的路径 __package__ # 导入的py文件所在的文件夹路径__cached__ # 导入文件的缓存_ ...