外设:K9F2G08 nandflash 底层读写、控制驱动程序,可随机读写

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

  Copyright (C), 2001-2011, DCN Co., Ltd.

 ******************************************************************************
  File Name     : nand.c
  Version       : Initial Draft
  Author        : oucaijun
  Created       : 2014/5/9
  Last Modified :
  Description   : K9F2G08 nandflash 底层读写、控制驱动程序
                    当前的程序可以对nand进行随机读写,随机读写的时候数据正确,但没有正确实现ecc算法。
                    当前程序可以实现对nand普通的页读写,并实现ecc算法。
                    因随机读写ecc不正确,因此不能和普通的带ecc的读写方式配套使用。
                    页内地址: 2048 = 2 ^ 11 , 使用A0-A11表示页内地址 见K9F2G08手册
  Function List :
              CheckBadBlk
              CheckNandflash
              EraseBlock
              getBlockNum
              getPageNum
              InitNandCfg
              MarkBadBlk
              MY_ReadPage
              MY_WritePage
              nandNew
              NF_Reset
              RandomRead
              RandomWrite
              ReadBlock
              ReadChipId
              ReadPage
              ReadPageAll
              ReadStatus
              WaitNFBusy
              WriteBlock
              WritePage
  History       :
  1.Date        : 2014/5/9
    Author      : ocj
    Modification: Created file

******************************************************************************/
/*----------------------------------------------*
 * routines' implementations                    *
 *----------------------------------------------*/
#include "Common.h"
#include <string.h>
#include "nand.h"
#include "nfarea.h"
/*----------------------------------------------*
 * macros                                       *
 *----------------------------------------------*/

/*----------------------------------------------*
 * external routine prototypes                  *
 *----------------------------------------------*/

/*----------------------------------------------*
 * internal routine prototypes                  *
 *----------------------------------------------*/

/*----------------------------------------------*
 * project-wide global variables                *
 *----------------------------------------------*/

/*----------------------------------------------*
 * module-wide global variables                 *
 *----------------------------------------------*/

/*----------------------------------------------*
 *external variables                            *
 *----------------------------------------------*/

/*----------------------------------------------*
 * constants                                    *
 *----------------------------------------------*/
#define NF_WAIT_RB() {while(!(rNFSTAT &(1<<0)));} //this bit is ReadOnly
#define NF_CLEAR_RB() {rNFSTAT |=(1<<2);} //清除RnB信号 //this bit is RW
#define NF_DETECT_RB() {while(!(rNFSTAT &(1<<2))) ;}


/*
R/B: When low, it indicates that a program, erase or
random read operation is in process
and returns to high state upon completion.
*/
void NF_Reset(void)
{
    NFChipEn();
    NF_CLEAR_RB();
    WrNFCmd(RESET_CMD);
    NF_DETECT_RB();
    NFChipDs();
}
/*------------------------------------------------------------/
函数名称:    InitNandCfg
功能描述:    配置flash
传    参:    无
返 回 值:    无
-------------------------------------------------------------*/
static void InitNandCfg(void)
{
    rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);//初始化时序参数
    rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
    //非锁定,屏蔽nandflash中断,初始化ECC及锁定main区和spare区ECC,使能nandflash片选及控制器
    NF_Reset();
}

/*------------------------------------------------------------/
函数名称:    WaitNFBusy
功能描述:  Read Status Register , I/O = RdNFDat();
            RdNFDat() until(I/O 6 = 1   or  R/B = 1  ) ;
            if(I/O 0 = 0 ) program/erase/ success ;
传    参:    无
返 回 值:    I/O bit0 , 表示了命令的执行状况。若为0,表示success
-------------------------------------------------------------*/
static U32 WaitNFBusy(void)    //
{
    U8 stat;

    WrNFCmd(QUERYCMD);
    do
    {
        stat = RdNFDat();
    }
    while (!(stat&0x40));
    WrNFCmd(READCMD0);
    return stat&1;    //注意0为操作成功
}

/*------------------------------------------------------------/
函数名称:    ReadChipId
功能描述:    读flash ID
传    参:    无
返 回 值:    static U32 id
-------------------------------------------------------------*/
U32 ReadChipId(void)
{
    U8 MID , PID , cyc3,cyc4,cyc5 ;
    NFChipEn();
    WrNFCmd(RdIDCMD);
    WrNFAddr(0);
    while(NFIsBusy());

    MID = RdNFDat();
    PID = RdNFDat();
    cyc3 = RdNFDat();
    cyc4 = RdNFDat();
    cyc5 = RdNFDat();
    NFChipDs();

    return (MID<<24)|(PID<<16)|(cyc3<<8)|(cyc4);
}

/*------------------------------------------------------------/
函数名称:    ReadStatus
功能描述:    读FLASH状态
传    参:    无
返 回 值:    static U16 stat
-------------------------------------------------------------*/
static U16 ReadStatus(void)
{
    U16 stat;

    NFChipEn();
    WrNFCmd(QUERYCMD);
    stat = RdNFDat();
    NFChipDs();

    return stat;

}

//CheckNandflash(int info) ret =0,没有flash或者不支持的flash。
int CheckNandflash(int info)
{
    U32 i;
    int have_nandflash ;
    InitNandCfg();
    i = ReadChipId();
    if(info)
        debugk("NAND ID is 0x%04x 
", i);

    if((i==0xecda) || (i==0xadda)) {
        have_nandflash = 1;
    }
    else if(i==0xecf1) {
        have_nandflash = 1;
    }
    else {
        have_nandflash = 0;
        debugk("unsupported nandflash id 
");
    }

    if(info)
        debugk("Nand flash status = %x
", ReadStatus());
    return have_nandflash ;
}


/*------------------------------------------------------------/
函数名称:    EraseBlock
功能描述:    擦除 FLASH
传    参:    U32 addr
返 回 值:    U32 ~stat
-------------------------------------------------------------*/
U32 EraseBlock(U32 addr)// if(  stat & 0x1 == 1),erase success
{
    U8 stat;
    addr &= ~0x3f; // page_addr 的低六位清零
    //addr(page_addr) : row_addr A12-A28   not need cloumn addr A0-A11
    //64*2048(row_addr : one nand 64*2048 pages) * 2048(cloumn_addr : one page 2048 bytes)
    NFChipEn();
    WrNFCmd(ERASECMD0);
    WrNFAddr(addr); //行地址A18~A19
    WrNFAddr(addr>>8);//行地址A20~A27
    WrNFAddr(addr>>16);//行地址A28
    WrNFCmd(ERASECMD1);
    stat = WaitNFBusy();
    NFChipDs();

    return ~stat; //最后一位等于0,success
}

/*------------------------------------------------------------/
函数名称:    ReadPage
功能描述:
传    参:    U32 addr, U8 *buf
返 回 值:    无
-------------------------------------------------------------*/
void ReadPage(U32 addr, U8 *buf)
{
    U16 i;

    NFChipEn();
    WrNFCmd(READCMD0);
    WrNFAddr(0);
    WrNFAddr(0);
    WrNFAddr(addr);
    WrNFAddr(addr>>8);
    WrNFAddr(addr>>16);
    WrNFCmd(READCMD1);
    InitEcc();
    WaitNFBusy();
    for(i=0; i<2048; i++)
        buf[i] = RdNFDat();
    NFChipDs();
}
void ReadPageAll(U32 addr, U8 *buf)
{
    U16 i;

    NFChipEn();
    WrNFCmd(READCMD0);
    WrNFAddr(0);
    WrNFAddr(0);
    WrNFAddr(addr);
    WrNFAddr(addr>>8);
    WrNFAddr(addr>>16);
    WrNFCmd(READCMD1);
    InitEcc();
    WaitNFBusy();
    for(i=0; i<2048+64; i++)
        buf[i] = RdNFDat();
    NFChipDs();
}

/*------------------------------------------------------------/
函数名称:    WritePage
功能描述:
传    参:    U32 addr, U8 *buf
返 回 值:    ret若为0xff,表示success
-------------------------------------------------------------*/
U32 WritePage(U32 addr, U8 *buf)
{
    U32 i, mecc;
    U8 stat, tmp[7];

    NFChipEn();
    WrNFCmd(PROGCMD0);
    WrNFAddr(0);
    WrNFAddr(0);
    WrNFAddr(addr);
    WrNFAddr(addr>>8);
    WrNFAddr(addr>>16);
    InitEcc(); //reset mecc and secc
    MEccUnlock();
    for(i=0; i<2048; i++)
        WrNFDat(buf[i]);
    MEccLock();
//因为K9F2G08U0A是8位IO口,因此S3C2440共产生4个字节的main区ECC码和2个字节的spare区ECC码
//在这里我们规定,在每一页的spare区的第0个地址到第3个地址存储main区ECC,第4个地址和第5个地址存储spare区ECC。
//在下次读取这一页数据的时候,同样我们也计算ECC校验码,然后与spare区中的ECC校验码比较,如果一致则说明读取的数据正确,如果不一致则不正确

//读取rNFMECC0 -- Main的ECC校验码
//for 8 bit nand flash, only use NFMECC0
    mecc = RdNFMEcc() ;
    tmp[0] = mecc&0xff;
    tmp[1] = (mecc>>8)&0xff;
    tmp[2] = (mecc>>16)&0xff;
    tmp[3] = (mecc>>24)&0xff;

    WrNFDat(0xff);//2048,坏块标志
    SEccUnlock();
    WrNFDat(tmp[0]);//ECC校验码
    WrNFDat(tmp[1]);
    WrNFDat(tmp[2]);
    WrNFDat(tmp[3]);
    SEccLock();

    WrNFCmd(PROGCMD1);
    stat = WaitNFBusy();//stat若为0,表示success
    NFChipDs();

    return ~stat;////ret若为0xff,表示success
}

// RandomWrite 随机写
// 不直接改写spare区域
// addr_in_page 0-2047
U32 RandomWrite(int page_num, int addr_in_page ,U8 *buf,int len)
{
    U8 stat ;
    U32 mecc , secc ;
    if( len+addr_in_page>2048 ){
        debugs("RandomWrite :do not allow to write spare_section directly!
");
    }
    if(buf==NULL){
        debugs("RandomWrite :wrong data pointer!
");
    }
    //cs
    NFChipEn();
    WrNFCmd(PROGCMD0);
    WrNFAddr(0);
    WrNFAddr(0);
    WrNFAddr(page_num&0xff);
    WrNFAddr((page_num>>8) &0xff);
    WrNFAddr((page_num>>16) &0xff);

    WrNFCmd(RANDOM_PROGRAMCMD); //85h
    WrNFAddr( (addr_in_page&0xff) );         //页内A0~A7
    WrNFAddr( ((addr_in_page>>8)&0x0f) );    //页内地址A8~A11
    while(len--){
        WrNFDat(*buf++);
    }
    WrNFCmd(PROGCMD1);//10
    stat = WaitNFBusy();
    //ncs
    NFChipDs();
    return ~stat;
}

//MY_WritePage 写块 ,并将ecc写入spare区域 。
//完全同 WritePage
U32 MY_WritePage(U32 addr, U8 *buf)
{
    U32 mecc ,secc ;
    int i ,ret ;
    U8 stat;
    InitEcc();          //复位ECC
    MEccUnlock();     //解锁main区的ECC
    NFChipEn();          //打开nandflash片选
   // NF_CLEAR_RB();        //清RnB信号 没有用这个判断busy而是直接读的query_nand ,没必要。

    WrNFCmd(PROGCMD0);//页写命令周期1
    //写入5个地址周期
    WrNFAddr(0x00);           //列地址A0~A7
    WrNFAddr(0x00);           //列地址A8~A11  列地址就是页内的地址,不能超过2048,要注意传入的值的有效性。
    WrNFAddr((addr) & 0xff);         //行地址A12~A19
    WrNFAddr((addr >> 8) & 0xff);    //行地址A20~A27
    WrNFAddr((addr >> 16) & 0xff);  //行地址A28
    for (i = 0; i < 2048; i++)//写入一页数据
    {
        WrNFDat( buf[i] );
    }
    MEccLock();    //锁定main区的ECC值

//读取main区的ECC校验码
//for 8 bit nand flash, only use NFMECC0
    mecc = rNFMECC0 ;
    SEccUnlock();//解锁spare区的ECC
    WrNFDat(0xff);//先写入0XFF非坏块标志到2048
    WrNFDat32(mecc);//把main区的ECC值写入到spare区的前2-5字节地址内,即第2049~2052地址
    SEccLock();//锁定spare区的ECC值

    secc = rNFSECC ;//读取spare区的ECC校验码
    WrNFDat8(secc & 0xff);//写入secc校验码到spare区第6-7个字节
    WrNFDat8((secc>>8) & 0xff);

    WrNFCmd(PROGCMD1);

    WrNFCmd(QUERYCMD);
    do {
        stat = RdNFDat();
    } while(!(stat & 0x40));

    NFChipDs();
    if (stat & 0x1) {//fail
        debugs("fail to write nand!
");
    }

    return ~(stat & 0x1); //if ok,ret = 0xff
}

/*------------------------------------------------------------/
函数名称:    ReadBlock
功能描述:
传    参:    U32 addr, U8 *buf
返 回 值:    无
-------------------------------------------------------------*/
void ReadBlock(U32 addr, U8 buf[N_PAGES_NAND_BLOCK][N_BYTES_NAND_PAGE]) //addr :pages ,64的整数倍
{
    int i;
    int start ;
    start = addr ;
    for(i=0; i<64; i++) {
        ReadPage( start+i,buf[i] );
    }
}

/*------------------------------------------------------------/
函数名称:    WriteBlock
功能描述:
传    参:    U32 addr, U8 *buf
返 回 值:    无
-------------------------------------------------------------*/
void WriteBlock(U32 addr, U8 buf[64][2048])
{
    int i  ;
    int start = addr ;

    for(i=0; i<64; i++) {
        WritePage( start+i ,buf[i] );
    }

}


int getPageNum(u32 addr ,u32 PageNum[1])
{
    PageNum[0] = addr/2048 ;
    return  PageNum[0] ;
}

int getBlockNum(u32 addr ,u32 BlockNum[1])
{
    BlockNum[0] = addr/2048/64 ;
    return  BlockNum[0] ;
}


////////////////////////////////////////////
////////////////////////////////////////////
//CheckBadBlk
//addr : pageaddr{A12--A28}
//ret == 0 : badblk
//在该块的第一页 第2048bytes查询是否为non-FFh,是则为badblk 。
int CheckBadBlk(U32 addr)
{
    U8 dat;
    addr &= ~0x3f;
    /*
    Samsung makes sure that either the 1st or 2nd page of
    everyinitial invalid block has non-FFh data
    at the column address of 2048.
    */
    NFChipEn();
    WrNFCmd(READCMD0);
    WrNFAddr(0);        //
    WrNFAddr(8);        // A11=1   该地址值为2048
    WrNFAddr(addr & 0xff);
    WrNFAddr((addr>>8) & 0xff);
    WrNFAddr((addr>>16) & 0xff);//in a page [offset == 2048] : read the 2048th bytes of page(addr) .
    WrNFCmd(READCMD1);
    WaitNFBusy();
    dat = RdNFDat();

    NFChipDs();
    if(dat!=0xff) {
        debugs("Blk % 4d is NG! page_addr=%d
" ,addr>>6 , addr );
    }
    return (dat != 0xff);
}

//MarkBadBlk 标记坏块
//addr : pageaddr{A12--A28}
//在该块的第一页 第2048bytes 写入non-FFh。
void MarkBadBlk(U32 addr)
{
    addr &= ~0x3f;
    NFChipEn();
    WrNFCmd(PROGCMD0);

    //mark offset 2048
    WrNFAddr(0);        //
    WrNFAddr(8);        // A11=1   2048
    WrNFAddr(addr & 0xff);
    WrNFAddr((addr>>8) & 0xff);
    WrNFAddr((addr>>16) & 0xff);//in a page [offset == 2048] : read the 2048th bytes of page(addr) .

    WrNFDat(0);            //mark with  0 ==  “badblk”
    WrNFCmd(PROGCMD1);
    WaitNFBusy();        //needn't check return status

    NFChipDs();
}

//MY_ReadPage
//ret ==0 ok
//ret ==1 ecc error
int MY_ReadPage(U32 addr, U8 *buf)
{
    int i ;

    U32 mecc ,secc ;
    char ch;
    InitEcc();
    MEccUnlock();

    NFChipEn();
    NF_CLEAR_RB();

    WrNFCmd(READCMD0);
    WrNFAddr(0);
    WrNFAddr(0);
    WrNFAddr(addr&0xff);
    WrNFAddr((addr>>8)&0xff);
    WrNFAddr((addr>>16)&0xff);
    WrNFCmd(READCMD1);

    NF_DETECT_RB();

    for(i=0; i<2048; i++) {
        buf[i] = RdNFDat();
    }
    MEccLock();

    SEccUnlock();
    ch = RdNFDat();//跳过0XFF坏块标志 2048
    //PREFERENCE :DATASHEET--ECC MODULE FEATURES
    //读spare区的前4个地址内容,即第 2049 - 2052地址,这4个字节为main区的ECC
    //把读取到的main区的ECC校验码放入NFMECCD0/1的相应位置内
    mecc = RdNFDat32();
    rNFMECCD0 = ((mecc&0xff00)<<8) | (mecc&0xff) ;
    rNFMECCD1 = ((mecc&0xff000000)>>8) | ((mecc&0xff0000)>>16) ;
    SEccLock();//这之前计算的secc仅仅包括bit2048 2049 2050 2051 2052 的计算结果????? 应该是吧

    secc = RdNFDat32();
    //继续读spare区的4个地址内容,即第 2052--2055地址
    //把读取到的spare区的ECC校验码放入NFSECCD的相应位置内
    rNFSECCD = ((secc&0xff00)<<8) | (secc&0xff);
    NFChipDs();

    if((rNFESTAT0&0xf)==0x0) { //查看ECC状态寄存器
        return 0 ;
    } else {
        debugs("rNFESTAT0 = %0xh 
" ,rNFESTAT0 );
        return 1 ;
    }
}

//
int RandomRead(U32 page_number, U32 addr_in_page , U8 *bufr ,int len )
{
    if( len+addr_in_page>2048+64 ){
        debugs("RandomRead error : read out of spare_section!
");
        return 1;
    }
    if(bufr==NULL){
        debugs("RandomRead error : wrong data pointer!
");
        return 1 ;
    }
    NFChipEn();                  //打开Nand Flash片选
    NF_CLEAR_RB();               //清RnB信号
    WrNFCmd(READCMD0);           //页读命令周期1
    //写入5个地址周期
    WrNFAddr(0x00);       //列地址A0~A7
    WrNFAddr(0x00);       //列地址A8~A11
    WrNFAddr((page_number) & 0xff);                //行地址A12~A19
    WrNFAddr((page_number >> 8) & 0xff);           //行地址A20~A27
    WrNFAddr((page_number >> 16) & 0xff);          //行地址A28
    WrNFCmd(READCMD1);          //页读命令周期2
    NF_DETECT_RB();             //等待RnB信号变高,即不忙
    WrNFCmd(RANDOM_READCMD0);   //随意读命令周期1
    //页内地址
    WrNFAddr( addr_in_page&0xff );         //列地址A0~A7
    WrNFAddr( (addr_in_page>>8)&0x0f );    //列地址A8~A11
    WrNFCmd(RANDOM_READCMD1);           //随意读命令周期2
    while(len--){
        *bufr++ = RdNFDat();                   //读取数据
    }
    NFChipDs();
    return 0 ;
}


//http://www.cnblogs.com/idle_man/archive/2010/12/23/1915303.html
#define getnum(i) {
            mygetstring(string) ;
            i = myatoi(string ) ;
        }
void nandNew(void)
{
    int ret , n ,i , j ,k;
    U32 nID;
    U8 MID , PID , cyc3,cyc4,cyc5 ;
    char dat ;
    char ch ;
    U8 uch;
    char string[1000] = {0};
    char bufw[2048] = {1 , 1, 1};
    char bufr[2048+64] = {0};
    memset(bufw , 0xaa , 2048);

    while(1) {

        debugs("
------------------------------------------------
");
        debugs("nand menu
");
        debugs("input num to select:
");
        debugs("now will operate block %d,its addr is %x
",AppParaBpageS,AppParaBaseNF);//page num = 34816
        debugs("0 sysHardwareReset
");
        debugs("1 nand EraseBlock
");
        debugs("2 nand MY_WritePage caculate ecc
");
        debugs("3 nand ReadPageAll
");
        debugs("4 nand my_cop
");
        debugs("5 nand CheckBadBlk
");
        debugs("6 nand MY_ReadPage check ecc
");
        debugs("------------------------------------------------
");
        ch = mygetc();
        switch ( ch - '0' )
        {
        case 0 :
            sysHardwareReset();
            break;
        case 1 :
            ret = EraseBlock(AppParaBpageS );
            if(ret&0x1 ==1 ) {
                debugs("EraseBlock ok!
");
            } else {
                debugs("EraseBlock fail!
");
            }
            break;
        case 2 :
            ret = MY_WritePage(AppParaBpageS,  bufw);
            if(ret&0x1 ==1 ) {
                debugs("WritePage ok!
");
            } else {
                debugs("WritePage fail!
");
            }
            break;
        case 3:
            if(1){
                int j ;
                int i = 34816 ;
                char buf[2047] = {4,5,6,7,8,9,10,11,12};
                buf[2044] = 11;
                buf[2045] = 12;
                buf[2046] = 13;
                memset(bufr, 0 , sizeof(bufr));
                ReadPageAll(i , bufr);
                ret = memcmp(buf , bufr+1 , 2047);
                debugs("ret of memcmp %x
" , ret);
                arryprintfs("ReadPage+0" ,bufr ,2048 );
                arryprintfs("ReadPage+2048" ,bufr+2048 ,64 );
            }
            break;
        case 4:
            if(1){
                int time = 0;
                int nPage = 34816 , nAddr = 1;
                char rbufw[10] = {1, 2, 3 ,4 ,5 ,6 ,7 ,8 ,9 ,10};
                ret = RandomWrite(nPage , nAddr, rbufw , 10);
                if(ret&0x1 ==1 ) {
                    debugs("WritePage ok!
");
                } else {
                    debugs("WritePage fail!
");
                }

                for(time = 0 ; time<10 + 7; time++){
                    ret = 0x11;
                    ret = RandomRead(nPage ,nAddr , bufr , 2048+63);
                    debugs("RamdomRead(page %d, in_page_addr%d ) ,ret = 0x%x
" ,nPage , nAddr, ret);
                    arryprintfs("RamdomRead bufr" ,bufr ,2048+63 ) ;
                    nAddr++;
                }

            }
            /*
            ----------------prints---------------------------
            WritePage ok!
            RamdomRead(page 34816, in_page_addr1 ) ,uch = 0x1
            RamdomRead(page 34816, in_page_addr2 ) ,uch = 0x2
            RamdomRead(page 34816, in_page_addr3 ) ,uch = 0x3
            RamdomRead(page 34816, in_page_addr4 ) ,uch = 0x4
            RamdomRead(page 34816, in_page_addr5 ) ,uch = 0x5
            RamdomRead(page 34816, in_page_addr6 ) ,uch = 0x6
            RamdomRead(page 34816, in_page_addr7 ) ,uch = 0x7
            RamdomRead(page 34816, in_page_addr8 ) ,uch = 0x8
            RamdomRead(page 34816, in_page_addr9 ) ,uch = 0x9
            RamdomRead(page 34816, in_page_addr10 ) ,uch = 0xa
            ----------------prints---------------------------
            */
            break;
        case 5: //CheckBadBlk from blk0~blk2047
            for(ret=0 ; ret<2047; ret++) {
                CheckBadBlk(ret<<6); //ret<<6 : page_addr
            }
            break;
        case 6: //
            if(1){
                memset(bufr, 0 , sizeof(bufr));
                ret = MY_ReadPage(34816, bufr);
                debugs("MY_ReadPage ret==%d
" ,  ret);
                arryprintfs("ReadPage+0" ,bufr ,2048 );
            }
            break;

        case 7: //
            if(1){
              T_ecc() ;
            }
            break;
        }
    }
}
#ifndef _NAND_H_
#define _NAND_H_

#include "common.h"

#define N_BYTES_NAND_PAGE 2048
#define N_PAGES_NAND_BLOCK 64
#define N_BYTES_NAND_BLOCK (N_PAGES_NAND_BLOCK*N_BYTES_NAND_PAGE)

#define    EnNandFlash()    (rNFCONT |= 1)
#define    DsNandFlash()    (rNFCONT &= ~1)
#define    NFChipEn()        (rNFCONT &= ~(1<<1))
#define    NFChipDs()        (rNFCONT |= (1<<1))
#define    InitEcc()        (rNFCONT |= (1<<4))
#define    MEccUnlock()    (rNFCONT &= ~(1<<5))
#define    MEccLock()        (rNFCONT |= (1<<5))
#define    SEccUnlock()    (rNFCONT &= ~(1<<6))
#define    SEccLock()        (rNFCONT |= (1<<6))

#define    WrNFDat8(dat)    (rNFDATA8 = (dat))
#define    WrNFDat32(dat)    (rNFDATA = (dat))
#define    RdNFDat8()        (rNFDATA8)    //byte access
#define    RdNFDat32()        (rNFDATA)    //word access

#define    WrNFCmd(cmd)    (rNFCMD = (cmd))
#define    WrNFAddr(addr)    (rNFADDR = (addr))
#define    WrNFDat(dat)    WrNFDat8(dat)
#define    RdNFDat()        RdNFDat8()    //for 8 bit nand flash, use byte access

#define    RdNFMEcc()        (rNFMECC0)    //for 8 bit nand flash, only use NFMECC0
#define    RdNFSEcc()        (rNFSECC)    //for 8 bit nand flash, only use low 16 bits

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

#define    READCMD0    0
#define    READCMD1    0x30
#define    ERASECMD0    0x60
#define    ERASECMD1    0xd0
#define    PROGCMD0    0x80
#define    PROGCMD1    0x10
#define    QUERYCMD    0x70
#define    RdIDCMD        0x90

#define RESET_CMD   0xff
#define RANDOM_READCMD0 0x05
#define RANDOM_READCMD1 0xe0
#define RANDOM_PROGRAMCMD 0x85

#define TACLS        1//7    // 1-clk(0ns)
#define TWRPH0        4//7    // 3-clk(25ns)
#define TWRPH1        1//7    // 1-clk(10ns)  //TACLS+TWRPH0+TWRPH1>=50ns

//func
extern void ReadBlock(U32 addr, U8 buf[64][2048]) ; //pgaddr
extern U32  EraseBlock(U32 addr) ;                  //pgaddr
extern void WriteBlock(U32 addr, U8 buf[64][2048]); //pgaddr
extern void ReadPage(U32 addr, U8 *buf);            //pgaddr
extern U32  WritePage(U32 addr, U8 *buf);           //pgaddr
extern int getBlockNum(u32 addr ,u32 BlockNum[1]);  //0x_addr
extern int getPageNum(u32 addr ,u32 PageNum[1]);    //0x_addr
extern U32 ReadChipId(void);
extern int CheckNandflash(int info);
#endif
原文地址:https://www.cnblogs.com/mylinux/p/3994764.html