<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > s3c2440對norflash的操作

s3c2440對norflash的操作

作者: 時(shí)間:2016-11-11 來(lái)源:網(wǎng)絡(luò ) 收藏
norflash和nandflash是應用不同技術(shù)而實(shí)現的非易失閃存。它們之間的各自特點(diǎn)在這里就不做介紹了,而只把s3c2440對norflash的操作做一講解。我們用的norflash為EN29LV160AB,其實(shí)對各種型號的norflash進(jìn)行讀寫(xiě)等操作差別不大。

本文引用地址:http://dyxdggzs.com/article/201611/316866.htm

對norflash的操作主要就是讀、寫(xiě)、擦除和識別等。EN29LV160AB的數據寬度可以是8位字節型,也可以是16位的字型,它由EN29LV160AB的某一引腳配置實(shí)現的。在這里我們選擇字型。

對norflash的讀操作比較簡(jiǎn)單,系統上電后會(huì )自動(dòng)進(jìn)入讀模式,而且也不需要額外的命令來(lái)實(shí)現讀操作。下面的函數實(shí)現了讀操作:

U16 read_en29lv160ab(U32 addr)

{

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

}

norflash不僅能夠實(shí)現硬件復位,而且可以實(shí)現軟件復位。軟件復位的操作是向任一地址寫(xiě)入復位命令0xF0。下面的函數實(shí)現了軟件復位:

void reset_en29lv160ab(void)

{

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

}

norflash的擦除操作和寫(xiě)操作要稍微復雜一些,它們需要4個(gè)或6個(gè)周期來(lái)完成,每一個(gè)周期都要把相應的命令寫(xiě)入norflash中的某一命令寄存器中。寫(xiě)操作的過(guò)程為第一個(gè)周期是把命令0xAA寫(xiě)入地址為0x555的命令寄存器中,第二個(gè)周期是把命令0x55寫(xiě)入地址為0x2AA命令寄存器中,第三個(gè)周期是把命令0xA0再寫(xiě)入地址為0x555命令寄存器中,第四個(gè)周期為真正地把要寫(xiě)入的數據寫(xiě)入到norflash的地址中。下面的函數實(shí)現了寫(xiě)操作,其中該函數的兩個(gè)輸入參數分別為要寫(xiě)入的數據和地址,為了方便,我們事先定義好命令寄存器:

#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來(lái)說(shuō)基址為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; //正確

}

它的原理是連續兩次讀取數據總線(xiàn)上的數據,判斷數據總線(xiàn)上的第6位數值(DQ6)是否翻轉,如果沒(méi)有翻轉則正確,否則還要判斷第5位(DQ5),以確定是否是因為超時(shí)而引起的翻轉。

寫(xiě)操作只能使“1”變?yōu)?ldquo;0”,而只有擦除才能使“0”變?yōu)?ldquo;1”。因此在寫(xiě)之前一定要先擦除。擦除分為塊擦除和整片擦除。塊擦除的過(guò)程為第一個(gè)周期是把命令0xAA寫(xiě)入地址為0x555的命令寄存器中,第二個(gè)周期是把命令0x55寫(xiě)入地址為0x2AA命令寄存器中,第三個(gè)周期是把命令0x80再寫(xiě)入地址為0x555命令寄存器中,第四個(gè)周期是把命令0xAA寫(xiě)入地址為0x555的命令寄存器中,第五個(gè)周期是把命令0x55再寫(xiě)入地址為0x2AA命令寄存器中,第六個(gè)周期是把命令0x30寫(xiě)入要擦除塊的首地址內。下面的函數為塊擦除,其中輸入參數為要擦除塊的首地址:

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另一個(gè)比較常用的操作是讀取芯片的ID。讀取廠(chǎng)商ID的過(guò)程為第一個(gè)周期是把命令0xAA寫(xiě)入地址為0x555的命令寄存器中,第二個(gè)周期是把命令0x55寫(xiě)入地址為0x2AA命令寄存器中,第三個(gè)周期是把命令0x90再寫(xiě)入地址為0x555命令寄存器中,第四個(gè)周期為讀取地址為0x100中的內容,即廠(chǎng)商ID(0x1C)。讀取設備ID的過(guò)程的前三個(gè)周期與讀取廠(chǎng)商ID相同,第四個(gè)周期是讀取地址為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;

}

下面的程序實(shí)現了對一塊區域進(jìn)行擦除,寫(xiě)入,并讀出的操作,判斷寫(xiě)入的數據是否與讀出的數據相同:

…… ……

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]); //寫(xiě)

if(sta == 0) //寫(xiě)出錯

{

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; //結束

}

//簡(jiǎn)單測試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;

}

}

}



關(guān)鍵詞: s3c2440norflas

評論


技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>