纠正几个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 的使用方法完全相同
纠正几个NANDFLASH很容易犯的错误【转】的更多相关文章
- css : 使用浮动实现左右各放一个元素时很容易犯的错误
比如说,有一个div,我想在左侧和右侧各方一个元素. 如果不想用flex,那就只能用浮动了. ... <div class="up clearfix"> <h6& ...
- PHP二维数组的引用赋值容易犯的错误
大家一起来分析一下下面这段代码: <?php $arr = array(); $arr["abc"] = array("sex" => 100, & ...
- 在CMMI推广过程中EPG常犯的错误(转)
本文转自: http://developer.51cto.com/art/200807/86953.htm 仅用于个人收藏,学习.如有转载,请联系原作者. ---------------------- ...
- 总结下java经常犯的错误
编写代码是一种艺术,认识错误是我们代码改进的重要途径之一.以下情况并非大家都能碰到过,但希望提高代码质量的人都引以为戒.以下各种情况,都是初学者经常犯的错误. 1.1 字符串没有判断是否为 ...
- 十个JAVA程序员容易犯的错误
十个JAVA程序员容易犯的错误 1. Array 转 ArrayList 一般开发者喜欢用: List<String> list = Arrays.asList(arr); Arrays. ...
- C#中几个经常犯的错误总汇
在我们平常编程中,时间久了有时候会形成一种习惯性的思维方式,形成固有的编程风格,但是有些地方是需要斟酌的,即使是一个很小的错误也可能会导致昂贵的代价,要学会善于总结,从错误中汲取教训,尽量不再犯同样错 ...
- 十个 PHP 开发者最容易犯的错误
PHP 语言让 WEB 端程序设计变得简单,这也是它能流行起来的原因.但也是因为它的简单,PHP 也慢慢发展成一个相对复杂的语言,层出不穷的框架,各种语言特性和版本差异都时常让搞的我们头大,不得不浪费 ...
- 64位平台C/C++容易犯的错误
64位平台的介绍 IA-64 is a 64-bit microprocessor architecture developed by Intel and Hewlett Packard compa ...
- javascript中易犯的错误有哪些
javascript中易犯的错误有哪些 一.总结 一句话总结: 比如循环中函数的使用 函数中this的指向谁(函数中this的使用) 变量的作用域 1.this.timer = setTimeout( ...
随机推荐
- Do in SDN
Do in SDN 书籍 <深度解析SDN 利益.战略.战术.实践> 张卫锋 <重构网络-SDN构架与实现>杨泽卫.李呈 <软件定义网络核心原理与应用实践> 黄韬. ...
- 『编程题全队』Alpha 阶段冲刺博客Day7
1.每日站立式会议 1.会议照片 2.昨天已完成的工作统计 孙志威: 1.添加了网络通信管理类 2.稍微修改了燃尽图模块ChartWidget 3.在主窗口中添加了用户信息框 4.重构了项目中的文件结 ...
- [转帖] Linux 下面栈空间大小的实验
比如局部变量是保存在栈空间中的,今天突然在想栈的上限是多大呢,什么时候才会栈溢出? ulimit 命令 linux下使用ulimit 命令可以查看系统的很多上限值. ulimit -a 查看所有 ul ...
- PSP(3.13——3.15)以及周记录
3.13 0:00 4:00 10 230 Cordova插件1,的尝试 N min 10:50 11:30 10 30 英语百词斩 N min 18:00 22:55 20 275 写博客 Y mi ...
- BZOJ1018 SHOI2008堵塞的交通(线段树)
动态图的连通性当然是可以用LCT维护的.但这相当的不优美,毕竟这样做没有用到任何该图的性质,LCT自带的大常数也会使其跑得非常慢. 考虑用线段树维护区间左右端四个点之间各自的连通性(仅经过该区间内路径 ...
- Merkle Tree 概念
Merkle Tree 概念 来源 https://www.cnblogs.com/fengzhiwu/p/5524324.html /*最近在看Ethereum,其中一个重要的概念是Merkle T ...
- MT【103】二阶递推找规律
评:如果直接找$a_n$的二阶递推式:$a_{n+2}-2\sqrt{2}a_{n+1}-a_n=0$有根号,不利于估计尾数.
- JS发送跨域Post请求出现两次请求的解决办法
原文地址: http://www.cnblogs.com/JimmyBright/p/7681097.html 所有跨域的js在提交post请求的时候,如果服务端设置了可跨域访问 public sta ...
- bzoj1345 序列问题 (贪心)
考虑某个点产生的贡献: 如果i左边是一个比它小的数x,那有两种情况: 1.x的左边的数y大于i,肯定要把x合并到i,i的贡献++ 2.x的左边的数y小于i,那肯定要把x合并到y,而这时候递归地来考虑, ...
- 【bzoj3992】 SDOI2015—序列统计
http://www.lydsy.com/JudgeOnline/problem.php?id=3992 (题目链接) 题意 集合${S}$中有若干个不超过${m}$的非负整数,问由这些数组成一个长度 ...