新闻  |   论坛  |   博客  |   在线研讨会
nand的裸板驱动---写的很规范(s3c2410) ---转载
hong60104 | 2011-09-29 14:02:31    阅读:1689   发布文章

nandflash在嵌入式设备中广泛的应用,学些nandflash的重要性不言而喻,这里分析一段实例代码,不管是编码规范还是程序的结构都是很有价值的。下边是K9F1208U0M的实例代码。
首先看nand.h文件:
 
#ifndef __NAND_Flash__
#define __NAND_Flash__
extern void InitNandCfg(void);                 //初始化K9F1208UOM NAND flash 配置
extern unsigned int ReadChipId(void);                 //读取NAND Flash的ID号
extern unsigned short ReadStatus(void);                 //读取NAND Flash的状态
extern unsigned int EraseBlock(unsigned int addr);                //NAND Flash块擦除
extern void ReadPage(unsigned int addr, unsigned char *buf);    //K9F1208U0M nand flash 的页数据读
extern void WritePage(unsigned int addr, unsigned char *buf);    //K9F1208U0M nand flash 的页数据写
extern void MarkBadBlk(unsigned int addr);            //屏蔽 K9F1208U0M nand flash 的坏块
extern int CheckBadBlk(unsigned int addr);            //检查 K9F1208U0M nand flash 的坏块
extern void InitNandFlash(void);            //K9F1208U0M nand flash 的初始化
#endif
需要详细看的是nandflash.c文件:
 
//====================================================
// 常量定义区
//====================================================
#define    EnNandFlash()    (rNFCONF |= 0x8000) //bit15=1 enable NAND flash controller
#define    DsNandFlash()    (rNFCONF &= ~0x8000) //bit15=1 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    READCMD0    0 //Read0 model command == Page addr 0~127
#define    READCMD1    1 //Read1 model command == Page addr 128~511
#define    READCMD2    0x50 //Read2 model command == Page addr 512~527
#define    ERASECMD0    0x60 //Block erase command 0
#define    ERASECMD1    0xd0 //Block erase command 1
#define    PROGCMD0    0x80 //page write command 0
#define    PROGCMD1    0x10 //page write command 1
#define    QUERYCMD    0x70 //query command
#define    RdIDCMD        0x90 //read id command

//====================================================
// 函数定义区
//====================================================
#include "NAND_Flash.h"
#include "2410addr.h"
static unsigned short NandAddr;
//等待NAND FLASH不忙
void wait_idle(void)
{
    int i;
    while(!(rNFSTAT & 0x1))
      for(i=0; i<10; i++);
}
/* 在第一次实用NAND Flash前,复位一下NAND Flash */
void reset_nand()
{
    int i=0;
    rNFCONF &= ~0x800;
        for(; i<10; i++);      
    rNFCMD = 0xff;    //reset command
    wait_idle();
}
//====================================================
// 语法格式: void InitNandCfg(void)
// 功能描述: 初始化 K9F1208U0M nand flash 配置
// 入口参数: 无
// 出口参数: 无
//====================================================

void InitNandCfg(void)
{
    //enable nand flash control, initilize ecc, chip disable,
    //基本所有的falsh都可以公用的。
    rNFCONF = (1<<15)|(1<<12)|(1<<11)|(7<<8)|(7<<4)|(7);   
}

//====================================================
// 语法格式: unsigned int ReadChipId(void)
// 功能描述: 读Nand Flash的ID号
// 入口参数: 无
// 出口参数: Nand Flash ID
//====================================================

unsigned int ReadChipId(void)
{
    unsigned int id;  
    NFChipEn();      
    WrNFCmd(RdIDCMD); 
    WrNFAddr(0); 
    wait_idle(); 
    id = RdNFDat()<<8;
    id |= RdNFDat();          
    NFChipDs();        
    return id;
}
//====================================================
// 语法格式: unsigned short ReadStatus(void)
// 功能描述: 读Nand Flash的状态
// 入口参数: 无
// 出口参数: Nand Flash 状态
//====================================================
unsigned short ReadStatus(void)
{
    unsigned short stat;   
    NFChipEn();   
    WrNFCmd(QUERYCMD);       
    stat = RdNFDat();   
    NFChipDs(); 
    return stat;
}
//====================================================
// 语法格式: unsigned int EraseBlock(unsigned int addr)
// 功能描述: Nand Flash块擦除
// 入口参数: 块地址
// 出口参数: 擦除状态 0 为成功 非0 失败
//====================================================
unsigned int EraseBlock(unsigned int addr)
{
    unsigned char stat;
    addr &= ~0x1f;      
    NFChipEn();     //使能  
    WrNFCmd(ERASECMD0);      
    WrNFAddr(addr);//擦除只针对块操作
    WrNFAddr(addr>>8);
    if(NandAddr)                         //判断Flash的型号
        WrNFAddr(addr>>16);  
    WrNFCmd(ERASECMD1); //发送擦除命令   
    wait_idle();          //等待,直到操作完成为止。  
    NFChipDs(); //失能
    return stat&1;
}
//====================================================
// 语法格式: void ReadPage(unsigned int addr, unsigned char *buf)
// 功能描述: 读取页的内容
// 入口参数: 1,页地址 2,读出的页内数据
// 出口参数: 无
//====================================================
/**** K9F1208U0M nand flash 的页数据读 ****/
void ReadPage(unsigned int addr,unsigned char *buf)//addr = page address
{
    unsigned short i;
    NFChipEn();  
    WrNFCmd(READCMD0);  
    WrNFAddr(0); 
    WrNFAddr(addr);
    WrNFAddr(addr>>8); 
    if(NandAddr)
        WrNFAddr(addr>>16);
    InitEcc(); 
    wait_idle(); 
    for(i=0; i<512; i++)
        buf[i] = RdNFDat();     
    NFChipDs();
}
//===================================================
// 语法格式:extern unsigned int WritePage(unsigned int addr, unsigned char *buf)
// 功能描述: 写页数据
// 入口参数: 1,页地址 2,写页内数据
// 出口参数: 无
//====================================================

/**** K9F1208U0M nand flash 的页数据写 ****/
void WritePage(unsigned int addr, unsigned char *buf)
{
    unsigned short i;
    unsigned char tmp[3];    
    NFChipEn();  
    WrNFCmd(PROGCMD0); 
    WrNFAddr(0); //低八位为0
    WrNFAddr(addr); //页地址
    WrNFAddr(addr>>8); // 
    if(NandAddr)
        WrNFAddr(addr>>16);
        InitEcc();   
    for(i=0; i<512; i++)
        WrNFDat(buf[i]);      
    tmp[0] = rNFECC0;//产生的3位校验码
    tmp[1] = rNFECC1;
    tmp[2] = rNFECC2;  
    WrNFDat(tmp[0]);//将校验码重新写入页
    WrNFDat(tmp[1]);
    WrNFDat(tmp[2]);      
    WrNFCmd(PROGCMD1);//正式开始写数据
    wait_idle();
    NFChipDs();
}

//====================================================
// 语法格式:extern void MarkBadBlk(unsigned int addr)
// 功能描述: 屏蔽 K9F1208U0M nand flash 的坏块
// 入口参数: 块地址
// 出口参数: 无
//====================================================

void MarkBadBlk(unsigned int addr)
{
    addr &= ~0x1f;
   
    NFChipEn();
   
    WrNFCmd(READCMD2);    //point to area c
   
    WrNFCmd(PROGCMD0);
    WrNFAddr(4);        //mark offset 4,5,6,7
    WrNFAddr(addr);
    WrNFAddr(addr>>8);
    if(NandAddr)
        WrNFAddr(addr>>16);
    WrNFDat(0);            //mark with 0
    WrNFDat(0);
    WrNFDat(0);            //mark with 0
    WrNFDat(0);
    WrNFCmd(PROGCMD1);
   
    wait_idle();
    WrNFCmd(READCMD0);    //point to area a       
    NFChipDs();
}

//====================================================
// 语法格式:int CheckBadBlk(unsigned int addr)
// 功能描述: 检查 K9F1208U0M nand flash 的坏块
// 入口参数: 块地址
// 出口参数: 是否为坏块 0 坏块 1非坏块
//====================================================
int CheckBadBlk(unsigned int addr)
{
    unsigned char dat;
   
    addr &= ~0x1f;
   
    NFChipEn();
   
    WrNFCmd(READCMD2);        //point to area c
    WrNFAddr(5);            //mark offset 4,5,6,7
    WrNFAddr(addr);
    WrNFAddr(addr>>8);
    if(NandAddr)
        WrNFAddr(addr>>16);
       
    wait_idle();
       
    dat = RdNFDat();
   
    WrNFCmd(READCMD0);    //point to area a
   
    NFChipDs();
    return (dat!=0xff);
}
//====================================================
// 语法格式:void InitNandFlash(void)
// 功能描述: K9F1208U0M nand flash 的初始化
// 入口参数: 无
// 出口参数: 无
//====================================================

static int support=0;
void InitNandFlash(void)
{   
    unsigned int i;
   
    InitNandCfg();                            //初始化配置   
    reset_nand();   
    i = ReadChipId();                        //读取NAND Flash的ID号                      
    if((i==0x9873)||(i==0xec75))   
        NandAddr = 0;
    else if(i==0xec76)
    {   
        support=1;                        //by chang
        NandAddr = 1;
    }
    else
    {   
        return;
    }
}
从上边的代码可以看出,尽管nandflash自身的操作时序非常的复杂,但在nandflash控制器的帮助下,nandflash的操作就变得非常的简单,这里只需要操作少量的寄存器就可以完成操作。首先分析代码,在驱动程序编程中,用的非常广泛的就是宏的定义,
#define    EnNandFlash()    (rNFCONF |= 0x8000) //bit15=1 enable NAND flash controller
#define    DsNandFlash()    (rNFCONF &= ~0x8000) //bit15=1 disable NAND flash controller
可以在上边看到,同样是一个操作,定义成宏之后,就可以很直观的通过宏名来识别具体要完成的操作,所以以后在写一些和硬件相关的操作与函数时,要多加使用宏定义。
 通常norflash与nandflash的区别在网上是很容易查到的,这里不重复了,这里看一些 nandflash 的ecc校验,nandflash存在两种导致数据出错的问题就是反转与坏块,坏块需要标记出来,以后不能在存入数据,而数据的反转是一种正常的现象,通常需要检测多次如果成功就认为是反转,不用标记为坏块了,通常情况下,在写数据之前需要进行坏块检测,首先关于ecc,ecc的实现在ARM中是通过硬件来完成,操作的时候只需要把经过ECC校验的结构重新写入到nandflash的相应区域就可以了。
    nandflash是串行的数据传输,而norflash是三总线结构的存储器件,所以nandflash是不能随即读写的,通常的nandflash占用的I/O口有限,数据需要通过多次发送才能完成,我们需要了解nandflash的组织模式,nandflash通过层层细化,划分为不同的小单元进行操作。在进行擦除操作时,是以block为单位进行操作的,而编程与读取操作是以page为单位进行操作的。

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
当你觉得为时已晚的时候,恰恰是最早的时候!
推荐文章
最近访客