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

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > arm2440的nandflash相關(guān)函數(shù)

          arm2440的nandflash相關(guān)函數(shù)

          作者: 時(shí)間:2016-11-21 來(lái)源:網(wǎng)絡(luò) 收藏
          K9F2G08U0A nand flash 的容量為256M byte,其內(nèi)部有2048塊,每塊有64頁(yè),每頁(yè)有2K+64字節(jié),其中每頁(yè)會(huì)分為main區(qū)(主域)和spare區(qū)(備用域),main區(qū)一般用來(lái)存入主要數(shù)據(jù),spare一般用來(lái)存放ECC校驗(yàn)碼。

          本文引用地址:http://www.ex-cimer.com/article/201611/319263.htm

          下面幾點(diǎn)是編程時(shí)需要注意的:

          1.NAND FLASH芯片手冊(cè)里說(shuō)的column是指頁(yè)內(nèi)地址,row是指頁(yè)地址,page也是指頁(yè);

          2.刪除時(shí)是以塊為單位的,但是刪除塊時(shí)寫(xiě)的是row地址,自動(dòng)會(huì)刪除row所在的塊;

          3.讀寫(xiě)方式有頁(yè)讀寫(xiě),或隨機(jī)讀寫(xiě),所謂的隨機(jī)讀寫(xiě)就是可以在頁(yè)內(nèi)的任一地方讀寫(xiě)一個(gè)字節(jié);

          4.ECC校驗(yàn)碼分為main區(qū)的ECC和spare區(qū)的ECC,它們一般都會(huì)存放在64字節(jié)的spare區(qū)內(nèi),下面是翻譯2440手冊(cè)的關(guān)于ECC編程的內(nèi)容:

          ECC 編程向?qū)?/p>

          1) 在軟件模式, ECC 模塊會(huì)為全部讀 / 寫(xiě)數(shù)據(jù)產(chǎn)生 ECC 檢驗(yàn)碼。所以你需要在讀或者寫(xiě)數(shù)據(jù)前給 InitECC(NFCONT[4]) 位寫(xiě) 1 和給 MainECCLock(NFCONT[5]) 位寫(xiě) 0(Unlock) 來(lái)復(fù)位 ECC 值。

          MainECCLock(NFCONT[5]) 和 SpareECCLock(NFCONT[6] 控制 ECC 校驗(yàn)碼是否產(chǎn)生。

          2) 任何時(shí)候讀或者寫(xiě)數(shù)據(jù)時(shí), ECC 模塊在 NFMECC0/1 上產(chǎn)生 ECC 校驗(yàn)碼。

          3) 在你完成讀或者寫(xiě)一個(gè)頁(yè)后(不包含備用數(shù)據(jù)域),給 MainECCLock 位置 1(lock) 。 ECC 校驗(yàn)碼被鎖上, ECC 狀態(tài)寄存器的值將不會(huì)被改變。

          4) 清 0(Unlock) SpareECCLock(NFCONT[6]) 位來(lái)產(chǎn)生備用域的 ECC 校驗(yàn)碼。

          5) 任何時(shí)候讀或者寫(xiě)數(shù)據(jù)時(shí),備用域 ECC 模塊在寄存器 NFSECC 上產(chǎn)生 ECC 校驗(yàn)碼。

          6) 在完成讀或者寫(xiě)備用域后,給 SpareECCLock 位置 1(lock) 。 ECC 校驗(yàn)碼被鎖上, ECC 狀態(tài)寄存器的值將不會(huì)被改變。

          7) 一旦完成你就可以使用這些值來(lái)記錄到備用域或者檢測(cè)位錯(cuò)誤。

          接下來(lái)是代碼:

          NAND-FLASH.H內(nèi)容:



          #ifndef __NAND_FLASH_H__ //為了防止重復(fù)包含
          #define __NAND_FLASH_H__

          #include "lhg_def.h" //U8,U32相關(guān)的宏,也即變量類(lèi)型

          #define MAX_NAND_BLOCK 2048
          #define NAND_PAGE_SIZE 2048 //2048 blocks,1block has 64pages, each page has 2k+64 bytes
          typedef struct nand_id_info //這樣的結(jié)構(gòu)體變量保存芯片的ID信息
          {
          U8 IDm; //marker code
          U8 IDd; //device code
          U8 ID3rd;
          U8 ID4th;
          U8 ID5th;
          } nand_id_info;


          typedef struct bad_block_info //登記壞塊用的,只記錄數(shù)量,沒(méi)有記錄壞塊地址
          {
          U8 area[MAX_NAND_BLOCK];//0表示非壞塊,1表示壞塊
          U32 sum;//壞塊的總數(shù)
          } bad_block_info;


          //

          //NAND 操作指令,??從哪里來(lái)的,我看你怎么用
          #define NAND_CMD_READ_1st 0x00
          #define NAND_CMD_READ_2st 0x30
          #define NAND_CMD_RANDOM_WRITE 0x85
          #define NAND_CMD_RANDOM_READ_1st 0x05
          #define NAND_CMD_RANDOM_READ_2st 0xe0
          #define NAND_CMD_READ_CB_1st 0x00
          #define NAND_CMD_READ_CB_2st 0x35
          #define NAND_CMD_READ_ID 0x90
          #define NAND_CMD_RES 0xff
          #define NAND_CMD_WRITE_PAGE_1st 0x80
          #define NAND_CMD_WRITE_PAGE_2st 0x10
          #define NAND_CMD_BLOCK_ERASE_1st 0x60
          #define NAND_CMD_BLOCK_ERASE_2st 0xd0
          #define NAND_CMD_READ_STATUS 0x70

          //NAND 中斷向量,?這是什么意思
          #define INT_NFCON (24)

          //NFCONF HCLK=100MHZ,nandflash configuration register
          #define S3C2440_NFCONF_TACLS_init (1<<12) //設(shè)置cle ale的持續(xù)時(shí)間,NFCONF[14:12]
          #define S3C2440_NFCONF_TWRPH0_init (4<<8) //TWRPH0持續(xù)時(shí)間設(shè)置,NFCONF[10:8]
          #define S3C2440_NFCONF_TWRPH1_init (0<<4) //TWRPH1持續(xù)時(shí)間設(shè)置,NFCONF[6:4]
          #define S3C2440_NFCONF_BusWidth_init (0) //bus_width for autobooting or general access,0 for1B
          #define S3C2440_NFCONF_init() ( rNFCONF = S3C2440_NFCONF_TACLS_init | /
          S3C2440_NFCONF_TWRPH0_init | /
          S3C2440_NFCONF_TWRPH1_init | /
          S3C2440_NFCONF_BusWidth_init ) //牛逼啊這句話

          //NFCONT,nandflash control register
          #define S3C2440_NFCONT_LockTight_init (0<<13)//disable lock-tight
          #define S3C2440_NFCONT_SoftLock_init (0<<12)//disable lock
          #define S3C2440_NFCONT_EnbIllegalAccINT_init (1<<10)//illegal access interrupt enable
          #define S3C2440_NFCONT_EnbRnBINT_init (0<<9)//RnB ready not busy
          #define S3C2440_NFCONT_RnB_TransMode_init (0<<8)//detect RnB type is rising edge
          #define S3C2440_NFCONT_SpareECCLock_init (1<<6)//1 is to lock sparearea ecc generation
          #define S3C2440_NFCONT_MainECCLock_init (1<<5)//1 is to lock main area ecc generation
          #define S3C2440_NFCONT_InitECC_init (1<<4)//1 is to initialize ecc decoder and encoder
          #define S3C2440_NFCONT_Reg_nCE_init (1<<1)//force nFCE to high,namely disable chip-select
          #define S3C2440_NFCONT_MODE_init (0)//disable nandflash controller
          #define S3C2440_NFCONT_init() ( rNFCONT = S3C2440_NFCONT_LockTight_init | /
          S3C2440_NFCONT_SoftLock_init | /
          S3C2440_NFCONT_EnbIllegalAccINT_init | /
          S3C2440_NFCONT_EnbRnBINT_init | /
          S3C2440_NFCONT_RnB_TransMode_init | /
          S3C2440_NFCONT_SpareECCLock_init | /
          S3C2440_NFCONT_MainECCLock_init | /
          S3C2440_NFCONT_InitECC_init | /
          S3C2440_NFCONT_Reg_nCE_init | /
          S3C2440_NFCONT_MODE_init )

          //NFSTAT
          #define S3C2440_NFSTAT_init() ( rNFSTAT &= 0x3 )//NFSTAT 8 bits, 0x3 means nCE output high,
          //nandflash is ready to operate
          //NFESTAT0
          #define S3C2440_NFESTAT0_init() ( rNFESTAT0 = 0 )//ecc status for io0-io7,k9f1208 only io0-i07

          //NFESTAT1
          #define S3C2440_NFESTAT1_init() ( rNFESTAT1 = 0 )//ecc status for io8-io15

          //
          #define select_nand() ( rNFCONT &= ~(1<<1) )
          #define dis_select_nand() ( rNFCONT |= 1<<1 )片選信號(hào)設(shè)置不說(shuō)了啊
          #define controller_enable() ( rNFCONT |= 1 )
          #define controller_disable() ( rNFCONT &= ~1 )nandflash控制器使能與否也不說(shuō)了

          //
          extern void nand_flash_init(void);//初始化,extern意思是提供給外部上層函數(shù)要調(diào)用的入口
          extern int nand_block_erase(U32 num);//num要?jiǎng)h除的塊號(hào),一共2048個(gè)塊,這么大變量浪費(fèi)了!
          extern int nand_page_write(U32 addr,U8 *buffer,U32 size);//addr要寫(xiě)的起始頁(yè)地址,buffer要寫(xiě)的緩存,size要寫(xiě)的字節(jié)大小最大為4G,這里是針對(duì)u32說(shuō)的
          extern int nand_page_read(U32 addr,U8 *buffer,U32 size);//addr開(kāi)始頁(yè)地址,從每頁(yè)00地址開(kāi)始讀
          extern int nand_random_read(U32 paddr,U32 offset,U8 *data); //隨機(jī)讀數(shù)據(jù) paddr頁(yè)地址,offset頁(yè)內(nèi)偏移地址,每次一個(gè)字節(jié)
          extern int nand_random_write(U32 paddr,U32 offset,U8 data);//隨機(jī)寫(xiě),paddr頁(yè)地址,offset頁(yè)內(nèi)偏移地址
          extern void nand_test_bad_block(void);//測(cè)試壞塊函數(shù),并標(biāo)記在nand_bbi變量里和spare區(qū)最后一個(gè)地址(如果非0xff則為壞塊??原因是什么)


          #endif

          NAND-FLASH.c內(nèi)容:



          #include "2440addr.h"
          #include "NAND-FLASH.h"
          #include "uart.h"
          #include "lhg_def.h"
          //#include "iic_lhg.h"

          #define NAND_DEBUG 1
          #define USE_ECC 1

          nand_id_info nand_id;//定義登記芯片ID的全局變量
          bad_block_info nand_bbi;//定義來(lái)登記壞用的全局變量

          void init_nand_bbi(void)//初始化變量
          {
          U32 i;
          nand_bbi.sum=0;
          for (i=0;i nand_bbi.area[i]=0;//這里放的是塊數(shù),針對(duì)k9f1208是2048塊
          }

          void nand_mask_bad_block(U32 n)//標(biāo)志壞塊,n是壞塊的塊號(hào)
          {
          #ifdef NAND_DEBUG//宏定義的一種,尼瑪也可以寫(xiě)在這里
          Uart_Printf("NAND found and mask a bad block=%d .",n);
          #endif
          if (nand_bbi.area[n]!=1)//注意這里是對(duì)入口參數(shù)n操作的
          {
          nand_bbi.area[n]=1;
          nand_bbi.sum++;
          nand_random_write(n*64,2048+64-1,0);//每塊的第一個(gè)spare的最后一個(gè)字節(jié),標(biāo)志本塊是否為壞塊,非0xff為壞塊,頁(yè)地址計(jì)算中要看具體芯片一塊中有多少頁(yè),例如k9f1208是32頁(yè)
          }
          }

          int detect_nand_busy(void)//檢測(cè)是否忙
          {
          U32 a;
          a=0;
          while(!(rNFSTAT&(1<<2)))//也即RnB狀態(tài),0表示忙
          {
          a++;
          if (a==5000000)//等待超時(shí)
          {
          Uart_Printf("/r/n Error: Detect Nand Busy time out!!! /r/n");
          rNFSTAT |= (1<<2);//清忙標(biāo)志,1表示不忙
          return -1;//錯(cuò)誤返回-1,這個(gè)-1表示的是你他媽的nandflash一直忙,這里是有問(wèn)題的
          }
          }

          rNFSTAT |= (1<<2);//清忙標(biāo)志,沒(méi)有超時(shí),我給你正常設(shè)為清閑,返回值也沒(méi)問(wèn)題
          return 1;
          }

          void nand_reset(void)//復(fù)位
          {
          rNFCMD = NAND_CMD_RES;//?從哪里查到的NFCMD命令集合?和韋教材一樣,0xff為復(fù)位命令
          detect_nand_busy();//檢測(cè)忙,?為什么復(fù)位后檢測(cè)nandflash忙不忙呢?如果忙說(shuō)明程序出錯(cuò)在讀寫(xiě)
          }

          void control_start(void){ //開(kāi)啟
          select_nand();
          controller_enable();//也即最后兩位啟用nandflash和選中nandflash
          rNFSTAT |= (1<<2);//清忙標(biāo)志
          nand_reset();
          }

          void control_end(void) //關(guān)閉
          {
          dis_select_nand();//取消片選,關(guān)閉nandflash控制器
          controller_disable();
          }

          void ecc_main_init(void)//初始化ECC值
          {
          rNFCONT |= 1<<4;//NFCONT[4]初始化ecc編解碼器


          void ecc_main_start(void)//開(kāi)始main ECC
          {
          rNFCONT &= ~(1<<5);//unlock NFCONT[5],main area可以產(chǎn)生ecc
          }

          ecc_main_end(void)//結(jié)束main ECC
          {
          rNFCONT |= 1<<5;//unlock,main area不可以再產(chǎn)生ecc 了
          }

          void ecc_spare_start(void)//開(kāi)始spare ECC
          {
          // rNFCONT |= 1<<4; //initEcc
          rNFCONT &= ~(1<<6); //unlock,NFCONT[6]控制spare area的ecc產(chǎn)生
          }

          void ecc_spare_end(void)//結(jié)束spare ECC,同樣道理關(guān)閉ecc的產(chǎn)生
          {
          rNFCONT |= 1<<6; //unlock
          }

          void __irq nandINT(void) //中斷函數(shù)
          {
          //此處寫(xiě)處理代碼
          #ifdef NAND_DEBUG
          Uart_Printf("/r/n Nand Error... In interrupt now!!!");//只有錯(cuò)誤才會(huì)進(jìn)入中斷
          #endif
          rSRCPND |= 0x1< rINTPND |= 0x1<}


          void nand_read_id(void)//讀取芯片ID信息
          {
          control_start();//開(kāi)控制選中nandflash和開(kāi)啟nandflash控制器
          rNFCMD = NAND_CMD_READ_ID;//讀id命令為0x90,韋教材上有
          rNFADDR = 0;//nandflash address set register,不是發(fā)出4個(gè)地址序列嗎????
          //讀ID
          nand_id.IDm=(U8)rNFDATA8;//強(qiáng)制轉(zhuǎn)換為8位的,制造商
          nand_id.IDd=(U8)rNFDATA8; //設(shè)備代碼
          nand_id.ID3rd=(U8)rNFDATA8;//保留字節(jié)
          nand_id.ID4th=(U8)rNFDATA8;//多層操作代碼
          nand_id.ID5th=(U8)rNFDATA8;//??不知道是什么,反正一共5個(gè)信息數(shù)據(jù)

          #ifdef NAND_DEBUG
          Uart_Printf("/r/n Read NAND Flash ID:");
          Uart_Printf("/r/n NAND Mark code: 0x%x ",nand_id.IDm);//打印ID信息
          Uart_Printf("/r/n NAND Device code: 0x%x ",nand_id.IDd);
          Uart_Printf("/r/n NAND 3rdID code: 0x%x ",nand_id.ID3rd);
          Uart_Printf("/r/n NAND 4thID code: 0x%x ",nand_id.ID4th);
          Uart_Printf("/r/n NAND 5thID code: 0x%x ",nand_id.ID5th);
          #endif

          control_end();//關(guān)控制,取消片選和關(guān)閉nandflash控制器
          }

          int nand_block_erase(U32 num)//num要擦除的塊號(hào)
          {
          num=num*64;//表示要擦除的塊地址,這種nandflash每一個(gè)塊有64頁(yè),其他的就不一定了哈哈
          control_start();//開(kāi)控制
          nand_reset();//復(fù)位
          rNFCMD = NAND_CMD_BLOCK_ERASE_1st;//0x60命令
          rNFADDR = num&0xff;//需要發(fā)3個(gè)地址序列,這里有3個(gè),非常好!?。?br /> rNFADDR = (num>>8)&0xff;
          rNFADDR = (num>>16)&0xff;
          rNFCMD = NAND_CMD_BLOCK_ERASE_2st;//0xd0命令
          detect_nand_busy();//看看nandflash忙不忙

          rNFCMD =NAND_CMD_READ_STATUS; //讀擦出的結(jié)果狀態(tài),命令是0x70
          if (rNFDATA8&1)//如果最高位是1,下面報(bào)錯(cuò),就是說(shuō)擦除這個(gè)塊沒(méi)有成功,這個(gè)得記?。?br /> {
          #ifdef NAND_DEBUG
          Uart_Printf("/r/n Error:nand erase error... block=0x%x",num/64);
          #endif
          control_end();//關(guān)控制
          nand_mask_bad_block(num/64);//登記為壞塊
          return -1;//刪除錯(cuò)誤返回0
          }

          control_end();//關(guān)控制
          #ifdef NAND_DEBUG
          Uart_Printf("/r/n NAND block %d erase completed.",num/64);
          #endif
          return 1;
          }

          int nand_page_write(U32 addr,U8 *buffer,U32 size)

          //addr要寫(xiě)的起始頁(yè)地址,buffer要寫(xiě)的緩存,size要寫(xiě)的字節(jié)大小最大為4G

          //這樣的話addr是有格式要求的比如末尾幾個(gè)零,結(jié)果這個(gè)函數(shù)里面沒(méi)有加上所謂“對(duì)齊判斷”失敗啊?。?br />{
          U32 i,n,p,temp,ecc;
          U8 *bu;
          bu=buffer;
          temp=0;
          //我自己加上的對(duì)齊判斷,假如每頁(yè)是2kbyte的話,也可以再加上串口打印信息

          if(addr & 0xfff) {return -1;}

          //

          n=size/2048+(((size 48)==0)?0:1); //計(jì)算出要寫(xiě)的頁(yè)數(shù),小于一頁(yè)的部分當(dāng)作一頁(yè)

          for (i=0;i{
          control_start();//開(kāi)控制,選中nandflash和開(kāi)啟nandflash控制器
          nand_reset();//復(fù)位

          #ifdef USE_ECC
          ecc_main_init();
          ecc_main_start();//可以產(chǎn)生main區(qū)ECC
          #endif

          // detect_nand_busy();

          //檢測(cè)忙,這里有相當(dāng)于是復(fù)位nandflash后檢測(cè)nandflash,復(fù)位都不相信了,擦!

          //檢測(cè)了更好考慮問(wèn)題更全面
          rNFCMD = NAND_CMD_WRITE_PAGE_1st;//0x80命令,
          rNFADDR = 0; //從每頁(yè)的0地址開(kāi)始
          rNFADDR = 0; //從每頁(yè)的0地址開(kāi)始
          rNFADDR = (addr)&0xff;//???不是發(fā)送四個(gè)地址序列嗎?
          rNFADDR = (addr>>8)&0xff;
          rNFADDR = (addr>>16)&0xff;

          for (p=0;p<2048;p++)//寫(xiě)入一頁(yè)
          {
          temp=temp+1;
          if (temp>size)//這個(gè)temp并沒(méi)有在每一頁(yè)中重新置零!?。?br /> rNFDATA8 = 0xff;//多余的填寫(xiě)0xff,NFDATA是32位數(shù)據(jù)
          else
          rNFDATA8 = *(bu+p);
          }
          delay_lhg(100,100);//?草具體的延時(shí)函數(shù)在哪里
          #ifdef USE_ECC//也即宏定義里面是否啟用了ecc產(chǎn)生記錄
          ecc_main_end();//鎖定main區(qū)ecc
          ecc=rNFMECC0;//main ECC值寫(xiě)入備用區(qū)的頭0~4個(gè)地址內(nèi),NFMECCO是main aera的ecc產(chǎn)生的臨時(shí)地方

          ecc_spare_start();//開(kāi)始spare區(qū)ECC
          rNFDATA8 = ecc&0xff;//這樣來(lái)看ecc32位數(shù)據(jù),
          rNFDATA8 = (ecc>>8)&0xff;
          rNFDATA8 = (ecc>>16)&0xff;
          rNFDATA8 = (ecc>>24)&0xff;//自動(dòng)完成寫(xiě)入
          ecc_spare_end();
          delay_lhg(100,100);//
          ecc = rNFSECC;//spare ECC值寫(xiě)入備用區(qū)的5~6兩個(gè)地址內(nèi),NFSECC是spare area生成ecc的臨時(shí)地方
          rNFDATA8 = ecc&0xff;
          rNFDATA8 = (ecc>>8)&0xff;//我靠 spare area的ecc只有16位

          #endif

          bu=bu+2048;//頁(yè)增量
          addr++;//起始頁(yè)地址為何是++?

          rNFCMD = NAND_CMD_WRITE_PAGE_2st;//這個(gè)命令是ox10,意思是啟動(dòng)寫(xiě)操作
          detect_nand_busy();//檢測(cè)忙
          rNFCMD =NAND_CMD_READ_STATUS; //讀nandflash忙不忙的狀態(tài)指令,這個(gè)命令是0x70
          if (rNFDATA8&1)//???為什么出來(lái)最后一位是1則是有問(wèn)題啊?。。?!
          {
          #ifdef NAND_DEBUG
          Uart_Printf("/r/n nand write page error: page addr=0x%d",addr-1);//寫(xiě)入失敗
          #endif
          control_end();//關(guān)控制,取消選中nandflash然后關(guān)閉nandflash控制器
          nand_mask_bad_block((addr-1)/64);//登記為壞塊,我靠整個(gè)塊都是壞的!?。?br /> return -1;//寫(xiě)入錯(cuò)誤返回-1
          }
          control_end();//關(guān)控制
          }
          return 1;//成功返回1
          }

          int nand_page_read(U32 addr,U8 *buffer,U32 size)//addr開(kāi)始頁(yè)地址,從每頁(yè)00地址開(kāi)始讀
          {
          U32 i,n,p,temp,ecc;
          U8 *bu,no;
          bu=buffer;
          temp=0;

          n=size/2048+(((size 48)==0)?0:1); //計(jì)算出要讀的頁(yè)數(shù),小于一頁(yè)的部分當(dāng)作一頁(yè)

          for (i=0;i++;i {
          control_start();//開(kāi)控制,選中nandflash并且打開(kāi)nandflash控制器
          nand_reset();//復(fù)位,擦 下邊例行監(jiān)測(cè)nandflash的busy與否
          detect_nand_busy();

          #ifdef USE_ECC
          rNFESTAT0 = 0;//復(fù)位錯(cuò)誤標(biāo)志位
          ecc_main_init();
          ecc_main_start();//可以產(chǎn)生main區(qū)ECC
          #endif

          rNFCMD = NAND_CMD_READ_1st;
          rNFADDR = 0;
          rNFADDR = 0;
          rNFADDR = addr&0xff;
          rNFADDR = (addr>>8)&0xff;
          rNFADDR = (addr>>16)&0xff;//尼瑪?shù)刂沸蛄邪l(fā)送的這么混亂!??!
          rNFCMD = NAND_CMD_READ_2st;//這個(gè)命令應(yīng)該是0x50,讀取的是c區(qū)的數(shù)據(jù)
          detect_nand_busy();
          for (p=0;p<2048;p++)
          {
          temp=temp+1;
          if (temp>size)
          no=rNFDATA8;//多余的讀出來(lái)扔掉,給了一個(gè)無(wú)用的臨時(shí)變量
          else
          *(bu+p) = rNFDATA8;
          }

          #ifdef USE_ECC
          rNFESTAT0=0;//這個(gè)表示io0-io7的ecc狀態(tài)
          ecc_main_end();//鎖定main區(qū)ECC
          delay_lhg(100,100);//
          ecc_spare_start();//解鎖spare區(qū)ecc
          ecc=rNFDATA8;//從flash讀出main區(qū)ECC
          no=rNFDATA8;
          ecc |= ((U32)no)<<8;
          no=rNFDATA8;
          ecc |= ((U32)no)<<16;
          no=rNFDATA8;
          ecc |= ((U32)no)<<24;

          //這個(gè)是什么意思?。烤褪怯弥虚g變量no讓ecc存儲(chǔ)了32位的main area的ecc
          rNFMECCD0 = ((ecc&0xff00)<<8)|(ecc&0xff);//硬件檢驗(yàn)main ECC,一次檢驗(yàn)16位
          rNFMECCD1 = ((ecc&0xff000000)>>8)|((ecc&0xff0000)>>16);
          ecc_spare_end();//鎖定spare區(qū)ecc
          delay_lhg(100,100);//
          ecc=rNFDATA8;//從flash讀出spare區(qū)ECC的值
          no=rNFDATA8;
          ecc |= ((U32)no)<<8;

          rNFSECCD = ((ecc&0xff00)<<8)|(ecc&0xff);//硬件檢驗(yàn)spare ECC
          delay_lhg(100,100);//延時(shí)一會(huì)

          ecc=rNFESTAT0&0xffffff;//ecc只是臨時(shí)用一下錯(cuò)誤狀態(tài),并非ecc內(nèi)容

          if (ecc!=0)//有錯(cuò)誤
          {
          //以后再優(yōu)化
          #ifdef NAND_DEBUG
          Uart_Printf("/r/n Nand ecc check error... page addr=0x%x,NFESTAT0=0x%x ",addr,ecc);
          #endif
          nand_mask_bad_block((addr+i)/64);//登記為壞塊
          return -1;//
          }
          #endif

          bu=bu+2048;
          addr++;
          control_end();//關(guān)控制
          }

          return 1;
          }

          int nand_random_read(U32 paddr,U32 offset,U8 *data) //隨機(jī)讀數(shù)據(jù) paddr頁(yè)地址,offset頁(yè)內(nèi)偏移地址
          {
          control_start();//開(kāi)控制
          nand_reset();//復(fù)位

          rNFCMD = NAND_CMD_READ_1st;
          rNFADDR = 0;
          rNFADDR = 0;
          rNFADDR = paddr&0xff;
          rNFADDR = (paddr>>8)&0xff;
          rNFADDR = (paddr>>16)&0xff;
          rNFCMD = NAND_CMD_READ_2st;

          detect_nand_busy();
          rNFCMD = NAND_CMD_RANDOM_READ_1st;
          rNFADDR = offset&0xff; //寫(xiě)入頁(yè)內(nèi)偏移地址
          rNFADDR = (offset>>8)&0xff;
          rNFCMD = NAND_CMD_RANDOM_READ_2st;

          *data = rNFDATA8;
          control_end();
          return 1;
          }

          int nand_random_write(U32 paddr,U32 offset,U8 data)//隨機(jī)寫(xiě),paddr頁(yè)地址,offset頁(yè)內(nèi)偏移地址
          {
          control_start();//開(kāi)控制
          nand_reset();//復(fù)位

          rNFCMD = NAND_CMD_WRITE_PAGE_1st;
          rNFADDR = 0;
          rNFADDR = 0;
          rNFADDR = paddr&0xff;
          rNFADDR = (paddr>>8)&0xff;
          rNFADDR = (paddr>>16)&0xff;

          rNFCMD = NAND_CMD_RANDOM_WRITE;
          rNFADDR = offset&0xff; //寫(xiě)入頁(yè)內(nèi)偏移地址
          rNFADDR = (offset>>8)&0xff;

          rNFDATA8 = data;
          rNFCMD = NAND_CMD_WRITE_PAGE_2st;
          detect_nand_busy();//檢測(cè)忙

          rNFCMD =NAND_CMD_READ_STATUS; //讀狀態(tài)
          if (rNFDATA8&1)
          {
          #ifdef NAND_DEBUG
          Uart_Printf("/r/n Error:nand random write error... paddr=0x%x,offset=0x%x ",paddr,offset);
          #endif
          return -1;//刪除錯(cuò)誤返回0
          }

          control_end();
          return 1;//成功返回1
          }


          void nand_test_bad_block(void)//測(cè)試壞塊函數(shù),并標(biāo)記spare區(qū)最后一個(gè)地址,如果非0xff則為壞塊
          {

          U8 dest[64*2048];//一個(gè)塊的main區(qū)容量
          U8 src [64*2048];
          U32 i,k;

          #ifdef NAND_DEBUG
          Uart_Printf("/r/n test and mask bad block is begain. /r/n");
          #endif
          //
          //main區(qū)檢測(cè)
          for (i=0;i<64*2048;i++)
          {
          dest[i]=0xff;//初始化緩沖區(qū)
          src [i]=0;
          }
          //刪除所有塊
          for (i=0;i
          {
          nand_block_erase(i);
          }

          for (i=0;i
          {
          nand_page_write(i*64,src,64*2048);
          nand_page_read(i*64,dest,64*2048);//使用了ecc校驗(yàn)讀出來(lái)即可登記壞塊信息
          }

          for (i=0;i<64*2048;i++)
          {
          dest[i]=0;//初始化緩沖區(qū)
          src [i]=0xff;
          }
          //刪除所有塊
          for (i=0;i
          {
          nand_block_erase(i);
          }

          for (i=0;i
          {
          nand_page_write(i*64,src,64*2048);
          nand_page_read(i*64,dest,64*2048);//使用了ecc校驗(yàn)讀出來(lái)即可登記壞塊信息
          }

          //
          //spare區(qū)檢測(cè)
          for (i=0;i<64;i++)
          {
          dest[i]=0xff;//初始化緩沖區(qū)
          src [i]=0;
          }
          //刪除所有塊
          for (i=0;i
          {
          nand_block_erase(i);
          }
          for (i=0;i
          {
          if ( nand_bbi.area[i/64] ==1 )//如果是壞塊則跳過(guò)
          continue;

          for (k=0;k<64;k++)
          {
          nand_random_write(i,2048+k,src[k]);
          nand_random_read(i,2048+k,&dest[k]);
          if (dest[k]!=src[k])//不相等則登記為壞塊
          {
          nand_mask_bad_block(i/64);
          break;
          }
          }

          }

          for (i=0;i<64;i++)
          {
          dest[i]=0x0;//初始化緩沖區(qū)
          src [i]=0xff;
          }
          //刪除所有塊
          for (i=0;i
          {
          nand_block_erase(i);
          }
          for (i=0;i
          {
          if ( nand_bbi.area[i/64] ==1 )//如果是壞塊則跳過(guò)
          continue;

          for (k=0;k<64;k++)
          {
          nand_random_write(i,2048+k,src[k]);
          nand_random_read(i,2048+k,&dest[k]);
          if (dest[k]!=src[k])//不相等則登記為壞塊
          {
          nand_mask_bad_block(i/64);
          break;
          }
          }
          }

          #ifdef NAND_DEBUG
          Uart_Printf("/r/n test and mask bad block is over. /r/n");
          #endif
          }

          void nand_flash_init(void)//初始化
          {
          #ifdef NAND_DEBUG
          Uart_Printf("/r/nNAND FLASH init");//
          #endif

          //中斷入口地址
          pISR_NFCON = (U32)nandINT;

          //配置GPIO
          rGPGUP |= 0x7<<13; //GPG13~15關(guān)閉上位
          rGPGCON &= ~((U32)0x3f<<26);//GPG13~15為輸入

          //初始化各寄存器
          S3C2440_NFCONF_init();
          S3C2440_NFCONT_init();
          S3C2440_NFSTAT_init();
          S3C2440_NFESTAT0_init();
          S3C2440_NFESTAT1_init();

          //關(guān)于中斷
          rINTMSK &= ~(0x1< rINTMOD &= ~(0x1< rSRCPND |= 0x1< rINTPND |= 0x1<
          init_nand_bbi();//初始化全局變量
          nand_read_id();//讀ID

          nand_test_bad_block();//測(cè)試并登記壞塊
          }



          關(guān)鍵詞: arm2440nandflash函

          評(píng)論


          技術(shù)專(zhuān)區(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); })();