zoukankan      html  css  js  c++  java
  • nor flash的一般操作与分析

    是现在市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NOR Flash 技术,彻底改变了原先由EPROM(Electrically Programmable Read-Only-Memory电可编程序只读存储器)和EEPROM(电可擦只读存储器Electrically Erasable Programmable Read - Only Memory)一统天下的局面。紧接着,1989年,东芝公司发表了NAND Flash 结构,强调降低每比特的成本,有更高的性能,并且像磁盘一样可以通过接口轻松升级。NOR Flash 的特点是芯片内执行(XIP ,eXecute In Place),这样应用程序可以直接在Flash闪存内运行,不必再把代码读到系统RAM。

    这样我们知道程序能直接在norlash执行的原因在XIP

    那:什么是XIP?工作原理又是怎么样的?

    XIP eXecute In Place

      eXecute In Place,即芯片内执行,指应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中。flash内执行是指nor flash 不需要初始化,可以直接在flash内执行代码。但往往只执行部分代码,比如初始化RAM.

    (注:片内执行不是说程序在存储器内执行哦,CPU的基本功能就是取指、译码和执行。norflash能在芯片内执行,就是指CPU的取指模块能够直接从norflash中把指令取出来,供后面的译码和执行模块使用

    --------------------- 本文来自 yjzh_td 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/yjzh_td/article/details/72870044?utm_source=copy 

    转:https://blog.csdn.net/thisway_diy/article/details/79397638

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

    Nor Flash原理图如图:

    这里写图片描述

    Flash介绍

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

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

    -NorNAND
    XIP(代码可以直接运行) Yes no
    性能(擦除) 非常慢(5s) 快(3ms)
    性能(写)
    性能(读)
    可靠性 较高,位反转的比例小于NAND Flash的10% 比较低,位反转比较常见,必须有校验措施,比如TNR必须有坏块管理措施
    可擦除次数 10000 ~ 100000 100000 ~ 1000000
    生命周期 低于NAND Flash的10% 是Nor Flash的10倍以上
    接口 与RAM接口相同 I/O接口
    易用性 容易 复杂
    主要用途 常用于保存代码和关键数 用于保存数据
    价格

    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....
    • 1
    • 2
    • 3
    • 4

    可以得出结论: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上的操作进行比较,如下表:

    Nor Flash的操作2440的操作U-BOOT上的操作
    往地址555H写入AAH(解锁) 往地址AAAH写入AAH(解锁) mw.waaaaa
    往地址2AAH写入55H(解锁) 往地址554H写入55H(解锁) mw.w 554 55
    往地址555H写入90H(命令) 往地址AAAH写入90H(命令) mw.w aaa 90
    读0地址得到厂家ID(C2H) 读0地址得到厂家ID(C2H) md.w 0 1 (1:表示都一次)
    读1地址得到设备ID(22DAH或225BH) 读2地址得到设备ID(22DAH或225BH) md.w 2 1 (1:表示都一次)
    退出读ID状态:给任意地址写F0H就可以了 退出读ID状态:给任意地址写F0H就可以了 mw.w 0 f0

    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 探测(读取芯片信息)进行比较参考芯片手册。

    Nor Flash上操作cfi2440上操作cfiU-BOOT上操作cfi
    往55H地址写入98H 往AAH地址写入98H mw.w aa 98
    读地址10H得到0051 读地址20H得到0051 md.w 20 1
    读地址11H得到0052 读地址22H得到0052 md.w 22 1
    读地址12H得到0059 读地址24H得到0059 md.w 24 1
    读地址27H得到容量 读地址4EH得到容量 md.w 4e 1

    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的写操作,如下表:

    Nor Flash上操作写操作2440上操作写操作U-BOOT上操作写操作
    往地址555H写AAH(解锁) 往地址AAAH写AAH(解锁) mw.w aaa aa
    往地址2AAH写55H(解锁) 往地址554H写55H(解锁) mw.w 554 55
    往地址555H写A0H 往地址AAAH写A0H mw.w aaa a0
    往地址PA写PD 往地址0x100000写1234h mw.w 100000 1234

    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  }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    读取函数

    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  }
    • 1
    • 2
    • 3
    • 4
    • 5

    读取地址中的数据

    向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  }
    • 1
    • 2
    • 3
    • 4

    进入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("
    
    ");
    118     }
    119     }
    120 printf("
    
    ");
    121 /* 退出CFI模式 */
    122 nor_cmd(0, 0xf0);
    123 }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    第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 flash
    
    ");
    240         printf("[e] Erase nor flash
    
    ");
    241         printf("[w] Write nor flash
    
    ");
    242         printf("[r] Read nor flash
    
    ");
    243         printf("[q] quit
    
    ");
    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 }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    主函数

    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("
    
    g_A = ");
    20      printHex(g_A);
    21      puts("
    
    ");
    22
    23      nor_flash_test();
    24  
    25      return 0;
    26  }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    第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}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    擦除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); 
    140     nor_cmd(addr>>1, 0x30);  /* 发出扇区地址 */
    141     wait_ready(addr);
    142 }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    第131行,get_uint函数用于获取输入的地址。

    第134,135这两行是解锁。

    第136行是erase sector。

    第138,139行是再次解锁。

    第140行是对发出的扇区地址。

    第 141行等待擦除完成。

    写NOR Flash

    do_write_nor_flash的代码如下所示,开发板上的NOR Flash的位宽是16bit,所以可以把要写的数据构造出16bit然后在写进NOR Flash中。

    144 void do_write_nor_flash(void)
    145 {
    146     unsigned int addr;
    147     unsigned char str[100];
    148     int i, j;
    149         unsigned int val;
    150 
    151     /* 获得地址 */
    152     printf("Enter the address of sector to write: ");
    153     addr = get_uint();
    154
    155     printf("Enter the string to write: ");
    156     gets(str);
    157
    158     printf("writing ...
    
    ");
    159
    160     /* str[0],str[1]==>16bit 
    161      * str[2],str[3]==>16bit 
    162     */
    163     i = 0;
    164     j = 1;
    165     while (str[i] && str[j])
    166     {
    167         val = str[i] + (str[j]<<8);
    168     
    169         /* 烧写 */
    170         nor_cmd(0x555, 0xaa);    /* 解锁 */
    171         nor_cmd(0x2aa, 0x55); 
    172         nor_cmd(0x555, 0xa0);    /* program */
    173         nor_cmd(addr>>1, val);
    174         /* 等待烧写完成 : 读数据, Q6无变化时表示结束 */
    175         wait_ready(addr);
    176
    177         i += 2;
    178         j += 2;
    179         addr += 2;
    180     }
    181
    182     val = str[i];
    183     /* 烧写 */
    184     nor_cmd(0x555, 0xaa);    /* 解锁 */
    185     nor_cmd(0x2aa, 0x55); 
    186     nor_cmd(0x555, 0xa0);    /* program */
    187     nor_cmd(addr>>1, val);
    188     /* 等待烧写完成 : 读数据, Q6无变化时表示结束 */
    189     wait_ready(addr);
    190 }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    第153行把通过get_uint获得的地址赋值给addr变量,

    第156行通过gets函数获得输入的字符串。

    第168行两个8位的数据,组合成一个16位的数据赋值给变量val。

    读NOR Flash

    do_read_nor_flash函数代码如下,由于NOR Flash是内存类接口,可以像内存一样读取。

    191 void do_read_nor_flash(void)
    192 {
    193     unsigned int addr;
    194     volatile unsigned char *p;
    195     int i, j;
    196     unsigned char c;
    197     unsigned char str[16];
    198 
    199     /* 获得地址 */
    200     printf("Enter the address to read: ");
    201     addr = get_uint();
    202
    203     p = (volatile unsigned char *)addr;
    204
    205     printf("Data :  
    
    ");
    206     /* 长度固定为64 */
    207     for (i = 0; i < 4; i++)
    208     {
    209         /* 每行打印16个数据 */
    210         for (j = 0; j < 16; j++)
    211         {
    212             /* 先打印数值 */
    213             c = *p++;
    214             str[j] = c;
    215             printf("%02x ", c);
    216         }
    217
    218         printf("   ; ");
    219
    220         for (j = 0; j < 16; j++)
    221         {
    222             /* 后打印字符 */
    223             if (str[j] < 0x20 || str[j] > 0x7e)  /* 不可视字符 */
    224                 putchar('.');
    225             else
    226                 putchar(str[j]);
    227         }
    228         printf("
    
    ");
    229 }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    第201行中的get_uint函数,从串口中获得输入的地址。
    第203行,强制类型转化。
    第207行~216行是对NOR Flash内容的读取,输出的内容为16进制的数据,由于NOR Flash是内存类接口,可以像内存一样读取。
    第220行~227输出NOR Flash的内容为字符型数据,其中的第223行用来判断,输出的字符是否为不可视字符,要是为不可视字符输出点’.’,要是可视字符输出字符。

    --------------------- 本文来自 韦东山 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/thisway_diy/article/details/79397638?utm_source=copy 

  • 相关阅读:
    ssh 代理详细解释
    c++ extern c
    php 删除换行符
    doxygen 模板
    php 判断字符串
    php 链接 mysql 数据库
    远程桌面管理:tsmmc.msc在xp系统中的使用
    更改Server 2008域用户密码策略
    Windows Server 2008 IIS7部署
    iis6中FTP配置的技巧和细节
  • 原文地址:https://www.cnblogs.com/newjiang/p/9710508.html
Copyright © 2011-2022 走看看