国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

S3C2440-Nandflash

發(fā)布時(shí)間:2011-3-28 14:03    發(fā)布者:techshare
關(guān)鍵詞: nandflash , S3C2440
Nandflash在對(duì)大容量的數(shù)據(jù)存儲(chǔ)中發(fā)揮著重要的作用。相對(duì)于norflash,它具有一些優(yōu)勢(shì),但它的一個(gè)劣勢(shì)是很容易產(chǎn)生壞塊,因此在使用nandflash時(shí),往往要利用校驗(yàn)算法發(fā)現(xiàn)壞塊并標(biāo)注出來(lái),以便以后不再使用該壞塊。nandflash沒(méi)有地址或數(shù)據(jù)總線,如果是8位nandflash,那么它只有8個(gè)IO口,這8個(gè)IO口用于傳輸命令、地址和數(shù)據(jù)。nandflash主要以page(頁(yè))為單位進(jìn)行讀寫(xiě),以block(塊)為單位進(jìn)行擦除。每一頁(yè)中又分為main區(qū)和spare區(qū),main區(qū)用于正常數(shù)據(jù)的存儲(chǔ),spare區(qū)用于存儲(chǔ)一些附加信息,如塊好壞的標(biāo)記、塊的邏輯地址、頁(yè)內(nèi)數(shù)據(jù)的ECC校驗(yàn)和等。

三星公司是最主要的nandflash供應(yīng)商,因此在它所開(kāi)發(fā)的各類處理器中,實(shí)現(xiàn)對(duì)nandflash的支持就不足為奇了。s3c2440不僅具有nandflash的接口,而且還可以利用某些機(jī)制實(shí)現(xiàn)直接從nandflash啟動(dòng)并運(yùn)行程序。本文只介紹如何對(duì)nandflash實(shí)現(xiàn)讀、寫(xiě)、擦除等基本操作,不涉及nandflash啟動(dòng)程序的問(wèn)題。

在這里,我們使用的nandflash為K9F2G08U0A,它是8位的nandflash。不同型號(hào)的nandflash的操作會(huì)有所不同,但硬件引腳基本相同,這給產(chǎn)品的開(kāi)發(fā)帶來(lái)了便利。因?yàn)椴煌吞?hào)的PCB板是一樣的,只要更新一下軟件就可以使用不同容量大小的nandflash。

K9F2G08U0A的一頁(yè)為(2K+64)字節(jié)(加號(hào)前面的2K表示的是main區(qū)容量,加號(hào)后面的64表示的是spare區(qū)容量),它的一塊為64頁(yè),而整個(gè)設(shè)備包括了2048個(gè)塊。這樣算下來(lái)一共有2112M位容量,如果只算main區(qū)容量則有256M字節(jié)(即256M×8位)。要實(shí)現(xiàn)用8個(gè)IO口來(lái)要訪問(wèn)這么大的容量,K9F2G08U0A規(guī)定了用5個(gè)周期來(lái)實(shí)現(xiàn)。第一個(gè)周期訪問(wèn)的地址為A0"A7;第二個(gè)周期訪問(wèn)的地址為A8"A11,它作用在IO0"IO3上,而此時(shí)IO4"IO7必須為低電平;第三個(gè)周期訪問(wèn)的地址為A12"A19;第四個(gè)周期訪問(wèn)的地址為A20"A27;第五個(gè)周期訪問(wèn)的地址為A28,它作用在IO0上,而此時(shí)IO1"IO7必須為低電平。前兩個(gè)周期傳輸?shù)氖橇械刂罚笕齻(gè)周期傳輸?shù)氖切械刂贰Mㄟ^(guò)分析可知,列地址是用于尋址頁(yè)內(nèi)空間,行地址用于尋址頁(yè),如果要直接訪問(wèn)塊,則需要從地址A18開(kāi)始。

#include "2440addr.h"  
#define CMD_READ1 0x00  
#define CMD_READ2 0x30  
#define CMD_READID 0x90  
#define CMD_RESET 0xFF  
#define CMD_WRITE1 0x80  
#define CMD_WRITE2 0x10  
#define CMD_BLOCKERASE1 0x60  
#define CMD_BLOCKERASE2 0xD0  
#define CMD_RANDOMWRITE 0x85  
#define CMD_RANDOMREAD1 0x05  
#define CMD_RANDOMREAD2 0xE0  
#define CMD_READSTATE 0x70  
#define NF_CMMD(cmd) rNFCMD = cmd  
#define NF_ADDR(addr) rNFADDR = addr  
#define NF_WRDATA(data) rNFDATA = data   
#define NF_WRDATA8(data) rNFDATA8 = data  
#define NF_RDDATA() rNFDATA  
#define NF_RDDATA8() rNFDATA8  
#define NF_CE_L() rNFCONT &= "(0x1<<1)  
#define NF_CE_H() rNFCONT |= 0x1<<1  
#define NF_MECC_LOCK() rNFCONT |= 0x1<<5  
#define NF_MECC_ULOCK() rNFCONT &= "(0x1<<5)  
#define NF_SECC_LOCK() rNFCONT |= 0x1<<6  
#define NF_SECC_ULOCK() rNFCONT &= "(0x1<<6)  
#define NF_RESETECC() rNFCONT |= 0x1<<4  
#define NF_WAITRB() while(!(rNFSTAT&0x1))  
#define NF_CLEARRB() rNFSTAT |= 0x1<<2  
#define NF_DETECT() while(!(rNFSTAT&0x1<<2))  
#define TACLS 1  
#define TWRPH0 1  
#define TWRPH1 1  
#define U32 unsigned int   
#define U8 unsigned char   
U8 buffer[2048], Ecc[6];   
U8 cmd, data, command;   
U32 block, add, pagenumber, count;   
U8 NF_BlockErase(U32 block){                      //擦除以塊為單位   
    U8 state;   
    NF_CE_L();                                    //打開(kāi)nandflash片選   
    NF_CLEARRB();                                 //等待R/nB信號(hào)就緒   
    NF_CMMD(CMD_BLOCKERASE1);        
    NF_ADDR((block<<6)&0xff);                        
    NF_ADDR((block>>2)&0xff);   
    NF_ADDR((block>>10)&0xff);      
    NF_CMMD(CMD_BLOCKERASE2);   
    NF_WAITRB();   
    NF_CMMD(CMD_READSTATE);                     
    do{   
        state = NF_RDDATA8();   
    }while(!(state&0x40));   
    if(state&0x1){   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x40;   
        return 0x40;                              //0x40塊擦除失敗         
    }   
    else{   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x60;   
        return 0x60;                              //0x60塊擦除成功   
    }   
}   
  
U8 NF_PageWrite(U32 pagenumber){   
    U32 i, mecc, secc;   
    U8 state;   
    NF_CE_L();   
    NF_RESETECC();                            //復(fù)位ECC     
    NF_CLEARRB();                  
    NF_CMMD(CMD_WRITE1);   
    NF_ADDR(0x00);   
    NF_ADDR(0x00);   
    NF_ADDR(pagenumber&0xff);   
    NF_ADDR((pagenumber>>8)&0xff);   
    NF_ADDR((pagenumber>>16)&0xff);  
    //先解鎖main區(qū),然后在main區(qū)讀寫(xiě),產(chǎn)生main區(qū)ECC校驗(yàn),然后鎖定ECC,這樣ECC就被硬件寫(xiě)入rNFMECC0/1,我們將它讀到spare
    //區(qū)應(yīng)該存放校驗(yàn)的位置2048"2051。在讀寫(xiě)spare區(qū)的時(shí)候,即產(chǎn)生spare區(qū)的ECC,硬件把它自動(dòng)寫(xiě)入rNFSECC中,會(huì)產(chǎn)生spare區(qū)
    //的校驗(yàn),兩個(gè)字節(jié),寫(xiě)到2052"2053,在讀取的時(shí)候,我們將main區(qū)的ECC和spare區(qū)的ECC讀出來(lái),放入rNFMECCD0/1和rNFSECC中,
    //硬件完成rNFMECC0/1,rNFSECC和rNFMECCD0/1,rNFSECCD的校驗(yàn)。
    NF_MECC_ULOCK();                          //解鎖main區(qū)的ECC   
    for(i = 0; i < 2048; i++){                  
        NF_WRDATA8((char)(i+1));              //這個(gè)過(guò)程中產(chǎn)生ECC   
    }   
    NF_MECC_LOCK();                           //鎖定main區(qū)ECC   
    mecc = rNFMECC0;                          //讀取main區(qū)ECC      
    Ecc[0] = (U8)(mecc&0xff);   
    Ecc[1] = (U8)((mecc>>8)&0xff);   
    Ecc[2] = (U8)((mecc>>16)&0xff);   
    Ecc[3] = (U8)((mecc>>24)&0xff);   
    NF_SECC_ULOCK();                          //解鎖main區(qū)的ECC   
    for(i = 0; i < 4; i++){   
        NF_WRDATA8(Ecc[ i]);                   //將maina區(qū)的ECC寫(xiě)入spare前4個(gè)字節(jié),這個(gè)過(guò)程產(chǎn)生spare區(qū)的ECC         
    }   
    NF_SECC_LOCK();                           //鎖定spare區(qū)的ECC   
    secc = rNFSECC;                           //讀取spare區(qū)的ECC   
    Ecc[4] = (secc)&0xff;   
    Ecc[5] = (secc>>8)&0xff;   
    for(i = 4; i < 6; i++){   
        NF_WRDATA8(Ecc[ i]);                   //將spare區(qū)的ECC寫(xiě)入spare   
    }   
    NF_CMMD(CMD_WRITE2);   
    NF_DETECT();                              //等待R/nB信號(hào)變高,即不忙
    NF_CMMD(CMD_READSTATE);                   //發(fā)讀狀態(tài)命令, 0x70
    do{   
        state = NF_RDDATA8();                 //檢查狀態(tài) I/O 位0為0 是寫(xiě)成功 1 是失敗, I/O 位6為0表示忙 為1是就緒   
    }while(!(state&0x40));   
    if(state&0x1){   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x43;   
        return 0x43;                              //0x43隨機(jī)寫(xiě)失敗   
    }   
    else{   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x63;   
        return 0x63;                              //0x63隨機(jī)寫(xiě)成功   
    }   
}   
U8 NF_PageRead(U32 pagenumber){   
    U32 i, mecc, secc;   
    NF_CE_L();   
    NF_RESETECC();   
    NF_CLEARRB();   
    NF_CMMD(CMD_READ1);   
    NF_ADDR(0x00);   
    NF_ADDR(0x00);   
    NF_ADDR(pagenumber&0xff);   
    NF_ADDR((pagenumber>>8)&0xff);   
    NF_ADDR((pagenumber>>16)&0xff);   
    NF_CMMD(CMD_READ2);   
    NF_WAITRB();   
    NF_MECC_ULOCK();   
    for(i = 0; i < 2048; i++){   
        buffer[ i] = NF_RDDATA8();   
    }   
    NF_MECC_LOCK();   
    NF_SECC_ULOCK();   
    mecc = NF_RDDATA();   
    NF_SECC_LOCK();   
    rNFMECCD0 = ((mecc&0xff00)<<8) | (mecc&0xff);                        //讀取剛才的ECC 讓rNFMECCD0/1,rNFSECCD與rNFMECC0/1,RNFSECC比較,看是否發(fā)生錯(cuò)誤   
    rNFMECCD1 = ((mecc&0xff000000)>>8) | ((mecc&0xff0000)>>16);          //校驗(yàn)是因?yàn)閚andflash很容易發(fā)生位反轉(zhuǎn),壞塊     
    secc =  NF_RDDATA();   
    rNFSECCD = ((secc&0xff00)<<8)|(secc&0xff);   
    NF_CE_H();   
    if((rNFESTAT0 & 0x0f) == 0x0){                                //如果低4位都是0,說(shuō)明沒(méi)有錯(cuò)誤   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x66;   
        for(i = 0; i < 8; i++){   
            while(!(rUTRSTAT0&0x4));     
            rUTXH0 = buffer[ i];   
        }   
        return 0x66;                                 
    }   
    else{   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x44;   
        return 0x44;   
    }   
}   
void NF_Init(){   
    //GPA 17~22接在nandflash上   
    rGPACON = rGPACON & ("(0x3f<<17)) | (0x3f<<17);   
    //TACLS為CLE/ALE有效到nWE有效之間的持續(xù)時(shí)間,TWRPH0為nWE的有效持續(xù)時(shí)間,TWRPH1為nWE無(wú)效到CLE/ALE無(wú)效之間的持續(xù)時(shí)間,這些時(shí)間都是以HCLK為單位的(本文程序中的HCLK=100MHz)   
    rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);   
    //非鎖定,屏蔽nandflash中斷,初始化ECC及鎖定main區(qū)和spare區(qū)ECC,使能nandflash片選及控制器   
    rNFCONT = (0<<13)|(0<<12)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);   
}   
void NF_Reset(){   
    NF_CE_L();   
    NF_WAITRB();   
    NF_CMMD(CMD_RESET);   
    NF_DETECT();   
    NF_CE_H();   
}   
void NF_ReadID(){   
    char MID, DID, cyc3, cyc4, cyc5;   
    NF_CE_L();   
    NF_CLEARRB();   
    NF_CMMD(CMD_READID);   
    NF_ADDR(0x00);   
    MID = NF_RDDATA8();                     //廠商ID   
    while(!(rUTRSTAT0&0x4));     
    rUTXH0 = MID;   
    DID = NF_RDDATA8();                     //設(shè)備ID   
    while(!(rUTRSTAT0&0x4));     
    rUTXH0 = DID;   
    cyc3 = NF_RDDATA8();                     //其他信息   
    while(!(rUTRSTAT0&0x4));     
    rUTXH0 = cyc3;   
    cyc4 = NF_RDDATA8();   
    while(!(rUTRSTAT0&0x4));     
    rUTXH0 = cyc4;   
    cyc5 = NF_RDDATA8();   
    while(!(rUTRSTAT0&0x4));     
    rUTXH0 = cyc5;   
    NF_CE_H();   
}   
U8 NF_RandomWrite(U32 pagenumber, U32 add, U8 data){      //根據(jù)時(shí)序來(lái)就行   
    U8 state;   
    NF_CE_L();   
    NF_CMMD(CMD_WRITE1);   
    NF_ADDR(0x00);   
    NF_ADDR(0x00);   
    NF_ADDR(pagenumber&0xff);   
    NF_ADDR((pagenumber>>8)&0xff);   
    NF_ADDR((pagenumber>>16)&0xff);   
    NF_CMMD(CMD_RANDOMWRITE);   
    NF_ADDR(add&0xff);                            //確定頁(yè)內(nèi)地址
    NF_ADDR((add>>8)&0xff);   
    NF_WRDATA8(data);                             //寫(xiě)數(shù)據(jù)   
    NF_CMMD(CMD_WRITE2);   
    NF_WAITRB();   
    NF_CMMD(CMD_READSTATE);   
    do{   
        state = NF_RDDATA8();   
    }while(!(state&0x40));   
    if(state&0x1){   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x44;   
        return 0x44;                              //0x44隨機(jī)寫(xiě)失敗   
    }   
    else{   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x66;   
        return 0x66;                              //0x66隨機(jī)寫(xiě)成功   
    }      
}   
U8 NF_RandomRead(U32 pagenumber, U32 add){         //根據(jù)時(shí)序來(lái)就行   
    char ch;   
    NF_CE_L();   
    NF_CMMD(CMD_READ1);   
    NF_ADDR(0x00);   
    NF_ADDR(0x00);   
    NF_ADDR(pagenumber&0xff);   
    NF_ADDR((pagenumber>>8)&0xff);   
    NF_ADDR((pagenumber>>16)&0xff);   
    NF_CMMD(CMD_READ2);   
    NF_WAITRB();   
    NF_CMMD(CMD_RANDOMREAD1);   
    NF_ADDR(add&0xff);   
    NF_ADDR((add>>8)&0xff);   
    NF_CMMD(CMD_RANDOMREAD2);   
    ch = NF_RDDATA8();                             //讀數(shù)據(jù)   
    while(!(rUTRSTAT0&0x4));     
    rUTXH0 = ch;   
    NF_CE_H();   
    return ch;   
}   
U8 NF_IsBadBlock(U32 block){   
    U8 result;   
    result = NF_RandomRead(block*64, 2054);   //0"2047是main區(qū)數(shù)據(jù),2048"2051是main區(qū)的ECC校驗(yàn),2052"2053是spare區(qū)的ECC校驗(yàn)
    if(result == 0x33){   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x62;   
        return 0x62;                              //0x62是壞塊        
    }   
    else{   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x42;   
        return 0x42;                              //0x42不是壞塊   
    }   
}   
U8 NF_MarkBadblock(U32 block){   
    U8 result;   
    result = NF_RandomWrite(block*64, 2054, 0x33);  //0x33標(biāo)記壞塊   block*64得到的是block塊第一個(gè)頁(yè)的地址
    if(result == 0x66){   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x61;   
        return 0x61;                              //0x61標(biāo)記壞塊成功   
    }   
    else{   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x41;   
        return 0x41;                              //0x41標(biāo)記壞塊失敗   
    }   
}   
   
void __irq UART0_ISR(void){     
    U8 ch;     
    rSRCPND |= (0x1<<28);     
    rINTPND |= (0x1<<28);     
    rSUBSRCPND |= 0x1<<0;     
    if(rUTRSTAT0 & 0x1){     
        ch = rURXH0;     
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = ch;   
        cmd = ch;   
    }     
}     
      
int Main(){   
    count = 0;   
    rULCON0 = 0x3;     
    rUCON0 = (1<<11)|(1<<2)|(1<<0);     
    rUBRDIV0 = 26;      
    rSRCPND = 0x1<<28;     
    rINTPND = 0x1<<28;     
    rSUBSRCPND = 0x1<<0;     
    rINTMSK &= "(0x1<<28);     
    rINTSUBMSK &= "(0x1<<0);     
    pISR_UART0 = (U32)UART0_ISR;   
    NF_Init();   
    while(1){   
        switch(cmd){   
            case 0x11:   
                NF_Reset();   
                break;   
            case 0x22:   
                NF_ReadID();   
                break;   
            case 0x33:   
                NF_RandomRead(2001*64,0x3);   
                break;   
            case 0x44:   
                NF_RandomWrite(2001*64,2052,0xbc);   
                break;   
            case 0x55:   
                NF_PageRead(2001*64);   
                break;   
            case 0x66:   
                while(!(rUTRSTAT0&0x4));     
                rUTXH0 = 0xba;   
                NF_PageWrite(2001*64);   
                break;   
            case 0x77:   
                NF_BlockErase(2001);   
                break;   
            case 0x88:   
                NF_IsBadBlock(2001);   
                break;   
            case 0x99:   
                NF_MarkBadblock(2001);   
                break;   
        }   
        cmd = 0;   
    }   
    return 0;   
}

作者:李萬(wàn)鵬
本文地址:http://m.qingdxww.cn/thread-60214-1-1.html     【打印本頁(yè)】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問(wèn)題,我們將根據(jù)著作權(quán)人的要求,第一時(shí)間更正或刪除。
銀洋電子 發(fā)表于 2011-4-1 16:43:49
頂一個(gè),,,,
您需要登錄后才可以發(fā)表評(píng)論 登錄 | 立即注冊(cè)

廠商推薦

  • Microchip視頻專區(qū)
  • 無(wú)線充電基礎(chǔ)知識(shí)及應(yīng)用培訓(xùn)教程
  • Chiptorials ——如何將CryptoAuthLib庫(kù)用于Microchip安全身份驗(yàn)證IC
  • Chiptorials ——使用ATECC608 TrustFLEX實(shí)現(xiàn)基本非對(duì)稱身份驗(yàn)證
  • Chiptorials——如何使用ATECC608 TrustFLEX實(shí)現(xiàn)公鑰輪換
  • 貿(mào)澤電子(Mouser)專區(qū)
關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號(hào) | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 国产日韩欧美视频在线观看 | 一级毛片在线免费观看 | 亚洲国产精品综合久久网络 | 色婷婷5月 | 日本免费在线观看 | 亚洲精品在线免费 | 麻豆xx | 久久久综合香蕉尹人综合网 | 久热精品在线视频 | 亚洲国产精品自在在线观看 | 久久是精品| 69视频在线观看免费 | 青青青青久在线观看视频 | 国产中文在线观看 | 亚洲性一级理论片在线观看 | 日本经典在线三级视频 | 欧美多人三级级视频播放 | 日本高清视频www | 一级成人黄色片 | 欧美一级特黄aaa大片 | 亚洲人成网址在线观看 | 看全色黄大色黄女视频 | 亚洲系列在线 | 色资源网 | 美女久久久久久久久久久 | 99久久国产综合精麻豆 | 国产亚洲精品午夜高清影院 | 香蕉网站视频高清在线观看 | 午夜 dy888理论久久 | 亚洲免费大片 | 国外欧美一区另类中文字幕 | 久久综合九色综合欧洲 | 另类视频色综合 | 国产午夜人做人视频羞羞 | 窝窝午夜在线观看免费观看 | 免费a级午夜绝情美女图片 免费a级毛片 | 亚洲欧美日韩国产综合 | 激情影院在线视频永久观看 | 日本精品久久久 | 日韩精品1区 | 九九99视频在线观看视频观看 |