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

S3C2440-Nandflash

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

三星公司是最主要的nandflash供應商,因此在它所開發的各類處理器中,實現對nandflash的支持就不足為奇了。s3c2440不僅具有nandflash的接口,而且還可以利用某些機制實現直接從nandflash啟動并運行程序。本文只介紹如何對nandflash實現讀、寫、擦除等基本操作,不涉及nandflash啟動程序的問題。

在這里,我們使用的nandflash為K9F2G08U0A,它是8位的nandflash。不同型號的nandflash的操作會有所不同,但硬件引腳基本相同,這給產品的開發帶來了便利。因為不同型號的PCB板是一樣的,只要更新一下軟件就可以使用不同容量大小的nandflash。

K9F2G08U0A的一頁為(2K+64)字節(加號前面的2K表示的是main區容量,加號后面的64表示的是spare區容量),它的一塊為64頁,而整個設備包括了2048個塊。這樣算下來一共有2112M位容量,如果只算main區容量則有256M字節(即256M×8位)。要實現用8個IO口來要訪問這么大的容量,K9F2G08U0A規定了用5個周期來實現。第一個周期訪問的地址為A0"A7;第二個周期訪問的地址為A8"A11,它作用在IO0"IO3上,而此時IO4"IO7必須為低電平;第三個周期訪問的地址為A12"A19;第四個周期訪問的地址為A20"A27;第五個周期訪問的地址為A28,它作用在IO0上,而此時IO1"IO7必須為低電平。前兩個周期傳輸的是列地址,后三個周期傳輸的是行地址。通過分析可知,列地址是用于尋址頁內空間,行地址用于尋址頁,如果要直接訪問塊,則需要從地址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區,然后在main區讀寫,產生main區ECC校驗,然后鎖定ECC,這樣ECC就被硬件寫入rNFMECC0/1,我們將它讀到spare
    //區應該存放校驗的位置2048"2051。在讀寫spare區的時候,即產生spare區的ECC,硬件把它自動寫入rNFSECC中,會產生spare區
    //的校驗,兩個字節,寫到2052"2053,在讀取的時候,我們將main區的ECC和spare區的ECC讀出來,放入rNFMECCD0/1和rNFSECC中,
    //硬件完成rNFMECC0/1,rNFSECC和rNFMECCD0/1,rNFSECCD的校驗。
    NF_MECC_ULOCK();                          //解鎖main區的ECC   
    for(i = 0; i < 2048; i++){                  
        NF_WRDATA8((char)(i+1));              //這個過程中產生ECC   
    }   
    NF_MECC_LOCK();                           //鎖定main區ECC   
    mecc = rNFMECC0;                          //讀取main區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區的ECC   
    for(i = 0; i < 4; i++){   
        NF_WRDATA8(Ecc[ i]);                   //將maina區的ECC寫入spare前4個字節,這個過程產生spare區的ECC         
    }   
    NF_SECC_LOCK();                           //鎖定spare區的ECC   
    secc = rNFSECC;                           //讀取spare區的ECC   
    Ecc[4] = (secc)&0xff;   
    Ecc[5] = (secc>>8)&0xff;   
    for(i = 4; i < 6; i++){   
        NF_WRDATA8(Ecc[ i]);                   //將spare區的ECC寫入spare   
    }   
    NF_CMMD(CMD_WRITE2);   
    NF_DETECT();                              //等待R/nB信號變高,即不忙
    NF_CMMD(CMD_READSTATE);                   //發讀狀態命令, 0x70
    do{   
        state = NF_RDDATA8();                 //檢查狀態 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比較,看是否發生錯誤   
    rNFMECCD1 = ((mecc&0xff000000)>>8) | ((mecc&0xff0000)>>16);          //校驗是因為nandflash很容易發生位反轉,壞塊     
    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;   
    }   
}   
void NF_Init(){   
    //GPA 17~22接在nandflash上   
    rGPACON = rGPACON & ("(0x3f<<17)) | (0x3f<<17);   
    //TACLS為CLE/ALE有效到nWE有效之間的持續時間,TWRPH0為nWE的有效持續時間,TWRPH1為nWE無效到CLE/ALE無效之間的持續時間,這些時間都是以HCLK為單位的(本文程序中的HCLK=100MHz)   
    rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);   
    //非鎖定,屏蔽nandflash中斷,初始化ECC及鎖定main區和spare區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();                     //設備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){      //根據時序來就行   
    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);                            //確定頁內地址
    NF_ADDR((add>>8)&0xff);   
    NF_WRDATA8(data);                             //寫數據   
    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隨機寫失敗   
    }   
    else{   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x66;   
        return 0x66;                              //0x66隨機寫成功   
    }      
}   
U8 NF_RandomRead(U32 pagenumber, U32 add){         //根據時序來就行   
    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();                             //讀數據   
    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區數據,2048"2051是main區的ECC校驗,2052"2053是spare區的ECC校驗
    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標記壞塊   block*64得到的是block塊第一個頁的地址
    if(result == 0x66){   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x61;   
        return 0x61;                              //0x61標記壞塊成功   
    }   
    else{   
        while(!(rUTRSTAT0&0x4));     
        rUTXH0 = 0x41;   
        return 0x41;                              //0x41標記壞塊失敗   
    }   
}   
   
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;   
}

作者:李萬鵬
本文地址:http://www.qingdxww.cn/thread-60214-1-1.html     【打印本頁】

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

廠商推薦

  • Microchip視頻專區
  • 安靜高效的電機控制——這才是正確的方向!
  • 想要避免發生災難,就用MPLAB® SiC電源仿真器!
  • 無線充電基礎知識及應用培訓教程2
  • 無線充電基礎知識及應用培訓教程3
  • 貿澤電子(Mouser)專區
關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日本www色视频成人免费免费 | 国产永久免费草莓网视频 | 蝴蝶传媒4.754 | 亚洲综合在线视频 | 四虎永久免费在线观看 | 亚洲精品98久久久久久中文字幕 | 999热视频 | 日韩一区二区三区在线观看 | 一本大道香焦在线视频 | 激情视频在线观看免费 | 国产一级毛片a午夜一级毛片 | 国产欧美日韩精品一区二区三区 | 国产区精品视频 | 四虎永久在线精品 | 99热66| 日本网站在线播放 | 特级毛片一级美国黑人 | 曰本亚洲欧洲色a在线 | 四虎影库紧急大通知 | 日日夜夜欧美 | 青青操手机看 | 香蕉视频网页版 | 久久毛片免费看 | 免费理论片高清西瓜影院 | 依欧美视频 | 老外一级毛片免费看 | 亚洲香蕉久久一区二区三区四区 | xxxxx亚洲 | 精品在线免费视频 | 好吊色青青青国产在线观看 | 久久6精品 | 国产yw855.c免费观看网站 | 女老师1| 国产三级在线观看完整版 | 91精品在线免费观看 | 亚洲色四在线视频观看 | 91热久久免费频精品99欧美 | 日语高清视频在线观看 | 青青青国产手机在线播放 | 中文字幕成人在线观看 | 欧洲97色综合成人网 |