关于NorFlash的一点总结

最近在搞Uboot时才发现自己的裸机实验中没有相关NorFlash的代码,对NorFlash一无所知,查了一些资料,将自己的一点心得总结一下。

       开发板:mini2440

       NorFlash:SST39VF1601

 

       NorFlash简单来说与sdram与Nand的中间品,它能像sdram一样直接读,但是又得像nand一样编程擦写。因此程序可以直接在nor里跑,速度要比sdram慢一些,往nor里写数据必须先擦除,因为nor的每一位只能由1变为0。Nor可读不可直接写的特性可以被用来判断是Nor启动还是nand启动,因为nand启动的话前4K是可写的,我们写入数据再读取出来应该是没有问题的,而nor启动的话,读出的数据必然是错误的。


NorFlash的硬件接线:

       首先,如果做过sdram实验的朋友应该知道,NorFlash与sdram很相似,只不过sdram位宽为32,NOR为16。在硬件连接上,Nor的地址线与cpu的地址线错开1位,sdram错开2位。简单分析一下:

       32位的CPU地址线为32位,每一个地址对应1个byte,地址的步长为1byte
               0x0000 0000 对应第1个地址空间 大小为1bytes
               0x0000 0001 对应  2           大小为1bytes
               依次类推...
               可以理解为cpu的地址类型 为 u8 * addraddr+1  移动1个字节
       32位的sdram,每一个地址对应于4个byte,地址步长为4byte
               0x0000 0000 对应第1个地址空间 大小为4bytes
               0x0000 0001 对应  2           大小为4bytes
               依次类推...
               可以理解为sdram的地址类型 为 u32 * addraddr+1  移动4个字节
       16位的nor,每一个地址对应于2个byte,地址步长为2byte
               0x0000 0000 对应第1个地址空间 大小为2bytes
               0x0000 0001 对应  2           大小为2bytes
               依次类推...
               可以理解为nor的地址类型 为 u16 * addraddr+1  移动2个字节
       因此,CPU的地址与它们的地址是错位的。
               CPU的4个连续地址 如 0 1 2 3 均对应于sdram的 0地址
               CPU的2个连续地址 如 0 1     均对应于nor  的 0地址

       假如我想取sdram 0地址的 第二个byte 地址如何写?对于sdram和nor具体的每一个byte是无法寻址的呀,但是arm有一个叫存储管理器的东西,它大概会帮我们实现单字节的读写,至于sdram和nor支不支持单字节读写,我们后边在分析。


NorFlash的软件设置:

       需要像初始化sdram一样,设置Bank寄存器,主要是一些时序图的时间大小。

       位宽在BWSCON寄存器中设置,不过它是由硬件决定的,bank0的位宽,我们拨动开关选择nor启动还是nand启动的时候,它就已经确定了。


NorFlash信息:

        我这款Nor大小为2M,32个Block,每个block分为16个sector,一个sector为4K,具体信息如下图。

NorFlash写、擦除、读芯片ID:

       Nor可以像sdram一样直接读取,对于其它的操作,例如写、擦除、读信息等需要写特定的Date到特定的Addr。

这里尤其需要注意的是,Addr指的是nor地址线上看到的地址,相对于cpu也就是我们写程序的时候,需要将addr<<1,这样cpu错位的地址线发出的地址正好对上nor需求的地址。


        对于擦除操作,nor支持按block、sector或者整片的擦除,整个擦除需要6个周期,以按sector擦除为例,前五个周期为往XXX里写XXX,最后一个周期将0X30写入要擦除的sector对应的首地址即可。

        对于写操作,需要4个周期,前3个周期往XXX里写XXX,最后一个周期将Data写入addr,这里需要注意的是addr必须是半字对齐,data也要求为16bit。

       对于读取信息的操作,主要是读ID的操作,前3个周期往XXX里写XXX,第四个周期去读特定的地址,对于DeviceID来说,A1-A19=0,A0=1,对于CPU来说就是0x1<<1.      

NorFlash的等待:
       NorFlash有三种方式,1中读硬件引脚,另外两种读地址线,主要用读地址线的两种方式。
       1、Toggle
             连续读两次相同地址的数据,看DQ6是否相等,相等则擦除或写完成
       2、polling
             读数据,看DQ7是否正确,正确则擦除完成。如果擦除的话DQ7应该等于1,写操作的话,对比数据的第7位。




还有,很重要的一点:

经过我的测试,sdram的单字节读取没有问题,但是Nor单字节读取的时候,读出的数据并不正确。比如我在0x00地址处写入了0xff11,单字节读取0x0理论上应该得到0x11,而我在实际实验的时候得到的却是0xff。也就是说nor在存储半字数据的时候高8位于低8位互换了。



[cpp]  view plain  copy
  1. #include "uart.h"  
  2.   
  3. #define MAIN_SECT_SIZE  (4*1024)    /* 4 KB */  
  4. #define CMD_UNLOCK1         0x000000AA  
  5. #define CMD_UNLOCK2         0x00000055  
  6. #define CMD_ERASE_SETUP     0x00000080  
  7. #define CMD_ERASE_CONFIRM   0x00000030  
  8. #define CMD_PROGRAM         0x000000A0  
  9.   
  10. #define MEM_FLASH_ADDR1     (*(volatile U16 *)(0x000005555 << 1))  
  11. #define MEM_FLASH_ADDR2     (*(volatile U16 *)(0x000002AAA << 1))  
  12.   
  13. #define U16 unsigned short  
  14. #define U32 unsigned long  
  15. #define U8  unsigned char  
  16. int write_hword (U32 dest, U16 data);  
  17. typedef struct {  
  18.     U32 size;               /* total bank size in bytes             */  
  19.     U16 sector_count;       /* number of erase units                */  
  20.     U32 flash_id;           /* combined device & manufacturer code  */  
  21.     U32 start[512];         /* physical sector start addresses      */  
  22. } flash_info_t;  
  23. /*-----------------------------------------------------------------------*/  
  24.   
  25. void flash_id(){  
  26.     MEM_FLASH_ADDR1 = CMD_UNLOCK1;  
  27.     MEM_FLASH_ADDR2 = CMD_UNLOCK2;  
  28.     MEM_FLASH_ADDR1 = 0x00000090;  
  29.     print("Manufacturer ID :%x\r\n",*((U16 *)0x00));  
  30.     MEM_FLASH_ADDR1 = CMD_UNLOCK1;  
  31.     MEM_FLASH_ADDR2 = CMD_UNLOCK2;  
  32.     MEM_FLASH_ADDR1 = 0x00000090;  
  33.     print("Device ID :%x\r\n",*((U16 *)(0x01<<1)));  
  34. }  
  35. void flash_init ()      //计算总大小,每个sector的起始地址  
  36. {  
  37.     flash_id();  
  38.     //print("flash init OK\r\n");  
  39.     print("*((U32 *)0x32000000) = 0x00001100\r\n");  
  40.     *((U32 *)0x32000000) = 0x00001100;  
  41.     print("U8 0x32000001 == %x\r\n",*((U8 *)0x32000001));  
  42.       
  43.     *((U8 *)0x32000003) = 0xff;  
  44.     print("*((U8 *)0x32000003) = 0xff\r\n");  
  45.     print("now the U32 0x32000000 should be 0xff001100\r\n");  
  46.     print("U32 0x32000000 = %x\r\n",*((U32 *)0x32000000));  
  47.     print("U8  0x32000000 = %x\r\n",*((U8 *)0x32000000));  
  48.     print("U8  0x32000001 = %x\r\n",*((U8 *)0x32000001));  
  49.     print("U8  0x32000002 = %x\r\n",*((U8 *)0x32000002));  
  50.     print("U8  0x32000003 = %x\r\n",*((U8 *)0x32000003));  
  51.     if(flash_erase(0,1) == 0)  
  52.         print("erase OK\r\n");  
  53.   
  54.     U32 a = 0x00001c15;  
  55.     U16 b = 0x11ff;   
  56.     write_hword(a,b);  
  57.     print("*(U32 *0x00001c15) == 0x11ff\r\n");  
  58.     print("U8 0x1c15 = %x\r\n",*((U8 *)0x1c15));  
  59.     print("U8 0x1c16 = %x\r\n",*((U8 *)0x1c16));  
  60.     print("U16 0x1c15 = %x\r\n",*((U16 *)0x1c15));  
  61.       
  62.     if(write_buff((1024*20),0,(7*1024)) == 0)  
  63.         print("write OK\r\n");  
  64.   
  65. }  
  66.   
  67. int flash_erase (int s_first, int s_last)  
  68. {  
  69.     int i,j;  
  70.     U32 size = 0;  
  71.     flash_info_t flash_info;  
  72.     for (i = 0; i < 1; i++) {      
  73.         U32 flashbase = 0;  
  74.         flash_info.size = 2*1024*1024;  
  75.         flash_info.sector_count = 512;  
  76.         flashbase = 0;  
  77.           
  78.         for (j = 0; j < flash_info.sector_count; j++) {  
  79.                 flash_info.start[j] =  
  80.                     flashbase + (j) * MAIN_SECT_SIZE;  
  81.                     //print("%d   \t:%d\r\n",j,flash_info.start[j]);  
  82.         }         
  83.     }  
  84.           
  85.     int sect;  
  86.     unsigned short temp;  
  87.     /* Start erase on unprotected sectors */  
  88.     for (sect = s_first; sect <= s_last; sect++) {  
  89.         print ("Erasing sector %d ... \r\n", sect+1);         
  90.         volatile U16 * addr = (volatile U16 *)(flash_info.start[sect]);  
  91.         MEM_FLASH_ADDR1 = CMD_UNLOCK1;  
  92.         MEM_FLASH_ADDR2 = CMD_UNLOCK2;  
  93.         MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;  
  94.         MEM_FLASH_ADDR1 = CMD_UNLOCK1;  
  95.         MEM_FLASH_ADDR2 = CMD_UNLOCK2;  
  96.         *addr = CMD_ERASE_CONFIRM;  
  97.         print("wait\r\n");  
  98.         while(1){  
  99.               
  100.             temp = (*addr) & 0x40;  // 0100 0000   DQ6  
  101.             if(temp != (*addr) & 0x40)  //DQ6  
  102.                 continue;  
  103.             if(*addr & 0x80)        //dq7 ==1  
  104.                 break;  
  105.         }  
  106.     }  
  107.     return 0;  
  108. }  
  109.   
  110. //写16位数据,地址应该是16位对齐的。  
  111. int write_hword (U32 dest, U16 data)  
  112. {  
  113.     //print("now to write %d\r\n",dest);  
  114.     int rc;   
  115.     volatile U16 *addr = (volatile U16 *)dest;  
  116.     U16 result;  
  117.   
  118.     //Check if Flash is (sufficiently) erased  
  119.     result = *addr;  
  120.     if ((result & data) != data)  
  121.         return 1;  
  122.   
  123.     MEM_FLASH_ADDR1 = CMD_UNLOCK1;  
  124.     MEM_FLASH_ADDR2 = CMD_UNLOCK2;  
  125.     MEM_FLASH_ADDR1 = CMD_PROGRAM;  
  126.   
  127.     *addr = data;  
  128.     while(1){  
  129.     unsigned short i = *addr & 0x40;  
  130.     if(i != (*addr & 0x40))   //D6 == D6  
  131.         continue;  
  132.         if((*addr & 0x80) == (data & 0x80)){  
  133.             rc = 0;  
  134.             break;     //D7 == D7  
  135.         }  
  136.     }  
  137.     //print("write %d OK\r\n",dest);  
  138.     return rc;  
  139. }  
  140.   
  141. int write_buff (U32 src, U32 addr, U32 len)  
  142. {  
  143.     int rc;  
  144.     U16 data;   //16Bit?  
  145.     if(addr % 2){  
  146.         print("addr is not for 16bit align\n");  
  147.         return 1;  
  148.     }  
  149.     while (len >= 2) {  
  150.         data = *((volatile U16 *) src);  
  151.         if ((rc = write_hword (addr, data)) != 0) {  
  152.             return (rc);  
  153.         }  
  154.         src += 2;  
  155.         addr += 2;  
  156.         len -= 2;  
  157.     }  
  158.     return 0;  
  159. }  

注:转载自http://blog.csdn.net/lizuobin2/article/details/50381791
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值