14.Nor 您所在的位置:网站首页 s71200get指令读一个点怎么读 14.Nor

14.Nor

2024-07-12 03:55| 来源: 网络整理| 查看: 265

目录

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。

启动过程(大多数ARM芯片从0地址启动)

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)

如下:

擦除成功后就可以正常的写数据了,和上面写的步骤是一样的。

 

3.编写NOR-Flash测试程序

在这个测试例程中有这几个功能如下:

  /*菜单选项          *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 实验室设备网 版权所有