14.Nor | 您所在的位置:网站首页 › s71200get指令读一个点怎么读 › 14.Nor |
目录 1.基础知识 2.使用u-boot体验Nor Flash的操作 3.编写NOR-Flash测试程序 源代码 数据手册 1.基础知识 1).Nor Flash 和Nand Flash 的区别? NOR FLASH 和NAND FLASH 的区别 NOR FLASHNAND FLASH结构NORflash采用内存的随机读取技术。各单元之间是并联的,对存储单元进行统一编址,所以可以随机访问任意一个字,应用程序可直接在flash内运行,而无需先拷贝到RAM。NANDflash数据线和地址线共用I/O线,需额外联接一些控制的输入输出读写速度NOR flash有更快的读取速度NAND flash有更快的写、擦除速度可靠性NOR的擦写次数是10万次NAND的擦写次数是100万次 (NAND器件的坏块是随机分布的) 成本和容量在面积和工艺相同的情况下,NAND的容量比NOR大的多,成本更低优缺点无位翻转,无坏块,稳定(存储关键性的程序)位反转,有坏块易用性NOR flash有专用的地址引脚来寻址,较容易和其他芯片联接,还支持本地执行NAND flash的IO端口采用复用的数据线和地址线,必须先通过寄存器串行地进行数据存取。各厂商对信号的定义不同,增加了应用的难度编程NOR flash采用统一编址(有独立地址线),可随机读取每个“字”,但NOR flash不能像RAM以字节改写数据,只能按“页”写,故NOR flash不能代替RAM。擦除既可整页擦除,也可整块擦除 注意: flash进行写操作时,只能将相应的位由1变0,而擦除才能把块内所有位由0变1。所有写入数据时,如果该页已经存在数据,必须先擦除再写。 NAND flash共用地址线和数据线,页是读写数据的最小单元,块是擦除数据的最小单元NOR FLASH 的特点是: 可以像内存一样的读取,但是不能直接写。 例子: 在Nor Flash中有以下指令: mov R0,#0 --R0赋值为0 LDR R1 ,[R0] --读取地址R0的值到寄存器R1 STR R1 ,[R0] --把R1的值写入R0寄存器 当执行STR R1 ,[R0] 不会成功,被视为无效操作。 这样子如果程序烧写在NOR FLASH 中会出现什么问题呢? 程序中含有需要更改的全局变量/静态变量(变量存储在栈中),但是如果现在bin文件烧写到NOR FLASH 上,那么意味着不能修改变量的值了,程序就会达不到我们预期的效果。所以如果想要的到想要的结果,就需要把这些全局变量/静态变量,重定位放到SDRAM(可读可写)中。 2).以S3C2440为例,设为NOR Flash 或 Nand Flash 启动时,启动地址的差别 .基本框架S3C2440是一个SOC,在一块芯片上面集成了有CPU、GPIO控制器、Nand控制器、Nor控制器、以及4K的SRAM。 1.NoR启动,NoR Flash 基地址为0(片内RAM地址为:0x40000000),CPU读出NOR读出上的第一个指令(前四个字节)执行,CPU继续读出其他指令执行(CPU可以在Nor Flash取指令直接执行)。 2.Nand启动,片内4K SRAM 基地之为0(Nor Falsh 不可访问),硬件2240把NAND前4K内容复制到片内内存SRAM中,然后CPU从0地址取出第一条指令(前四个字节)执行。 3).不同位宽内存设备之间的连接 内存控制器地址线和片外内存设备的接法: 可以发现他们的接法好像都是不同的,他们的规律是什么? 这时需要去查看一下芯片手册。 8-bit ROM 16-bit ROM 32-bit ROM 规律:那么就是说外接芯片的位宽有变化,那地址线的接法也有变化。 大致如下简图所示: 那为什么是这样呢?需要了解数据内部的保存结构,简图如下: 假如现在执行指令: mov R0 ,#3 --把3的数值赋值给R0 LDRB R1, [R0] --读取地址为3的位置读取1个字节的数据 那么CPU就会把地址3发出去,也就是:0x00000011 ,那么此时地址线 A0 =1, A1 =1 ,其他(A2-A27)为0. 如果外界是8-bit ROM,因为A0接A0,A1连接A1,此时他收到的就是0x3如果外界是16-bit ROM,因为A1接A0,A2连接A1,此时他收到的就是0x1如果外界是32-bit ROM,因为A2接A0,A3连接A1,此时他收到的就是0x0我们的任务是读取第3byte的数据: 当为8-bit ROM,那我收到的正好也是0x3这个数值,没有问题。 当为16-bit ROM,我收到的是0x1,这个数值,也就是十进制的1,读取地址编号为1的地址的值,很巧,发现我们需要第3字节的数据刚好在地址1的位置,但是这个位置有两个字节啊,怎么办?CPU不用管,它只需要发出地址就行,所以这也是内存控制器做的事,内存控制器根据收到的CPU发送的 A0 = 1 ,那么读取的就是地址编号为1,右边的那个字节(第3字节)的数据。 当为32-bit ROM,我收到的是0x0,这个数值,也就是十进制的0,读取地址编号为0的地址的值,同样,发现我们需要第3字节的数据刚好在地址0的位置,但是这个位置有四个字节啊,怎么办?CPU不用管,它只需要发出地址就行,所以这也是内存控制器做的事,内存控制器根据收到的 [A1:A0] = 11 ,那么读取的就是地址编号为0,最右边的那个字节(第3字节)的数据。 这个过程可以使用一张图来表示,就可以简单明了。 再举个例子: 假如现在执行指令: mov R0 ,#4 --把4的数值赋值给R0 LDR R1, [R0] --读取地址为43的位置读取4个字节的数据 那他的过程可以简化为下表: 所以CPU就是一个大BOSS,它只负责发出指令(地址)给内存控制器,而关于你数据是如何拆分和组装的,CPU并不关心,我只需要发出指令,然后就收数据就好了,那剩下的事情就是手下(内存控制器)做的,它负责数据的组装和拆分,最终把正确的结果返回给CPU。 2.使用u-boot体验Nor Flash的操作
例子2:读数据 烧写u-boot,到Nor Flash 上,开发版设为Nor Flash启动、 使用OpenJTAG:输入命令读取:md.b 0 读取Nor Flash 0地址的数据: 结果如下: 查看一下uboot.bin文件的数据和读取出来是一样: 说明Nor Flash可以直接读取数据。 例子2:读取ID 查看Nor Flash的数据手册,在此开发版使用的芯片型号是:MX29LV160DBTI 步骤: ①往地址 0x555写入数据0xAA ②往地址 0x2AA写入数据0x55 ③往地址 0x555写入数据0x90 ④读取地址0x00得到厂家ID:0xC2 ⑤读取地址0x01得到设备ID:MX29LV160DT: 22C4; MX29LV160DB: 2249 注意:设备位宽连接的问题,因为NOR Flash连接的是16位的,所以连接的简图如下 因此如果CPU需要往NOR Flash的0x555的写入数据0xAA,那么需要在2440发送地址的时候需要把0x555左移一位,再发送给Nor Flash才是正确的地址。 那么此时UBOOT怎么操作呢? 如果CPU需要左移一位,才是正确的地址,也就是是说,发送的地址需要乘上2,如下: 步骤: ①往地址 0xAAA写入数据0xAA (mw.w aaa aa) ②往地址 0x554写入数据0x55 (mw.w 554 55) ③往地址 0xAAA写入数据0x90 (mw.w aaa 90) ④读取地址0x00得到厂家ID:0xC2 (md.w 0 1) ⑤读取地址0x02得到设备ID:MX29LV160DT: 22C4; MX29LV160DB: 2249 ( md.w 2 1) 结果如下: 如何退出读ID状态? 往任意地址写入:0xF0 结果如下: 例子3:读取CFI信息 查看芯片手册的描述: 进入CFI(common flash interface)模式: 往地址0x55 写入 0x98 进入CFI模式 查询芯片容量: 从0x10 读取一个字节数据得到0x51(Q) 从0x11 读取一个字节数据得到0x51(R) 从0x12 读取一个字节数据得到0x51(Y) 从0x27 读取一个字节数据得到内存大小。 由于设备位宽不同,所以在OpenJTAG的操作是: 往地址0xAA 写入 0x98 进入CFI模式 (mw.w aa 98) 从0x20 读取一个字节数据得到0x51(Q) (md.w 20 1) 从0x22读取一个字节数据得到0x51(R) (md.w 22 1) 从0x24 读取一个字节数据得到0x51(Y) (md.w 24 1) 从0x4E 读取一个字节数据得到内存大小。(md.w 4e 1) 结果如下: 退出CFI模式,往任意地址写0xf0 例子4:写数据 试一下在地址1M以外的地方写入数据0x1234,然后读出来 那如何写数据呢?需要一定的格式,如下手册所描述: 步骤: ①往地址 0x555写入数据0xAA ②往地址 0x2AA写入数据0x55 ③往地址 0x555写入数据0xA0 ④往指定Addr写Data 那么此时UBOOT怎么操作呢? 如果CPU需要左移一位,才是正确的地址,也就是是说,发送的地址需要乘上2,如下: 步骤: ①往地址 0xAAA写入数据0xAA (mw.w aaa aa) ②往地址 0x554写入数据0x55 (mw.w 554 55) ③往地址 0xAAA写入数据0xA0 (mw.w aaa A0) ④往地址 0x100000 写入数据 0x1234 (mw.w 100000 1234) ⑤读取地址0x100000的数据是否写入成功 (md.w 100000 1) 结果如下:
例子5:当原来的数据不是全f的时候 解锁后能写入成功的前提,必须是这个位置的数据时全f,也就是:ffff 再次往0x100000这个地址 ,写入一个新数据,是否能成功? 那如何写呢?如果原来的数据不是全f,那么需要先对这个位置进行擦除操作 芯片数据手册的描述如下: 擦除扇区0x100000数据的步骤步骤: ①往地址 0x555写入数据0xAA ②往地址 0x2AA写入数据0x55 ③往地址 0x555写入数据0x80 ④往地址 0x555写入数据0xAA ⑤往地址 0x2AA写入数据0x55 ⑥往扇区0x100000写0x30 那么此时UBOOT怎么操作呢? 如果CPU需要左移一位,才是正确的地址,也就是是说,发送的地址需要乘上2,如下: 步骤: ①往地址 0xAAA写入数据0xAA (mw.w aaa aa) ②往地址 0x554写入数据0x55 (mw.w 554 55) ③往地址 0xAAA写入数据0x80 (mw.w aaa 80) ④往地址 0xAAA写入数据0xAA (mw.w aaa aa) ⑤往地址 0x554写入数据0x55 (mw.w 554 55) ④往地址 0x100000 写入数据 0x30 (mw.w 100000 30) 如下: 擦除成功后就可以正常的写数据了,和上面写的步骤是一样的。 在这个测试例程中有这几个功能如下: /*菜单选项 *1.识别nor_falsh,设备和容量 *2.读取某个地址的数据 *3.擦除nor_flash扇区数据 *4.往某个地址写数据 */ 1).识别nor_falsh打印出各个扇区的起始地址,读取设备ID和厂家ID以及设备容量 由数据手册可知,需要查询设备容量,厂家ID和设备ID之前,需要进入CFI模式 那么进入CFI模式的方式如下所描述:往0x55的地址写入0x98 退出CFI模式,如下所描述:往任意地址写0xF0 进入CFI模式之后,可以查询的信息如下描述: 读取设备容量:读取地址0x27可以得到设备容量 在CFI模式下,可以查询 erase region的有关信息: 其中region的描述需要参考:CFI publication 100 规范,如下: 代码如下: /*进入NOR_FLASH的CFI模式,读取设备信息*/ void Scan_nor_flash(void) { char qry[4]; //存储读取CFI模式下的QRY int Manifacture_ID,Devide_ID; int n,size; int regions; //NOR_Flash的region个数 int i,j,count=0; /*变量含义: * 1.region的起始地址 2.block的个数 * 3.每个block的大小 4.block的起始扇区基地址 */ int region_Bank_Area,blocks,block_size,block_base_addr; /*读取QRY字符到数组qry*/ nor_cmd(0x55,0x98);/*进入CFI模式,往0x55写0x98*/ qry[0] = nor_read(0x10); qry[1] = nor_read(0x11); qry[2] = nor_read(0x12); qry[3] = '\0'; printf("******************msg = %s\n\r" ,qry); //打印出QRY nor_cmd(0,0xf0); //复位,退出CFI模式 /*打印nor_flash的厂家ID,设备ID*/ nor_cmd(0x555,0xaa); nor_cmd(0x2AA,0x55); //解锁 nor_cmd(0x555,0x90); //读取厂家ID命令 Manifacture_ID = nor_read(0x00); //读取厂家ID Devide_ID = nor_read(0x01); //读取设备ID printf("******************The Manifacture_ID is: 0x%x\r\n",Manifacture_ID); printf("******************The Devide_ID is: 0x%x\r\n",Devide_ID); nor_cmd(0,0xf0); //复位 /*打印设备容量*/ nor_cmd(0x55,0x98);/*进入CFI模式,往0x55写0x98*/ n = nor_read(0x27); size = 1 |
CopyRight 2018-2019 实验室设备网 版权所有 |