nandflash驱动分析以及与norflash的比较 (转)

Nand在驱动方面与nor有很大的不同,首先接口就不同,nor用的是emc接口,而nand用的是ecc接口,这样nand就复杂了很多,好在现在大部分的arm芯片都有自己的nand控制器,帮我们完成了许多的工作,下面以s3c2410为例:

1.       nandID

主要方法是先初始化ecc接口,然后写读ID的指令到指令寄存器,然后给eccID的地址(0),然后等待指令响应完成,读出ID

U32 ReadChipId(void)

{

       U32 id;

      

       NFChipEn();                

//bit11=0 NAND flash nFCE = L (active) 片选选中

       WrNFCmd(RdIDCMD);

       //rNFCMD = 0x90,Read ID Command    写读ID的指令到指令寄存器

       WrNFAddr(0);

       //rNFADDR = 0x00, 找到0x0地址

      

       //whether nand flash is busy?

       //rNFSTAT&1 = 1 ,busy

       //rNFSTAT&1 = 0 ,no busy

       NF_WAITRB();          //等到指令完成

      

       id  = RdNFDat()<<8;  

// Maker code(K9S1208V:0xec)  这时候读数据寄存器,读出信息

       id |= RdNFDat();   

// Devide code(K9S1208V:0x76)         

      

       NFChipDs();              

//bit11=1 NAND flash nFCE = H (inactive)  删除NFLASH

      

       return id;

}

 

这里我们回顾一下nor

int Strata_CheckID(int targetAddr)
{

//Add by HHTech
    _WR(targetAddr, 0x0090);   
    return _RD(targetAddr);                               }

nor没有寄存器的概念,直接和总线打交道,先直接给总线上的地址0写入指令(指令都是写在地址0的),然后直接在数据总线上读出数据。

 

 2.一些宏函数定义: 

#define    EnNandFlash()       (rNFCONF |= 0x8000) 

//bit15=1 enable NAND flash controller

#define    DsNandFlash()       (rNFCONF &= ~0x8000)

 //bit15=0 disable NAND flash controller

#define    InitEcc()        (rNFCONF |= 0x1000) 

 //bit12=1 initialize ECC

#define    NoEcc()                (rNFCONF &= ~0x1000)

//bit12=0 initialize ECC

#define    NFChipEn()           (rNFCONF &= ~0x800)

  //bit11=0 NAND flash nFCE = L (active)

#define    NFChipDs()           (rNFCONF |= 0x800) 

  //bit11=1 NAND flash nFCE = H (inactive)

 

#define    WrNFCmd(cmd)    (rNFCMD = (cmd))  

 //write commond to nand flash

#define    WrNFAddr(addr)    (rNFADDR = (addr))

 //write address to nand flash

#define    WrNFDat(dat) (rNFDATA = (dat)) 

//write data to nand flash

#define    RdNFDat()            (rNFDATA)    

//read data from nand flash

#define    RdNFStat()            (rNFSTAT)    

//read status from nand flash

#define    NFIsBusy()           (!(rNFSTAT&1))

//whether nand flash is busy?

#define    NFIsReady()          (rNFSTAT&1)  

 //whether nand flash is ready?

#define NF_WAITRB()    {while(!(rNFSTAT&(1<<0)));}

 

3.Nand常用指令定义:(具体对照下面程序)

#define    READCMD0   0  

#define    READCMD1   1

#define    READCMD2   0x50

#define    ERASECMD0 0x60

#define    ERASECMD1 0xd0

#define    PROGCMD0  0x80

#define    PROGCMD1  0x10

#define    NFSTATUS    0x70

#define    RdIDCMD             0x90

 

 

 

4.以下是nand的其他驱动函数

/****************************************

 ****  K9F1208U0M nand flash 的状态  ****

 ****************************************/

static U16 ReadStatus(void)         //道理同上

{

       U16 stat;

      

       NFChipEn();  

       WrNFCmd(NFSTATUS);//NFSTATUS = 0x70           

       stat = RdNFDat(); 

       NFChipDs();

      

       return stat;

}

 

 

/**********************************************

 ****  K9F1208U0M nand flash 的块擦除操作  ****

 **********************************************/

U32 EraseBlock(U32 addr) 

{

       U8 status;

       U32 i;

                    

       NFChipEn();  

       WrNFCmd(ERASECMD0);  

//ERASECMD0 = 0x60,Erase one block 1st command       删除指令

      

       WrNFAddr(NFBlcokAddr>>9&0xff);

 //删除的扇区地址,高932位,即块地址,每一个块256个字节

       WrNFAddr((NFBlcokAddr>>17)&0xff);

       WrNFAddr((NFBlcokAddr>>25)&0xff);   

                    

       WrNFCmd(ERASECMD1);

       //ERASECMD1 = 0xd0,Erase one blcok 2nd command      删除指令

      

       for(i=0;i<10;i++);

//wait tWB(100ns)

       NF_WAITRB();  

 // Wait tBERS max 3ms.  指令响应结束

       status = ReadStatus();

// Read status command 读状态

       if (status&0x1)

// Erase error  删除失败,把这个扇区当作坏块

    {    

           NFChipDs();

           MarkBadBlk(addr);

           return 0;

    }

    else

    {

           NFChipDs();;

        return 1;

    }

       NFChipDs();

}

 

 

/********************************************

 ****  K9F1208U0M nand flash 的页数据读  ****

 ********************************************/

 U32 ReadPage(U32 addr, U8 *buf)//addr = page address

{

       U16 i;

       U8 tmp[3],se[16];

       InitEcc();

       NFChipEn();

      

       WrNFCmd(READCMD0);

//READCMD0 = 0//read the first half page

       WrNFAddr(addr&0xff);    //32位地址

       WrNFAddr((addr>>9)&0xff);

       WrNFAddr((addr>>17)&0xff);

       WrNFAddr((addr>>25)&0xff);

      

       for(i=0;i<10;i++); //wait tWB(100ns)   

       NF_WAITRB();

      

       for(i=0; i<256; i++)

              buf[i] = RdNFDat();

 //读出块数据 256字节

      

       tmp[0] = rNFECC0;        //验证信息

    tmp[1] = rNFECC1;

    tmp[2] = rNFECC2;

      

       for(i=0;i<16;i++)

    {

           se[i]=RdNFDat();   // Read spare array

    }

       NFChipDs();

      

       if(tmp[0]==se[0] && tmp[1]==se[1] && tmp[2]==se[2])

 //验证成功

    {

           Uart_Printf("/n[ECC OK:%x,%x,%x]/n",se[0],se[1],se[2]);

           return 1;

    }

else                                               

 //失败,打印出错误

    {

           Uart_Printf("/n[ECC ERROR(RD):read:%x,%x,%x, reg:%x,%x,%x]/n",

                       se[0],se[1],se[2],tmp[0],tmp[1],tmp[2]);

           return 0;

    }

}

 

 

/********************************************

 ****  K9F1208U0M nand flash 的页数据读  ****

 ********************************************/

U32 WritePage(U32 addr, U8 *buf)

{

       U16 i;

       U8 status;

       U32 tmp[3];

      

       InitEcc();

      

       NFChipEn();

       WrNFCmd(0x00);write the first half page

       WrNFCmd(PROGCMD0); //PROGCMD0 = 0x80

       WrNFAddr(addr&0xff);

       WrNFAddr((addr>>9)&0xff);

       WrNFAddr((addr>>17)&0xff);

       WrNFAddr((addr>>25)&0xff);

 

       for(i=0; i<256; i++)

              WrNFDat(buf[i]);//Write one page to nand flash from buffer

             

       tmp[0] = rNFECC0;

    tmp[1] = rNFECC1;

    tmp[2] = rNFECC2;

          

       WrNFDat(tmp[0]);

       WrNFDat(tmp[1]);

       WrNFDat(tmp[2]);

          

       WrNFCmd(PROGCMD1);//PROGCMD1 = 0x10

      

       for(i=0;i<10;i++);  //tWB = 100ns.

    NF_WAITRB();    //wait tPROG 200~500us;

       status = ReadStatus();

       for(i=0;i<3;i++);  //twhr=60ns

      

       if (status&0x1) // Page write error

      { 

           NFChipDs();

           Uart_Printf("[PROGRAM_ERROR:block#=%d]/n",addr);

           MarkBadBlk(addr);

           return 0;

      }

    else

      {

           NFChipDs();

           return 1;

      }

}

 

 

5.坏区

另外,由于nand的工艺,nand非常容易产生坏的block,因此我们要进行坏块处理:

如下:

/*********************************************

 ****  屏蔽 K9F1208U0M nand flash 的坏块  ****

 *********************************************/

U32 MarkBadBlk(U32 addr)                    //标记坏块

{

       int i;

       U16 status;

       addr = addr<<5;

       NFChipEn();

      

       WrNFCmd(READCMD2);     //READCMD2=0x50

       WrNFCmd(PROGCMD0);  //PROGCMD0=0x80

      

       WrNFAddr(4);              //mark offset 4,5,6,7

       WrNFAddr(addr);

       WrNFAddr(addr>>8);

       WrNFAddr(addr>>16);

      

       WrNFDat(0);                //mark with 0

       WrNFDat(0);

       WrNFDat(0);                //mark with 0

       WrNFDat(0);

      

       WrNFCmd(PROGCMD1);  //PROGCMD1=0x10

      

       for(i=0;i<10;i++);  //tWB = 100ns.

       NF_WAITRB();             //needn't check return status

       WrNFCmd(READCMD0);     //READCMD0=0

      

       status = ReadStatus();

       for(i=0;i<3;i++);  //twhr=60ns    

        if (status&0x1) // Spare arrray write error

    {    

           NFChipDs();

           Uart_Printf("[Program error is occurred but ignored]/n");

    }

    else

    {

           NFChipDs();

    }

 

    Uart_Printf("[block #%d is marked as a bad block]/n",addr);

    return 1;

      

       NFChipDs();

}

 

 

/*********************************************

 ****  检查 K9F1208U0M nand flash 的坏块  ****

 *********************************************/

static int CheckBadBlk(U32 addr)

{

       U8 data;

       int i;

       addr = addr<<5;

      

       NFChipEn();

      

       WrNFCmd(READCMD2);     //READCMD2 = 0x50

       WrNFAddr(5);              //mark offset 4,5,6,7

       WrNFAddr(addr);

       WrNFAddr(addr>>8);

       WrNFAddr(addr>>16);

      

       for(i=0;i<10;i++);   // wait tWB(100ns) //

    NF_WAITRB();     // Wait tR(max 12us)

      

       data = RdNFDat();

    NFChipDs();

    if(data!=0xff)

    {

          Uart_Printf("[block %d has been marked as a bad block(%x)]/n",addr,data);

           return 1;

    }

    else

    {

           return 0;

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值