×
单片机 > 单片机程序设计 > 详情

arm2440的nandflash相关函数

发布时间:2020-08-27 发布时间:
|
K9F2G08U0A nand flash 的容量为256M byte,其内部有2048块,每块有64页,每页有2K+64字节,其中每页会分为main区(主域)和spare区(备用域),main区一般用来存入主要数据,spare一般用来存放ECC校验码。

 

下面几点是编程时需要注意的:

1.NAND FLASH芯片手册里说的column是指页内地址,row是指页地址,page也是指页;

2.删除时是以块为单位的,但是删除块时写的是row地址,自动会删除row所在的块;

3.读写方式有页读写,或随机读写,所谓的随机读写就是可以在页内的任一地方读写一个字节;

4.ECC校验码分为main区的ECC和spare区的ECC,它们一般都会存放在64字节的spare区内,下面是翻译2440手册的关于ECC编程的内容:

       ECC 编程向导

      1)       在软件模式, ECC 模块会为全部读 / 写数据产生 ECC 检验码。所以你需要在读或者写数据前给 InitECC(NFCONT[4]) 位写 1 和给 MainECCLock(NFCONT[5]) 位写 0(Unlock) 来复位 ECC 值。

MainECCLock(NFCONT[5]) 和 SpareECCLock(NFCONT[6] 控制 ECC 校验码是否产生。

      2)       任何时候读或者写数据时, ECC 模块在 NFMECC0/1 上产生 ECC 校验码。

      3)       在你完成读或者写一个页后(不包含备用数据域),给 MainECCLock 位置 1(lock) 。 ECC 校验码被锁上, ECC 状态寄存器的值将不会被改变。

      4)      清 0(Unlock) SpareECCLock(NFCONT[6]) 位来产生备用域的 ECC 校验码。

      5)      任何时候读或者写数据时,备用域 ECC 模块在寄存器 NFSECC 上产生 ECC 校验码。

      6)      在完成读或者写备用域后,给 SpareECCLock 位置 1(lock) 。 ECC 校验码被锁上, ECC 状态寄存器的值将不会被改变。

      7)       一旦完成你就可以使用这些值来记录到备用域或者检测位错误。

 

 

接下来是代码:

  NAND-FLASH.H内容:

 

#ifndef __NAND_FLASH_H__ //为了防止重复包含
#define __NAND_FLASH_H__

#include "lhg_def.h" //U8,U32相关的宏,也即变量类型

#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 //这样的结构体变量保存芯片的ID信息
{
 U8 IDm; //marker code
 U8 IDd; //device code
 U8 ID3rd;
 U8 ID4th;
 U8 ID5th;
} nand_id_info;


typedef struct bad_block_info //登记坏块用的,只记录数量,没有记录坏块地址
{
  U8 area[MAX_NAND_BLOCK];//0表示非坏块,1表示坏块
  U32 sum;//坏块的总数
} bad_block_info;


//

//NAND 操作指令,??从哪里来的,我看你怎么用
#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) //设置cle ale的持续时间,NFCONF[14:12]
#define S3C2440_NFCONF_TWRPH0_init (4<<8) //TWRPH0持续时间设置,NFCONF[10:8]
#define S3C2440_NFCONF_TWRPH1_init (0<<4) //TWRPH1持续时间设置,NFCONF[6:4]
#define S3C2440_NFCONF_BusWidth_init (0)  //bus_width for autobooting or general access,0 for 1B 
#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 spare area 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 )片选信号设置不说了啊
#define controller_enable() ( rNFCONT |= 1 )
#define controller_disable() ( rNFCONT &= ~1 )nandflash控制器使能与否也不说了

//
extern void nand_flash_init(void);//初始化,extern意思是提供给外部上层函数要调用的入口
extern int nand_block_erase(U32 num);//num要删除的块号,一共2048个块,这么大变量浪费了!
extern int nand_page_write(U32 addr,U8 *buffer,U32 size);//addr要写的起始页地址,buffer要写的缓存,size要写的字节大小最大为4G,这里是针对u32说的
extern int nand_page_read(U32 addr,U8 *buffer,U32 size);//addr开始页地址,从每页00地址开始读
extern int nand_random_read(U32 paddr,U32 offset,U8 *data); //随机读数据 paddr页地址,offset页内偏移地址,每次一个字节
extern int nand_random_write(U32 paddr,U32 offset,U8 data);//随机写,paddr页地址,offset页内偏移地址
extern void nand_test_bad_block(void);//测试坏块函数,并标记在nand_bbi变量里和spare区最后一个地址(如果非0xff则为坏块??原因是什么)


#endif

 

 

 

    NAND-FLASH.c内容:

 



#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;//定义来登记坏用的全局变量

void init_nand_bbi(void)//初始化变量
{
  U32 i;
  nand_bbi.sum=0;
  for (i=0;i    nand_bbi.area[i]=0;//这里放的是块数,针对k9f1208是2048块
}

void nand_mask_bad_block(U32 n)//标志坏块,n是坏块的块号
{
 #ifdef NAND_DEBUG//宏定义的一种,尼玛也可以写在这里
 Uart_Printf("NAND found and mask a bad block=%d .",n);
 #endif
 if (nand_bbi.area[n]!=1)//注意这里是对入口参数n操作的
 {
  nand_bbi.area[n]=1;
  nand_bbi.sum++;
  nand_random_write(n*64,2048+64-1,0);//每块的第一个spare的最后一个字节,标志本块是否为坏块,非0xff为坏块,页地址计算中要看具体芯片一块中有多少页,例如k9f1208是32页
 }
}

int detect_nand_busy(void)//检测是否忙
{
  U32 a;
  a=0;
  while(!(rNFSTAT&(1<<2)))//也即RnB状态,0表示忙
  {
   a++;
   if (a==5000000)//等待超时
   {
    Uart_Printf("/r/n Error: Detect Nand Busy time out!!! /r/n");
    rNFSTAT |= (1<<2);//清忙标志,1表示不忙
    return -1;//错误返回-1,这个-1表示的是你他妈的nandflash一直忙,这里是有问题的
   }
  }
 
  rNFSTAT |= (1<<2);//清忙标志,没有超时,我给你正常设为清闲,返回值也没问题
  return 1;
}

void nand_reset(void)//复位
{
  rNFCMD  = NAND_CMD_RES;//?从哪里查到的NFCMD命令集合?和韦教材一样,0xff为复位命令
  detect_nand_busy();//检测忙,?为什么复位后检测nandflash忙不忙呢?如果忙说明程序出错在读写
}

void control_start(void){ //开启
 select_nand();
 controller_enable();//也即最后两位启用nandflash和选中nandflash
 rNFSTAT |= (1<<2);//清忙标志
 nand_reset();
}

void control_end(void) //关闭
{
 dis_select_nand();//取消片选,关闭nandflash控制器
 controller_disable();
}
  
void ecc_main_init(void)//初始化ECC值
{
 rNFCONT |= 1<<4;//NFCONT[4]初始化ecc编解码器

                                                           
void ecc_main_start(void)//开始main ECC
{
 rNFCONT &= ~(1<<5);//unlock NFCONT[5],main area可以产生ecc
}

ecc_main_end(void)//结束main ECC
{
 rNFCONT |= 1<<5;//unlock,main area不可以再产生ecc 了
}

void ecc_spare_start(void)//开始spare ECC
{
// rNFCONT |= 1<<4; //initEcc
 rNFCONT &= ~(1<<6); //unlock,NFCONT[6]控制spare area的ecc产生
}

void ecc_spare_end(void)//结束spare ECC,同样道理关闭ecc的产生
{
 rNFCONT |= 1<<6; //unlock
}

void __irq nandINT(void) //中断函数
{
  //此处写处理代码
  #ifdef NAND_DEBUG
  Uart_Printf("/r/n Nand Error... In interrupt now!!!");//只有错误才会进入中断
  #endif
  rSRCPND |= 0x1<   rINTPND |= 0x1< }


void nand_read_id(void)//读取芯片ID信息
{
 control_start();//开控制选中nandflash和开启nandflash控制器
 rNFCMD  = NAND_CMD_READ_ID;//读id命令为0x90,韦教材上有
 rNFADDR = 0;//nandflash address set register,不是发出4个地址序列吗????
 //读ID
 nand_id.IDm=(U8)rNFDATA8;//强制转换为8位的,制造商
 nand_id.IDd=(U8)rNFDATA8; //设备代码
 nand_id.ID3rd=(U8)rNFDATA8;//保留字节
 nand_id.ID4th=(U8)rNFDATA8;//多层操作代码
 nand_id.ID5th=(U8)rNFDATA8;//??不知道是什么,反正一共5个信息数据
 
 #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();//关控制,取消片选和关闭nandflash控制器
}

int nand_block_erase(U32 num)//num要擦除的块号
 
    num=num*64;//表示要擦除的块地址,这种nandflash每一个块有64页,其他的就不一定了哈哈
    control_start();//开控制
    nand_reset();//复位
    rNFCMD  = NAND_CMD_BLOCK_ERASE_1st;//0x60命令
    rNFADDR = num&0xff;//需要发3个地址序列,这里有3个,非常好!!!
    rNFADDR = (num>>8)&0xff;
    rNFADDR = (num>>16)&0xff;
    rNFCMD  = NAND_CMD_BLOCK_ERASE_2st;//0xd0命令
    detect_nand_busy();//看看nandflash忙不忙
   
    rNFCMD =NAND_CMD_READ_STATUS; //读擦出的结果状态,命令是0x70
    if (rNFDATA8&1)//如果最高位是1,下面报错,就是说擦除这个块没有成功,这个得记住!
    {
     #ifdef NAND_DEBUG
     Uart_Printf("/r/n Error:nand erase error... block=0x%x",num/64);
     #endif
     control_end();//关控制
     nand_mask_bad_block(num/64);//登记为坏块
     return -1;//删除错误返回0
    }
   
    control_end();//关控制
    #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要写的起始页地址,buffer要写的缓存,size要写的字节大小最大为4G

//这样的话addr是有格式要求的比如末尾几个零,结果这个函数里面没有加上所谓“对齐判断”失败啊!!
{
 U32 i,n,p,temp,ecc;
 U8 *bu;
 bu=buffer;
 temp=0;
  //我自己加上的对齐判断,假如每页是2kbyte的话,也可以再加上串口打印信息

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

  //

  n=size/2048+(((size 48)==0)?0:1); //计算出要写的页数,小于一页的部分当作一页
 
 for (i=0;i  
    control_start();//开控制,选中nandflash和开启nandflash控制器
    nand_reset();//复位
   
   #ifdef USE_ECC
    ecc_main_init();
    ecc_main_start();//可以产生main区ECC
   #endif
  
  //  detect_nand_busy();

//检测忙,这里有相当于是复位nandflash后检测nandflash,复位都不相信了,擦!

//检测了更好考虑问题更全面
    rNFCMD  = NAND_CMD_WRITE_PAGE_1st;//0x80命令,
    rNFADDR = 0; //从每页的0地址开始
    rNFADDR = 0; //从每页的0地址开始
    rNFADDR = (addr)&0xff;//???不是发送四个地址序列吗?
    rNFADDR = (addr>>8)&0xff;
    rNFADDR = (addr>>16)&0xff;
   
  for (p=0;p<2048;p++)//写入一页
  {
    temp=temp+1;
    if (temp>size)//这个temp并没有在每一页中重新置零!!!
     rNFDATA8 = 0xff;//多余的填写0xff,NFDATA是32位数据
    else
     rNFDATA8 = *(bu+p);
  }
   delay_lhg(100,100);//?草具体的延时函数在哪里
  #ifdef USE_ECC//也即宏定义里面是否启用了ecc产生记录
   ecc_main_end();//锁定main区ecc
   ecc=rNFMECC0;//main ECC值写入备用区的头0~4个地址内,NFMECCO是main aera的ecc产生的临时地方
  
   ecc_spare_start();//开始spare区ECC
   rNFDATA8 = ecc&0xff;//这样来看ecc32位数据,
   rNFDATA8 = (ecc>>8)&0xff;
   rNFDATA8 = (ecc>>16)&0xff;
   rNFDATA8 = (ecc>>24)&0xff;//自动完成写入
   ecc_spare_end();
   delay_lhg(100,100);//
   ecc = rNFSECC;//spare ECC值写入备用区的5~6两个地址内,NFSECC是spare area生成ecc的临时地方
   rNFDATA8 = ecc&0xff;
   rNFDATA8 = (ecc>>8)&0xff;//我靠 spare area的ecc只有16位
  
  #endif
  
   bu=bu+2048;//页增量
   addr++;//起始页地址为何是++?
  
   rNFCMD  = NAND_CMD_WRITE_PAGE_2st;//这个命令是ox10,意思是启动写操作
   detect_nand_busy();//检测忙
   rNFCMD =NAND_CMD_READ_STATUS; //读nandflash忙不忙的状态指令,这个命令是0x70
   if (rNFDATA8&1)//???为什么出来最后一位是1则是有问题啊!!!!
   {
    #ifdef NAND_DEBUG
    Uart_Printf("/r/n nand write page error: page addr=0x%d",addr-1);//写入失败
    #endif
    control_end();//关控制,取消选中nandflash然后关闭nandflash控制器
    nand_mask_bad_block((addr-1)/64);//登记为坏块,我靠整个块都是坏的!!!
    return -1;//写入错误返回-1
   }
   control_end();//关控制
 }
   return 1;//成功返回1
}

int nand_page_read(U32 addr,U8 *buffer,U32 size)//addr开始页地址,从每页00地址开始读
 
    U32 i,n,p,temp,ecc;
    U8 *bu,no;
    bu=buffer;
    temp=0;
   
    n=size/2048+(((size 48)==0)?0:1); //计算出要读的页数,小于一页的部分当作一页
 
    for (i=0;i++;i     {
     control_start();//开控制,选中nandflash并且打开nandflash控制器
     nand_reset();//复位,擦 下边例行监测nandflash的busy与否
     detect_nand_busy();

     #ifdef USE_ECC
      rNFESTAT0 = 0;//复位错误标志位
      ecc_main_init();
      ecc_main_start();//可以产生main区ECC
     #endif
      
     rNFCMD  = NAND_CMD_READ_1st;
     rNFADDR = 0;
     rNFADDR = 0;
     rNFADDR = addr&0xff;
     rNFADDR = (addr>>8)&0xff;
     rNFADDR = (addr>>16)&0xff;//尼玛地址序列发送的这么混乱!!!
     rNFCMD  = NAND_CMD_READ_2st;//这个命令应该是0x50,读取的是c区的数据
     detect_nand_busy();
     for (p=0;p<2048;p++)
     {
       temp=temp+1;
       if (temp>size)
       no=rNFDATA8;//多余的读出来扔掉,给了一个无用的临时变量
       else
       *(bu+p) = rNFDATA8;
     }
    
     #ifdef USE_ECC
     rNFESTAT0=0;//这个表示io0-io7的ecc状态
      ecc_main_end();//锁定main区ECC
      delay_lhg(100,100);//
      ecc_spare_start();//解锁spare区ecc
      ecc=rNFDATA8;//从flash读出main区ECC
      no=rNFDATA8;
      ecc |= ((U32)no)<<8;
      no=rNFDATA8;
      ecc |= ((U32)no)<<16;
      no=rNFDATA8;
      ecc |= ((U32)no)<<24;

//这个是什么意思啊?就是用中间变量no让ecc存储了32位的main area的ecc
      rNFMECCD0 = ((ecc&0xff00)<<8)|(ecc&0xff);//硬件检验main ECC,一次检验16位  
      rNFMECCD1 = ((ecc&0xff000000)>>8)|((ecc&0xff0000)>>16); 
      ecc_spare_end();//锁定spare区ecc
      delay_lhg(100,100);//
      ecc=rNFDATA8;//从flash读出spare区ECC的值
      no=rNFDATA8;
      ecc |= ((U32)no)<<8;
    
      rNFSECCD = ((ecc&0xff00)<<8)|(ecc&0xff);//硬件检验spare ECC 
      delay_lhg(100,100);//延时一会

      ecc=rNFESTAT0&0xffffff;//ecc只是临时用一下错误状态,并非ecc内容
    
     if (ecc!=0)//有错误
     {
      //以后再优化
      #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();//关控制
    }
   
    return 1;
}

int nand_random_read(U32 paddr,U32 offset,U8 *data) //随机读数据 paddr页地址,offset页内偏移地址
{
   control_start();//开控制
   nand_reset();//复位
  
   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; //写入页内偏移地址
   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)//随机写,paddr页地址,offset页内偏移地址
{
   control_start();//开控制
   nand_reset();//复位
  
   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; //写入页内偏移地址
   rNFADDR = (offset>>8)&0xff;
  
   rNFDATA8 = data;
   rNFCMD  = NAND_CMD_WRITE_PAGE_2st;
   detect_nand_busy();//检测忙
  
   rNFCMD =NAND_CMD_READ_STATUS; //读状态
    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;//删除错误返回0
    }
   
    control_end();
    return 1;//成功返回1
}


void nand_test_bad_block(void)//测试坏块函数,并标记spare区最后一个地址,如果非0xff则为坏块
{
 
 U8 dest[64*2048];//一个块的main区容量
 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区检测
 for (i=0;i<64*2048;i++)
 {
  dest[i]=0xff;//初始化缓冲区
  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校验读出来即可登记坏块信息
 }

 for (i=0;i<64*2048;i++)
 {
  dest[i]=0;//初始化缓冲区
  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校验读出来即可登记坏块信息
 }
  
 //
 //spare区检测
 for (i=0;i<64;i++)
 {
  dest[i]=0xff;//初始化缓冲区
  src [i]=0;
 }
 //删除所有块
 for (i=0;i
 {
  nand_block_erase(i);
 }
  for (i=0;i
 {
   if ( nand_bbi.area[i/64] ==1 )//如果是坏块则跳过
   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;//初始化缓冲区
  src [i]=0xff;
 }
 //删除所有块
 for (i=0;i
 {
  nand_block_erase(i);
 }
  for (i=0;i
 {
   if ( nand_bbi.area[i/64] ==1 )//如果是坏块则跳过
   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关闭上位
  rGPGCON &= ~((U32)0x3f<<26);//GPG13~15为输入
 
  //初始化各寄存器
  S3C2440_NFCONF_init();
  S3C2440_NFCONT_init();
  S3C2440_NFSTAT_init();
  S3C2440_NFESTAT0_init();
  S3C2440_NFESTAT1_init();
 
  //关于中断
  rINTMSK &= ~(0x1<   rINTMOD &= ~(0x1<   rSRCPND |= 0x1<   rINTPND |= 0x1<  
  init_nand_bbi();//初始化全局变量
  nand_read_id();//读ID

  nand_test_bad_block();//测试并登记坏块
}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32中断向量表的位置.重定向