历史上的今天
返回首页

历史上的今天

今天是:2024年11月23日(星期六)

2019年11月23日 | TX2440裸机程序-nor flash

2019-11-23 来源:eefocus

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;      

 

                     }

 

              }

 

推荐阅读

史海拾趣

Dialog Semiconductor(戴乐格半导体)公司的发展小趣事

Dialog Semiconductor自2000年成立以来,就致力于技术创新。公司在早期阶段就专注于电源管理技术的研发,推出了多款高效能、低功耗的电源管理芯片,这些芯片被广泛应用于智能手机、可穿戴设备等移动设备中。随着物联网(IoT)的兴起,Dialog Semiconductor进一步拓展了产品线,增加了蓝牙和射频(RF)芯片等连接性解决方案,以满足市场对低功耗无线通信的需求。这些技术创新使Dialog Semiconductor在电子行业中建立了稳固的地位。

General Instrument Optoelectronics公司的发展小趣事
如高品质的蜂鸣器或扬声器。
EHC(ELECTRONICHARDWARE)公司的发展小趣事

面对日益全球化的市场环境,EHC公司积极实施国际化战略。公司通过与国外知名企业的合作,引进先进的技术和管理经验,不断提升自身的竞争力。同时,EHC公司还积极参加国际展会和论坛,拓展海外市场。经过多年的努力,EHC公司的产品已经成功打入国际市场,并在多个国家和地区建立了稳定的销售渠道。

ACT [Advanced Crystal Technology]公司的发展小趣事

EHC公司自创立之初就专注于电子硬件的技术创新。在竞争激烈的电子市场中,EHC公司凭借其独特的设计理念和先进的生产工艺,成功推出了一系列高性能、高可靠性的电子产品。这些产品不仅满足了消费者对高品质电子产品的需求,也为EHC公司赢得了良好的市场口碑。随着技术的不断进步,EHC公司不断推出创新产品,逐步巩固了其在行业中的领先地位。

對餘科技(DIOFIT)公司的发展小趣事

在追求经济效益的同时,DIOFIT公司也积极履行社会责任,致力于环保事业。他们注重节能减排和资源循环利用,采用环保材料和生产工艺,降低产品对环境的污染。同时,DIOFIT公司还积极参与各类公益活动,为社会发展和环境保护贡献自己的力量。

C&K Switches公司的发展小趣事

C&K Switches公司一直致力于技术创新和研发。它不断投入资金和资源,研发出了一系列具有高性能和可靠性的开关产品。这些产品不仅提高了设备的运行效率和稳定性,还降低了故障率和维修成本。同时,C&K还积极与合作伙伴和客户进行技术交流和合作,共同推动电子行业的发展。这种技术突破和创新精神使得C&K在激烈的市场竞争中保持领先地位。

问答坊 | AI 解惑

串联对个设备后往一个串口写数据

串联对个设备后,这些设备均是独立往一个串口写数据, 后果有没有影响? 请有实战者给予回答。 谢谢!…

查看全部问答>

嵌入式TCP/IP数据帧结构定义?

在一般的代码中都可以看到如下定义的帧结构 struct ip { uint         EtherHead[9];             uchar         VerandIphLen;       & ...…

查看全部问答>

ucos的信息邮箱用在子函数里,是不是消息邮箱的指针就传递不出来了啊?

ucos 用在任务之间,任务不删除任务中的变量就还在生存,所以邮箱能够把指针传递出来,但是如果用在子函数中,子函数运行结束,变量就没了,那么邮箱传递的地址内容就不对了。我的理解对吗,如果对的话,那怎么从子函数中传递出多个数据例如一个数 ...…

查看全部问答>

多参量调试信号源---上位机软件界面

主要分为两部分,上面是交流信号,可输出三角波和正弦波,每个信号可选择输出电压幅度,频率和相位。左边的波形显示是调节参数后即将输出的波形的形状(目前还没有输出),当用户确定需要输出该波形后点击 “开始交流输出”后信号源即开始输出波 ...…

查看全部问答>

电源电池芯片

开关型2/3/4节锂离子/锂聚合物充电管理芯片 1、 HB6295功能简述1.1、特性● 适用于2、3、4节锂离子/锂聚合物高效率充电器设计● 0.5%的充电电压控制精度 ● 恒压充电电压值可通过外接电阻微调 ● 智能电池检测 ● 外置功率MOSFET● 开关频率400KH ...…

查看全部问答>

开发板能否利用电脑(笔记本)的显示屏作为自己的显示屏呢?

开发板能否利用电脑(笔记本)的显示屏作为自己的显示屏呢? 听有的人说 笔记本的接口可以输出屏的内容 但是不能借输入! …

查看全部问答>

STC换网址了大家注意一下哈

今天突然打不开以前的www.stcmcu.com 联系STC的人员才知道网址换了,这里给大家提个醒,省得下东东找不到地方 www.gxwmcu.com …

查看全部问答>

如何写图形配置界面软件

现在越来越多的IC厂商推出图形配置界面,图形配置,生成代码。 工作中机型和机型之间也只是功能有所差异,能否通过图形界面选择功能,生成代码。 如何写这类图形配置界面软件? …

查看全部问答>

设计狮大神你怎么看?这个可以替代带灯轻触开关的结构--可发光可贴片的硅胶按键

LED SMD Rubber Touch Switch 贴片带灯硅胶按键。 寿命300W次,过回流焊,耐高温280度。发光均匀。 能否替代带灯轻触开关呢? …

查看全部问答>