您的位置 首页 编程

s3c2440对norflash的操作

norflash和nandflash是应用不同技术而实现的非易失闪存。它们之间的各自特点在这里就不做介绍了,而只把s3c2440对norflash的操作做一讲解。…

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;

}

}

}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/biancheng/274902.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部