<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          S3C2440-Nandflash

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

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();