新聞中心

        S3C2440-Nandflash

        作者: 時間:2016-12-02 來源:網(wǎng)絡 收藏
        Nandflash在對大容量的數(shù)據(jù)存儲中發(fā)揮著重要的作用。相對于norflash,它具有一些優(yōu)勢,但它的一個劣勢是很容易產(chǎn)生壞塊,因此在使用nandflash時,往往要利用校驗算法發(fā)現(xiàn)壞塊并標注出來,以便以后不再使用該壞塊。nandflash沒有地址或數(shù)據(jù)總線,如果是8位nandflash,那么它只有8個IO口,這8個IO口用于傳輸命令、地址和數(shù)據(jù)。nandflash主要以page(頁)為單位進行讀寫,以block(塊)為單位進行擦除。每一頁中又分為main區(qū)和spare區(qū),main區(qū)用于正常數(shù)據(jù)的存儲,spare區(qū)用于存儲一些附加信息,如塊好壞的標記、塊的邏輯地址、頁內(nèi)數(shù)據(jù)的ECC校驗和等。
        三星公司是最主要的nandflash供應商,因此在它所開發(fā)的各類處理器中,實現(xiàn)對nandflash的支持就不足為奇了。s3c2440不僅具有nandflash的接口,而且還可以利用某些機制實現(xiàn)直接從nandflash啟動并運行程序。本文只介紹如何對nandflash實現(xiàn)讀、寫、擦除等基本操作,不涉及nandflash啟動程序的問題。
        在這里,我們使用的nandflash為K9F2G08U0A,它是8位的nandflash。不同型號的nandflash的操作會有所不同,但硬件引腳基本相同,這給產(chǎn)品的開發(fā)帶來了便利。因為不同型號的PCB板是一樣的,只要更新一下軟件就可以使用不同容量大小的nandflash。
        K9F2G08U0A的一頁為(2K+64)字節(jié)(加號前面的2K表示的是main區(qū)容量,加號后面的64表示的是spare區(qū)容量),它的一塊為64頁,而整個設備包括了2048個塊。這樣算下來一共有2112M位容量,如果只算main區(qū)容量則有256M字節(jié)(即256M×8位)。要實現(xiàn)用8個IO口來要訪問這么大的容量,K9F2G08U0A規(guī)定了用5個周期來實現(xiàn)。第一個周期訪問的地址為A0"A7;第二個周期訪問的地址為A8"A11,它作用在IO0"IO3上,而此時IO4"IO7必須為低電平;第三個周期訪問的地址為A12"A19;第四個周期訪問的地址為A20"A27;第五個周期訪問的地址為A28,它作用在IO0上,而此時IO1"IO7必須為低電平。前兩個周期傳輸?shù)氖橇械刂罚笕齻€周期傳輸?shù)氖切械刂贰Mㄟ^分析可知,列地址是用于尋址頁內(nèi)空間,行地址用于尋址頁,如果要直接訪問塊,則需要從地址A18開始。
        #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(); //打開nandflash片選
        NF_CLEARRB(); //等待R/nB信號就緒
        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(); //復位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ū)讀寫,產(chǎn)生main區(qū)ECC校驗,然后鎖定ECC,這樣ECC就被硬件寫入rNFMECC0/1,我們將它讀到spare
        //區(qū)應該存放校驗的位置2048"2051。在讀寫spare區(qū)的時候,即產(chǎn)生spare區(qū)的ECC,硬件把它自動寫入rNFSECC中,會產(chǎn)生spare區(qū)
        //的校驗,兩個字節(jié),寫到2052"2053,在讀取的時候,我們將main區(qū)的ECC和spare區(qū)的ECC讀出來,放入rNFMECCD0/1和rNFSECC中,
        //硬件完成rNFMECC0/1,rNFSECC和rNFMECCD0/1,rNFSECCD的校驗。
        NF_MECC_ULOCK(); //解鎖main區(qū)的ECC
        for(i = 0; i < 2048; i++){
        NF_WRDATA8((char)(i+1)); //這個過程中產(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寫入spare前4個字節(jié),這個過程產(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寫入spare
        }
        NF_CMMD(CMD_WRITE2);
        NF_DETECT(); //等待R/nB信號變高,即不忙
        NF_CMMD(CMD_READSTATE); //發(fā)讀狀態(tài)命令, 0x70
        do{
        state = NF_RDDATA8(); //檢查狀態(tài) I/O 位0為0 是寫成功 1 是失敗, I/O 位6為0表示忙 為1是就緒
        }while(!(state&0x40));
        if(state&0x1){
        while(!(rUTRSTAT0&0x4));
        rUTXH0 = 0x43;
        return 0x43; //0x43隨機寫失敗
        }
        else{
        while(!(rUTRSTAT0&0x4));
        rUTXH0 = 0x63;
        return 0x63; //0x63隨機寫成功
        }
        }
        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ā)生錯誤
        rNFMECCD1 = ((mecc&0xff000000)>>8) | ((mecc&0xff0000)>>16); //校驗是因為nandflash很容易發(fā)生位反轉,壞塊
        secc = NF_RDDATA();
        rNFSECCD = ((secc&0xff00)<<8)|(secc&0xff);
        NF_CE_H();
        if((rNFESTAT0 & 0x0f) == 0x0){ //如果低4位都是0,說明沒有錯誤
        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;
        }
        }
        上一頁 1 2 下一頁

        評論


        技術專區(qū)

        關閉
        主站蜘蛛池模板: 天镇县| 淮北市| 温州市| 清河县| 那坡县| 永顺县| 西丰县| 互助| 潜江市| 三江| 衡水市| 德清县| 韶山市| 资阳市| 麻栗坡县| 馆陶县| 卢湾区| 滨州市| 呈贡县| 建水县| 南雄市| 宜城市| 萍乡市| 平山县| 庆安县| 伊川县| 汶上县| 玉田县| 遵义县| 江门市| 新泰市| 昭苏县| 林州市| 大化| 洛川县| 巴塘县| 仪征市| 永安市| 马龙县| 玉田县| 阳高县|