原创 nandflash驱动分析以及与norflash的比较

2009-5-26 19:50 4757 10 10 分类: MCU/ 嵌入式

以前有一篇博文分析过norflash,现在分析下nandflash


Nand在驱动方面与nor有很大的不同,首先接口就不同,nor用的是emc接口,而nand用的是ecc接口,这样nand就复杂了很多,好在现在大部分的arm芯片都有自己的nand控制器,帮我们完成了许多的工作,下面以s<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />3c2410为例:


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;


}


<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 


这里我们回顾一下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 = RdNFDat();


 //读出块数据 256字节


      


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


    tmp[1] = rNFECC1;


    tmp[2] = rNFECC2;


      


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


    {


           se=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);//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;


    }


}

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
10
关闭 站长推荐上一条 /3 下一条