TX2440裸机程序-nor flash

转载 2013年12月01日 23:27:40

该文章转载于赵老师的博客:http://blog.csdn.net/zhaocj/article/details/5712259

norflash和nandflash是应用不同技术而实现的非易失闪存。它们之间的各自特点在这里就不做介绍了,而只把s3c2440对norflash的操作做一讲解。我们用的norflash为EN29LV160AB,其实对各种型号的norflash进行读写等操作差别不大。

       对norflash的操作主要就是读、写、擦除和识别等。EN29LV160AB的数据宽度可以是8位字节型,也可以是16位的字型,它由EN29LV160AB的某一引脚配置实现的。在这里我们选择字型。

 

对norflash的读操作比较简单,系统上电后会自动进入读模式,而且也不需要额外的命令来实现读操作。下面的函数实现了读操作:

 

U16 read_en29lv160ab(U32 addr)

{

       return *((volatile U16 *)(addr));

}

 

       norflash不仅能够实现硬件复位,而且可以实现软件复位。软件复位的操作是向任一地址写入复位命令0xF0。下面的函数实现了软件复位:

 

void reset_en29lv160ab(void)

{

       *((volatile U16 *)0x0) = 0xf0;

}

 

       norflash的擦除操作和写操作要稍微复杂一些,它们需要4个或6个周期来完成,每一个周期都要把相应的命令写入norflash中的某一命令寄存器中。写操作的过程为第一个周期是把命令0xAA写入地址为0x555的命令寄存器中,第二个周期是把命令0x55写入地址为0x2AA命令寄存器中,第三个周期是把命令0xA0再写入地址为0x555命令寄存器中,第四个周期为真正地把要写入的数据写入到norflash的地址中。下面的函数实现了写操作,其中该函数的两个输入参数分别为要写入的数据和地址,为了方便,我们事先定义好命令寄存器:

 

#define    flash_base              0x00000000

#define    CMD_ADDR0              *((volatile U16 *)(0x555<<1+flash_base))

#define    CMD_ADDR1              *((volatile U16 *)(0x2aa<<1+flash_base))

 

U8 en29lv160ab_program(U32 addr, U16 dat)

{

       CMD_ADDR0 = 0xaa;

       CMD_ADDR1 = 0x55;

       CMD_ADDR0 = 0xa0;

       *((volatile U16 *)(addr)) = dat;

 

       return check_toggle();

}

 

由于我们是把norflash连接到了s3c2440的bank 0上,因此norflash中的地址相对于s3c2440来说基址为0x00000000。而之所以又把norflash中的地址向左移一位(即乘以2),是因为我们是把s3c2440的ADDR1连接到了norflash的A0上的缘故。在该函数中,我们还调用了check_toggle函数,它的作用是用于判断这次操作是否正确,它的原型为:

 

U8 check_toggle()

{

       volatile U16 newtoggle,oldtoggle;

       oldtoggle = *((volatile U16 *)0x0);

 

       while(1)

       {    

              newtoggle = *((volatile U16 *)0x0);

             

              if((oldtoggle & 0x40)==(newtoggle & 0x40))

                     break;

             

              if(newtoggle & 0x20)           //DQ5

              {

                     oldtoggle = *((volatile U16 *)0x0);

                     newtoggle = *((volatile U16 *)0x0);

                    

                     if((oldtoggle & 0x40)==(newtoggle & 0x40))

                            break;

                     else

                            return 0;         //错误

              }    

              oldtoggle = newtoggle;

       }

      

       return 1;         //正确

}

 

它的原理是连续两次读取数据总线上的数据,判断数据总线上的第6位数值(DQ6)是否翻转,如果没有翻转则正确,否则还要判断第5位(DQ5),以确定是否是因为超时而引起的翻转。

 

       写操作只能使“1”变为“0”,而只有擦除才能使“0”变为“1”。因此在写之前一定要先擦除。擦除分为块擦除和整片擦除。块擦除的过程为第一个周期是把命令0xAA写入地址为0x555的命令寄存器中,第二个周期是把命令0x55写入地址为0x2AA命令寄存器中,第三个周期是把命令0x80再写入地址为0x555命令寄存器中,第四个周期是把命令0xAA写入地址为0x555的命令寄存器中,第五个周期是把命令0x55再写入地址为0x2AA命令寄存器中,第六个周期是把命令0x30写入要擦除块的首地址内。下面的函数为块擦除,其中输入参数为要擦除块的首地址:

U8 en29lv160ab_sector_erase(U32 section_addr)

{

       CMD_ADDR0 = 0xaa;

       CMD_ADDR1 = 0x55;

       CMD_ADDR0 = 0x80;

       CMD_ADDR0 = 0xaa;

       CMD_ADDR1 = 0x55;

       *((volatile U16 *)(section_addr)) = 0x30;

       

       return check_toggle();

}

 

       对norflash另一个比较常用的操作是读取芯片的ID。读取厂商ID的过程为第一个周期是把命令0xAA写入地址为0x555的命令寄存器中,第二个周期是把命令0x55写入地址为0x2AA命令寄存器中,第三个周期是把命令0x90再写入地址为0x555命令寄存器中,第四个周期为读取地址为0x100中的内容,即厂商ID(0x1C)。读取设备ID的过程的前三个周期与读取厂商ID相同,第四个周期是读取地址为0x01中的内容,即设备ID(0x2249)。下面的函数为读取芯片ID:

 

U32 get_en29lv160ab_id(void)

{

       U32 temp=0;

       CMD_ADDR0 = 0xaa;

       CMD_ADDR1 = 0x55;

       CMD_ADDR0 = 0x90;  

       temp = (*(volatile unsigned short *)(flash_base+ (0x100<<1)))<<16;

       temp |= *(volatile unsigned short *)(flash_base + (1<<1));

       

       return temp;

}

 

下面的程序实现了对一块区域进行擦除,写入,并读出的操作,判断写入的数据是否与读出的数据相同:

 

……   ……

U16 buffer[1024];

char cmd;

……   ……

 

void test_en29lv160ab(void)

{

       U32 temp;

       U8 sta;

       int i;

       

       for(i=0;i<1024;i++)

       buffer[i]=2*i+1;

           

       //读ID

temp = get_en29lv160ab_id();

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)((temp&0xff000000)>>24);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)((temp&0x00ff0000)>>16);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)((temp&0x0000ff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)((temp&0x000000ff));

   

reset_en29lv160ab();            //这里一定要复位

     

delay(100);

     

       //擦除块33

       sta=en29lv160ab_sector_erase(0xf0000);

if(sta == 0)

       {

              while(!(rUTRSTAT0 & 0x2)) ;

              rUTXH0=0xaf;             //擦除出错

       }

       else

       {

              for(i=0;i<1024;i++)

              {

                     sta = en29lv160ab_program(0xf0000+(i<<1),buffer[i]);            //写

                     if(sta == 0)           //写出错

                     {

                            while(!(rUTRSTAT0 & 0x2));

                            rUTXH0=0xbf;      

                            break;

                     }

                     delay(200);

              }

              

              if(sta == 1)

              {

                     for(i=0;i<1024;i++)

                     {

                            if(read_en29lv160ab(0xf0000+(i<<1))!=buffer[i])            //读出错

                            {

                                   while(!(rUTRSTAT0 & 0x2)) ;

                                   rUTXH0=0xcf; 

                                   sta = 3;

                                   break;

                            }

                     }

                     if(sta !=3)             //全部操作都正确

                     {

                            while(!(rUTRSTAT0 & 0x2)) ;

                            rUTXH0=0x66;      

                     }

              }

       }

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=0x88;                    //结束

}

 

//简单测试CFI

void test_en29lv160ab_CFI(void)

{

       U16 temp;

       

       *((volatile U16 *)(0x55<<1+flash_base))=0x98;               //CFI命令

       temp = (*(volatile unsigned short *)(flash_base+ (0x10<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x11<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x12<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x13<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x14<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x15<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x16<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x17<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x18<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x19<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

       

       temp = (*(volatile unsigned short *)(flash_base+ (0x1a<<1)));

       //while(!(rUTRSTAT0 & 0x2))      ;

       //rUTXH0=(U8)((temp&0xff00)>>8);

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=(U8)(temp&0x00ff);

}

 

void __irq uartISR(void)

{

       char ch;

       rSUBSRCPND |= 0x1;

       rSRCPND |= 0x1<<28;

       rINTPND |= 0x1<<28;

       ch=rURXH0;

       

       switch(ch)

       {

              case 0x11:                     //get ID

                     cmd = 1;

                     break;

              case 0x66:                    //test CFI

                     cmd = 6;

                     break;

              case 0x77:                    //test norflash

                     cmd = 7;

                     break;

       }

       while(!(rUTRSTAT0 & 0x2)) ;

       rUTXH0=ch;

}

 

void Main(void)

{

       U32 temp;

       int i;

 

//uart0 port

       rGPHCON = 0x00faaa;

rGPHUP  = 0x7ff;

 

//init uart0

rULCON0 = 0x3;

       rUCON0 = 0x5;

rUFCON0 = 0;

       rUMCON0 = 0;

rUBRDIV0 = 26;

       rSRCPND = (0x1<<19)|(0x1<<28);

       rSUBSRCPND = 0x1;

rINTPND = (0x1<<19)|(0x1<<28);

       rINTSUBMSK = ~(0x1);

       rINTMSK = ~((0x1<<19)|(0x1<<28));

       pISR_UART0 = (U32)uartISR;   

 

       cmd = 0;

       while(1)

       { 

              switch(cmd)

              {

                     case 1:                   //读ID

                            cmd = 0;

                            temp = get_en29lv160ab_id();

                            while(!(rUTRSTAT0 & 0x2)) ;

                            rUTXH0=(U8)((temp&0xff000000)>>24);

                            while(!(rUTRSTAT0 & 0x2)) ;

                            rUTXH0=(U8)((temp&0x00ff0000)>>16);

                            while(!(rUTRSTAT0 & 0x2)) ;

                            rUTXH0=(U8)((temp&0x0000ff00)>>8);

                            while(!(rUTRSTAT0 & 0x2)) ;

                            rUTXH0=(U8)((temp&0x000000ff));

                            reset_en29lv160ab();

                            break;

 

                     case 0x7:               

                            cmd = 0;

                            test_en29lv160ab();

                            break;

                            

                     case 0x6:

                            cmd = 0;

                            test_en29lv160ab_CFI();

                            reset_en29lv160ab();

                            break;

              }

}

}


 

 

为什么NORflash可以作为启动设备直接执行程序

NOR Flash 和 NAND Flash 是现在市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NOR Flash 技术,彻底改变了原先由EPROM(Electrically...
  • yjzh_td
  • yjzh_td
  • 2017年06月05日 18:26
  • 665

linux之NOR FLASH驱动程序

使用UBOOT体验NOR FLASH的操作(开发板设为NOR启动,进入UBOOT) 先使用OpenJTAG烧写UBOOT到NOR FLASH 1. 读数据 md.b 0 2. 读ID NOR手册...
  • sanmaoljh
  • sanmaoljh
  • 2016年04月09日 08:51
  • 894

NOR flash 坏块处理方法

一直认为"Nor flash没有坏块,而Nand flash出厂时可能就有坏块",推想NOR flash一旦存在坏块就报废了,挺可惜的,今天查找资料才了解到NOR flash 是存在坏块的,只不过是在...
  • xiaofei0859
  • xiaofei0859
  • 2015年11月16日 17:59
  • 4193

关于NorFlash的一点总结

最近在搞Uboot时才发现自己的裸机实验中没有相关NorFlash的代码,对NorFlash一无所知,查了一些资料,将自己的一点心得总结一下。        开发板:mini2440       ...
  • lizuobin2
  • lizuobin2
  • 2015年12月22日 19:09
  • 7588

嵌入式开发之NorFlash 和NandFlash

嵌入式开发之NorFlash 和NandFlash[摘要]:作为一个嵌入式工程师,要对NorFlash 和NandFlash要有最起码的认知。本文通过从启动方式、读写方式、容量成本、可靠性、寿命以及是...
  • tigerjb
  • tigerjb
  • 2013年07月14日 00:23
  • 5021

NOR FLASH读、写、擦原理与实现(1)——性能简述与术语解释

这段时间,由于项目需要,我得对FLASH的运作原理做初步的理解,并且对其实现方法进行研究。我将通过几篇博客将我的学习历程记录下来,并且希望跟诸位有缘看到博客的人共同讨论、学习。...
  • qq_30866297
  • qq_30866297
  • 2017年05月22日 10:54
  • 867

NOR FLASH和NAND FLASH各应用在什么产品上

随着电子产品的功能日益丰富,成本效益高、功耗低、密度高及外型小的存储器产品的市场需求日益增加,NOR FLASH和NAND FLASH原本不同的市场定义,现在也慢慢的变得模糊起来了。我们从以下几个方面...
  • yxfabcdefg
  • yxfabcdefg
  • 2014年08月04日 11:07
  • 2927

Nor Flash工作原理

Nor Flash 具有像内存一样的接口,它可以像内存一样读,却不可以像内存一样写,Nor Flash 的写、擦除都需要发出特定的命令。谈到 Nor Flash 通常就会涉及到 CFI ([Commo...
  • yuesichiu
  • yuesichiu
  • 2013年01月27日 14:15
  • 4915

NOR Flash擦写和原理分析

NOR Flash擦写和原理分析 1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程...
  • tangsun999
  • tangsun999
  • 2015年04月25日 15:32
  • 2672

NOR flash 和NAND flash区别深入分析

闪存芯片读写的基本单位不同     应用程序对NOR芯片操作以“字”为基本单位。为了方便对大容量NOR闪存的管理,通常将NOR闪存分成大小为128KB或者64KB的逻辑块,有时候块内还分成扇区。读...
  • zhangzker
  • zhangzker
  • 2017年04月01日 16:38
  • 755
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:TX2440裸机程序-nor flash
举报原因:
原因补充:

(最多只允许输入30个字)