历史上的今天
返回首页

历史上的今天

今天是:2025年03月23日(星期日)

正在发生

2020年03月23日 | 第015课 NOR Flash操作原理及裸机程序分析

2020-03-23 来源:eefocus

#第001节_Nor Flash原理及硬件操作 #
Nor Flash的连接线有地址线,数据线,片选信号读写信号等,Nor Flash的接口属于内存类接口,Nor Flash可以向内存一样读,但是不能像内存一样写,需要做一些特殊的操作才能进行写操作,读只需像内存一样读很简单。

Nor Flash原理图如图:

这里写图片描述

Flash介绍

常用的Flash类型有Nor Flash和NAND Flash两种。

Nor Flash由Intel公司在1988年发明,以替代当时在市场上占据主要地位的EPROM和E2PROM。NAND Flash由Toshiba公司在1989年发明。两者的主要差别如下表:

image.png?imageView2/2/w/550

Nor Flash支持XIP,即代码可以直接在Nor Flash上执行,无需复制到内存中。这是由于NorF lash的接口与RAM完全相同,可以随机访问任意地址的数据。Nor Flash进行读操作的效率非常高,但是擦除和写操作的效率很低,另外,Nor Flash的容量一般比较小。NAND Flash进行擦除和写操作的效率更高,并且容量更大。一般而言,Nor Flash用于存储程序,NAND Flash用于存储数据。基于NAND Flash的设备通常也要搭配Nor Flash以存储程字。

Flash存储器件由擦除单元(也称为块)组成,当要写某个块时,需要确保这个块己经
被擦除。Nor Flash的块大小范围为64kB、128kB:NAND Flash的块大小范围为8kB,64kB,擦/写一个Nor Flash块需4s,而擦/写一个NAND Flash块仅需2ms。Nor Flash的块太大,不仅增加了擦写时间,对于给定的写操作,Nor Flash也需要更多的擦除操作——特别是小文件,比如一个文件只有IkB,但是为了保存它却需要擦除人小为64kB—128kB的Nor Flash块。

Nor Flash的接口与RAM完全相同,可以随意访问任意地址的数据。而NAND Flash的
接口仅仅包含几个I/O引脚,需要串行地访问。NAND Flash一般以512字节为单位进行读写。这使得Nor Flash适合于运行程序,而NAND Flash更适合于存储数据。

容量相同的情况下,NAND Flash的体积更小,对于空间有严格要求的系统,NAND Flash可以节省更多空间。市场上Nor Flash的容量通常为IMB~4MB(也有32MB的Nor Flash),NAND Flash的容量为8MB~512MB。容量的差别也使得Nor Flash多用于存储程序,NAND Flash多用于存储数据。

对于Flash存储器件的可靠性需要考虑3点:位反转、坏块和可擦除次数。所有Flash器件都遭遇位反转的问题:由于Flash固有的电器特性,在读写数据过程中,偶然会产生一位或几位数据错误(这种概率很低),而NAND Flash出现的概率远大于Nor Flash,当位反转发生在关键的代码、数据上时,有可能导致系统崩溃。当仅仅是报告位反转,重新读取即可:如果确实发生了位反转,则必须有相应的错误检测/恢复措施。在NAND Flash上发生位反转的概率史高,推荐使用EDC/ECC进行错误检测和恢复。NAND Flash上面会有坏块随机分布在使用前需要将坏块扫描出来,确保不再使用它们,否则会使产品含有严重的故障。NAND Flash每块的可擦除次数通常在100000次左右,是Nor Flash的10倍。另外,因为NAND Flash的块大小通常是NorF lash的1/8,所以NAND Flash的寿命远远超过Nor Flash。

嵌入式Linux对Nor、NAND Flash的软件支持都很成熟。在Nor Flash上常用jffs2文
件系统,而在NAND Flash常用yaffs文件系统。在更底层,有MTD驱动程序实现对它们的读、写、擦除操仵,它也实现了EDC/ECC校验。

Nor Flash的操作##

下面我们使用u-boot来体验Nor Flash的操作(开发板设置Nor启动,进入u-boot)。

1).使用OpenJTAG烧写UBOOT到Nor Flash

那么我们怎么用u-boot来操作呢?

Nor Flash手册里会有一个命令的表格,如图:
这里写图片描述

下面简单的举一些例子:

复位(reset):往任何一个地址写入F0。

读ID(ReadSiliconID):很多的Nor Flash可以配置成位宽16bit(Word),位宽8bit(Byte)。对于我们使用的jz2440开发板使用是位宽16bit,怎样读ID呢?

根据前面得图可知,往Nor Flash的555地址写AA,再往2AA的地址写入55,再往555的地址写入90,然后就可以读ADI地址,就可以读到DDI数据了。

实例1

读数据:

在u-boot上执行:md.b0

结果(和我们烧进去的数据完全一样):

00000000:170000ea14f09fe514f09fe514f09fe5................
00000010:14f09fe514f09fe514f09fe514f09fe5................
00000020:6001f833c001f8332002f8337002f833`..3...3..3...3
00000030:e002f8330004f8332004f833efbeadde...3...3..3....

可以得出结论:u-boot可以像读内存一样来读nor flash

实例2

读ID(参考Nor手册)

  • 往地址555H写入AAH(解锁)

  • 往地址2AAH写入55H(解锁)

  • 往地址555H写入90H(命令)

  • 读0地址得到厂家ID(C2H)

  • 读1地址得到设备ID(22DAH或225BH)

  • 退出读ID状态:给任意地址写F0H就可以了。

下图为2440和Nor Flash的简易连接图:
这里写图片描述

2440的A1接到Nor的A0所以2440发出的地址是,Nor Flash收到的地址左移一位。比如:2440发出(555H<<1)地址,Nor Flash才能收到555H这个地址。

下面对在Nor Flash的操作,2440的操作,U-BOOT上的操作进行比较,如下表:

image.png?imageView2/2/w/550

1).当执行过
md.w 0 1
结果(输出厂家ID):
00000000:00c2…(00c2就是厂家ID)

2).当执行过
md.w 2 1

结果(输出设备ID):
00000002:2249I"(2249就是设备ID)

3).当执行
mw.w 0 f0
就退出读ID的状态,

执行:
md.b0
结果:
00000000:17.(读到的就是Nor Flash地址·0的数据)

Nor Flash的两种规范

通常内核里面要识别一个 Nor Flash 有两种方法:

一种是 jedec 探测,就是在内核里面事先定义一个数组,该数组里面放有不同厂家各个芯片的一些参数,探测的时候将 flash 的 ID 和数组里面的 ID 一一比较,如果发现相同的,就使用该数组的参数。
jedec 探测的优点就是简单,缺点是如果内核要支持的 flash 种类很多,这个数组就会很庞大。内核里面用 jedec 探测一个芯片时,是先通过发命令来获取 flash 的 ID,然后和数组比较,但是 flash.c 中连 ID 都是自己通过宏配置的。

一种是 CFI(common flash interface)探测,就是直接发各种命令来读取芯片的信息,比如 ID、容量等,芯片本身就包含了电压有多大,容量有有多少等信息。

下面对在Nor Flash上操作,2440上操作,U-BOOT上操作cfi 探测(读取芯片信息)进行比较参考芯片手册。

image.png?imageView2/2/w/550

##Nor Flash写数据 ##
我们在Nor Flash的10000的地址读数据,
md.w 100000 1
结果:
00100000:ffff…
在Nor flash的10000的地址写数据下0x1234,
mw.w 100000 1234
然后在这个地址读数据,
md.w 100000 1
结果:
00100000:ffff(这个地址上的数据没有被修改,写操作无效)。

怎样把数据写进Nor Flash进去呢?

写数据之前必须保证,要写的地址是擦除的。

下面是Nor Flash的写操作,如下表:

image.png?imageView2/2/w/550

1).U-BOOT执行完上述指令后,0x1234,就被写到0x100000地址处,


执行:

md.w1000001

结果(1234被写进去):

00100000:1234 4

从这里可以看出来U-BOOT的操作不是很复杂。


2).我们再次往0x100000地址处,写入0x5678,执行如下命令:

mw.w aaa aa

mw.w 554 55

mw.w aaa a0

mw.w 100000 5678

查看0x100000地址处的数据

md.w 100000 1

结果:

00100000:12300.

0x100000地址处的数据不是0x5678,写操作失败,失败的原因是,原来的数据已经是0x1234不是全0xffff,再次写操作失败,(Nor Flash只有先擦出,才能烧写)。


先擦除(参考Nor Flash芯片手册)

Nor Flash操作 u-boot操作

555H AAH mw.w aaa aa

2AAH 55H mw.w 554 55

555H 80H mw.w aaa 80

555H AAH mw.w aaa aa

2AAH 55H mw.w 554 55

SA 30H //往扇区地址写入30 mw.w 100000 30


执行完上述指令后测试


执行:

md.w 100000 1

结果:

00100000:ffff…

已被擦除,这个时候再次烧写就不会有问题了。


再烧写

mw.w aaa aa

mw.w 554 55

mw.w aaa a0

mw.w 100000 5678


测试烧写结果

执行:

md.w 100000 1

结果:

00100000:5678 xV

数据被烧写进去,烧写成功。


总结:我们烧写时,如果上面的数据,不是0ffff,没有被擦除过,我们就要先擦出,擦除完后,才可以烧写,擦除烧写的命令可以从芯片手册里面获得。


= 第002节_Nor Flash编程_识别 =

本节实例的目的目的:识别nor flash

发送命令函数

nor_cmd函数代码如下,往NOR Flash某个地址发送指令,


16

17 /* offset是基于NOR的角度看到 */

18 void nor_cmd(unsigned int offset, unsigned int cmd)

19 {

20 nor_write_word(NOR_FLASH_BASE, offset, cmd);

21 }

读取函数


nor_read_word函数是从NOR Flash 读取两个字节(本开发板位宽16bit),读取数据的地址,是基于2440,所以读取NOR Flash某个地址上的数据时,需要把NOR Flash对应的地址左移一位(地址乘以2)。


23 unsigned int nor_read_word(unsigned int base, unsigned int offset)

24 {

25 volatile unsigned short *p = (volatile unsigned short *)(base + (offset << 1));

26 return *p;

27 }

读取地址中的数据


向nor_dat函数中写入NOR Flash某个地址,返回该NOR Flash地址上的数据。


29 unsigned int nor_dat(unsigned int offset)

30 {

31 return nor_read_word(NOR_FLASH_BASE, offset);

32 }

进入NOR FLASH的CFI模式,读取各类信息


do_scan_nor_flash函数代码如下,该函数的功能:进入CFI模式读取NOR Flash中的厂家ID,设备ID,容量等信息。


50/* 进入NOR FLASH的CFI模式

51 * 读取各类信息

52 */

53 void do_scan_nor_flash(void)

54 {

55 char str[4];

56 unsigned int size;

57 int regions, i;

58 int region_info_base;

59 int block_addr, blocks, block_size, j;

60 int cnt;

61

62 int vendor, device;

63

64 /* 打印厂家ID、设备ID */

65 nor_cmd(0x555, 0xaa);    /* 解锁 */

66 nor_cmd(0x2aa, 0x55); 

67 nor_cmd(0x555, 0x90);    /* read id */

68 vendor = nor_dat(0);

69 device = nor_dat(1);

70 nor_cmd(0, 0xf0);        /* reset */

71

72 nor_cmd(0x55, 0x98);  /* 进入cfi模式 */

073

74 str[0] = nor_dat(0x10);

75 str[1] = nor_dat(0x11);

76 str[2] = nor_dat(0x12);

77 str[3] = '';

78 printf("str = %s", str);

79

80 /* 打印容量 */

81 size = 1<<(nor_dat(0x27));

82 printf("v=0x%x,d=0x%x,s=0x%x,%dM",vendor,device,size,size/(1024*1024));

83

84 /* 打印各个扇区的起始地址 */

85 /* 名词解释:

86 *    erase block region : 里面含有1个或多个block, 它们的大小一样

87 * 一个nor flash含有1个或多个region

88 * 一个region含有1个或多个block(扇区)

89

90 * Erase block region information:

91 *    前2字节+1    : 表示该region有多少个block 

92 *    后2字节*256  : 表示block的大小

93 */

94

95 regions = nor_dat(0x2c);

96 region_info_base = 0x2d;

97 block_addr = 0;

98 printf("Block/Sector start Address:");

99 cnt = 0;

100 for (i = 0; i < regions; i++)

101 {

102    blocks = 1 + nor_dat(region_info_base) + (nor_dat(region_info_base+1)<<8);

103    block_size=256*(nor_dat(region_info_base+2)+(nor_dat(region_info_base+3)<<8));

104    region_info_base += 4;

105

106    //printf("…………");

107

108 for (j = 0; j < blocks; j++)

109 {

110 /* 打印每个block的起始地址 */

111 //printf("0x%08x ", block_addr);

112 printHex(block_addr);

113 putchar(' ');

114 cnt++;

115 block_addr += block_size;

116 if (cnt % 5 == 0)

117 printf("nr");

118 }

119 }

120 printf("nr");

121 /* 退出CFI模式 */

122 nor_cmd(0, 0xf0);

123 }

第65,66行 这两步是解锁,解锁之后就进入读ID状态,就可以读取厂家和设备ID了。


第68行 是把读取到的厂家ID的值,复制给vendor变量。


第69行 是把读取到的设备ID的值,复制给device变量。


第70行 退出读ID状态: 给任意地址写F0H。


第72行,往地址0x55地址写入数据0x98,是进入cfi模式。


第74,75,76行是读取NOR Flash地址0x10,0x11,x012中的字符,赋值给字符串str。


第81行,根据芯片手册可知道,读取NOR Flash地址0x27处的数据,得到的是NOR Flash容量大小2的幂数,所以把1左移读取到的数据,就可得到NOR Flash的容量。


第95行读取NOR Flash地址0x2c地址中的数据,可以得到NOR Flash中有多少region。


第102行根据Erase block region information:的信息可以知道读取[2E,2D]这两个字节的地址+1,可以得到一个region有多少block(参考芯片手册)。代码中的region_info_base变量的值是0x2d,0x2d是前两个字节中的低字节,0x2e是前两个字节中的高字节,所以需要左移8位,然后加上1就得到了一个region有多少block.。


第103行参考芯片手册,读取[30,2F]这两个字节地址,然后乘上256就可以得到一个块的大小。


第104行,地址加4,读取下一个region有多少block和每个block的大小。


第112,115行,由于NOR Flash的基地址是0,所以第一个block的首地址是0,下一个block的首地址,就是上一个block的首地址加上block的大小。


第112行往0地址写入0xf0,退出CFI模式。


Nor Flash的测试


nor_flash_test函数通过switch语句,分别处理识别NOR Flash,擦除NOR Flash某个扇区,编写某个地址,读某个地址。代码如下:


232 void nor_flash_test(void)

233 {

234 char c;

235

236 while (1)

237 {

238 /* 打印菜单, 供我们选择测试内容 */

239 printf("[s] Scan nor flashnr");

240 printf("[e] Erase nor flashnr");

241 printf("[w] Write nor flashnr");

242 printf("[r] Read nor flashnr");

243 printf("[q] quitnr");

244 printf("Enter selection: ");

245

246 c = getchar();

247 printf("%c", c);

248

249 /* 测试内容:

250 * 1. 识别nor flash

251 * 2. 擦除nor flash某个扇区

252 * 3. 编写某个地址

253 * 4. 读某个地址

254 */

255 switch (c)  

256 {

257 case 'q':

258 case 'Q':

259 return;

260 break;

261

262 case 's':

263 case 'S':

264 do_scan_nor_flash();

265 break;

266

267 case 'e':

268 case 'E':

269 do_erase_nor_flash();

270 break;

271

272 case 'w':

273 case 'W':

274 do_write_nor_flash();

275 break;

276

277 case 'r':

278 case 'R':

279 do_read_nor_flash();

280 break;

281 default:

282 break;

283 }

284 }

285 }

主函数


main函数代码如下所示。把timer中断去掉,否则: 测试NOR Flash时进入CFI等模式时, 如果发生了中断,cpu必定读NOR Flash,那么读不到正确的指令,导致程序崩溃。


12 int main(void)

13 {

14 led_init();

15 //interrupt_init();  /* 初始化中断控制器 */

16 key_eint_init();   /* 初始化按键, 设为中断源 */

17 //timer_init();

18

19 puts("nrg_A = ");

20 printHex(g_A);

21 puts("nr");

22

23 nor_flash_test();

24

25 return 0;

26 }

第003节_Nor Flash编程_擦写读

本实例的目的目的:擦除nor flash某个扇区,编写某个地址,读某个地址。


等待烧写


等待烧写完成 : 读数据, Q6无变化时表示结束 (参考芯片手册),


35 void wait_ready(unsigned int addr)

36 {

37 unsigned int val;

38 unsigned int pre;

39

40 pre = nor_dat(addr>>1);

41 val = nor_dat(addr>>1);

42 while ((val & (1<<6)) != (pre & (1<<6)))

43 {

44 pre = val;

45 val = nor_dat(addr>>1);

46 }

47}

擦除NOR Flash 某个扇区


do_erase_nor_flash函数的代码如下。参考芯片手册,就可以知道擦除某个扇区,还是相对比较简单的。


125 void do_erase_nor_flash(void)

126 {

127 unsigned int addr;

128

129 /* 获得地址 */

130 printf("Enter the address of sector to erase: ");

131 addr = get_uint();

132

133 printf("erasing ...");

134 nor_cmd(0x555, 0xaa);    /* 解锁 */

135 nor_cmd(0x2aa, 0x55); 

136 nor_cmd(0x555, 0x80); /* erase sector */

137

138 nor_cmd(0x555, 0xaa);    /* 解锁 */

139 nor_cmd(0x2aa, 0x55); 

推荐阅读

史海拾趣

ECS公司的发展小趣事

ECS公司始终坚持以客户为中心的服务理念。他们深入了解客户的需求和痛点,为客户量身定制解决方案。例如,针对某些行业对数据安全性的特殊要求,ECS公司推出了专用的安全加密方案;针对一些大型企业对于大规模计算资源的需求,ECS公司提供了定制化的高性能计算服务。这些定制化服务不仅满足了客户的特殊需求,还增强了客户对ECS公司的信任和忠诚度。

DETCO公司的发展小趣事

随着智能家居市场的兴起,ElectronicsCorp看到了巨大的潜力。公司投入大量资金研发智能家居设备和技术,并与多家知名家居品牌合作推出了一系列智能家居解决方案。这些解决方案不仅提供了便捷的智能家居体验,还注重用户隐私保护和数据安全。通过不断创新和优化产品体验,ElectronicsCorp在智能家居领域取得了显著突破,并成为全球智能家居市场的领军企业之一。

GE公司的发展小趣事

ElectronicsCorp最初是一个在亚洲某城市的小型电子产品制造商。它以其高质量和合理的价格迅速获得了市场份额。公司创始人李先生坚持将研发作为核心驱动力,不断投入资金研发新技术。随着时间的推移,ElectronicsCorp的产品线不断扩大,包括智能手机、平板电脑和智能家居设备。凭借持续的创新和卓越的质量,ElectronicsCorp逐渐成长为全球电子行业的领导者。

ADI(亚德诺半导体)公司的发展小趣事

在电子产品行业日益关注环保和可持续发展的背景下,ElectronicsCorp采取了一系列积极措施。公司开始使用环保材料制造产品,并优化生产流程以减少能源消耗和废物排放。此外,ElectronicsCorp还推出了一系列回收计划,鼓励消费者将旧电子产品回收再利用。这些措施不仅提高了公司的环保形象,还增强了消费者对公司品牌的忠诚度。

Helium公司的发展小趣事

Helium公司成立于2013年,由Shawn Fanning、Amir Haleem和Sean Carey共同创立。在创立初期,Helium专注于物联网无线网络技术的研究,但并未迅速获得市场关注。这一时期,电子行业正处于创新与转型阶段,物联网作为新兴领域展现出巨大潜力。Helium团队预见到了物联网的发展趋势,但由于缺乏明确的商业模式,其网络发展并未大规模铺开。然而,这段时期的积累为Helium后续的技术突破和市场拓展奠定了坚实基础。

Dawn Electronics Inc公司的发展小趣事

在快速发展的同时,Dawn Electronics Inc公司始终关注社会责任。公司积极参与公益活动,支持教育、环保等事业。同时,公司还注重环保和可持续发展,采用环保材料和生产工艺,减少对环境的影响。这些举措不仅提升了公司的社会形象,也为公司的长期发展奠定了坚实的基础。

问答坊 | AI 解惑

第五届全国大学生机器人

好东西!同大家分享下!…

查看全部问答>

【专贴】各位需要什么资料?

本帖最后由 paulhyde 于 2014-9-15 09:37 编辑 各位需要什么资料或者关于什么方面的内容,可以跟帖说说~~~~ 看看大家能不能帮到你~~~ (一般在需要在CNKI期刊、万方等数据库处需要付费下载的资料我都可以下载到~~~如果有看中的论文、期刊等也可 ...…

查看全部问答>

模电设计不得不看——模拟电路设计原则

主要内容: 衡量设计质量的标准 常用模拟电路设计方法 电磁兼容和认证 PCB布局布线技巧等…

查看全部问答>

如何用C语言编程能让单片机读入通过USB输入的信息还有一个关于红外线发射的问题

用什么方法能让单片机(8051F320)读入 通过 USB输入到 单片机FLASH中的信息? 还有用什么语句能实现单片机通过红外线发射管 发射编码?…

查看全部问答>

winio初始化失败

,用winio本身提供的例子,对系统并口进行操作,可是初始化总是不成功,而将vb代码编译成可执行文件,则不存在此问题.怎么解决啊? …

查看全部问答>

wince里BT发ping封包用什麽函数阿?

具体要求是:在wince里先启动BT,搜寻固定的BT裝置,然后发ping封包,size為1K。 我已经搜到BT装置拉,但是不知道用什麽函数去发ping封包,我搜到的BT装置没有IP地址,所以不知道怎麽发. 请各位高手帮帮忙! …

查看全部问答>

申请LM3S8962 评估套件

 希望看得见,摸得着。…

查看全部问答>

RT-Thread 2010年11月上海开发者会议总结

11月7日,上海江场三路上海软件开源委员会上海软件促进中心 在发出RT-Thread 11月上海开发者会议消息的短短一周内,大家热情高涨,当天会场就有总计28名人员的参与!回忆前两年,开发者会议最低谷时仅有ffxz与shaolin两人参加的场面,感慨万千 ...…

查看全部问答>

基于单片机和LM35的温度测控

我们现在在做单片机课程设计,由于是第一次做项目很多东西都还不懂,望各位大哥大姐多多指教哈。 用LM35和ADC0809基于单片机STC89C52检测室内温度,为何在数码管显示数值是乱码。…

查看全部问答>

Failed to match a default incude file。

怎么回事,我是菜鸟,刚刚入门,多多指教了。…

查看全部问答>