| 
 
| 本帖最后由 群龙舞十方 于 2010-6-8 09:18 编辑 
 /**********************按键实验*********************************/
 // 公司名称 :飞凌嵌入式技术有限公司
 // 描    述 :nandflash
 // 版    权 :飞凌嵌入式技术有限公司
 // 网    址 :www.witech.com.cn
 /***************************************************************/
 本文转引自 飞凌嵌入式 ARM学习专区 感谢作者无私奉献!
 /*
 本实验接口说明
 */
 #include "include.h"
 /*-----------------------函数声明----------------------------*/
 void InitNandFlash(int info);
 void cpy_bpage(void);
 void add_bpage(unsigned int seq);
 extern void Uart_Printf(char *fmt,...);
 extern void Uart_Init(int baud);
 extern void Uart_Select(int ch);
 /*------------------------------------------------------------/
 函数名称:        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);
 //
 }
 /*------------------------------------------------------------/
 函数名称:        WaitNFBusy
 功能描述:
 传    参:        无
 返 回 值:        static U32 stat&1
 -------------------------------------------------------------*/
 static U32 WaitNFBusy(void)        // 等待nand flash 的操作结束
 {
 U8 stat;                                //因为nansh flash数据通道只有8bit
 
 WrNFCmd(QUERYCMD);                //QUERYCMD=0X70,将0x70写入NFCMD
 //查看nand flash芯片的资料中的Command Sets
 //0x70表示读nand flash的状态
 do
 {
 stat = RdNFDat();        //上面命令是读nandflash的状态,因此RdNFDat获得的是nandflash的状态。
 }
 while (!(stat&0x40));        //[6] busy:0  ready:1
 WrNFCmd(READCMD0);                //READCMD0=0
 return stat&1;    //注意0为操作成功.见datasheet34页表。
 }
 /*------------------------------------------------------------/
 函数名称:        ReadChipId
 功能描述:        读flash ID
 传    参:        无
 返 回 值:        static U32 id
 -------------------------------------------------------------*/
 // 读ID过程的时序图在K9F1G08U0A的datasheet中,第28和35页//
 static U32 ReadChipId(void)
 {
 U32 id,k;
 
 NFChipEn();        //选中nandflash
 WrNFCmd(RdIDCMD);//读ID命令
 WrNFAddr(0);        //写入00h(根据datasheet)
 while(NFIsBusy());        //等待前一步完成
 id  = RdNFDat()<<8;        //define中规定:RdNFDat8(); for 8 bit nand flash,use byt access
 for(k=0;k<500;k++);        //
 id |= RdNFDat();        //从运行结果ID:ecda来看,可能是这边程序有点问题(ID指什么不明确)
 NFChipDs();
 
 return id;
 }
 /*------------------------------------------------------------/
 函数名称:        ReadStatus
 功能描述:        读FLASH状态
 传    参:        无
 返 回 值:        static U16 stat
 -------------------------------------------------------------*/
 static U16 ReadStatus(void)
 {
 U16 stat;
 
 NFChipEn();
 WrNFCmd(QUERYCMD);
 stat = RdNFDat();
 NFChipDs();
 
 return stat;
 }
 /*------------------------------------------------------------/
 函数名称:        EraseBlock
 功能描述:        擦除 FLASH
 传    参:        U32 addr
 返 回 值:        U32 ~stat
 -------------------------------------------------------------*/
 //         地址输入(两个周期) datasheet第27页       //
 U32 EraseBlock(U32 addr)
 {
 U8 stat;
 addr &= ~0x3f;                        //addr=0000 0001 1000 0000
 
 NFChipEn();
 WrNFCmd(ERASECMD0);                //ERASECMD0=0X60
 WrNFAddr(addr);                        //cycle1:8bit address=1000 0000
 WrNFAddr(addr>>8);                //cycle2:8bit address=0000 0001
 WrNFCmd(ERASECMD1);                //ERASE confirm cmd
 stat = WaitNFBusy();        //等待擦除完成
 NFChipDs();
 
 return ~stat;
 }
 /*------------------------------------------------------------/
 函数名称:        ReadPage
 功能描述:
 传    参:        U32 addr, U8 *buf
 返 回 值:        无
 -------------------------------------------------------------*/
 //                读取block6中的page25   参考datasheet30页                 //
 void ReadPage(U32 addr, U8 *buf)
 {
 U16 i;
 
 NFChipEn();
 WrNFCmd(READCMD0);                //READCMD0=0
 WrNFAddr(0);                        //
 WrNFAddr(0);                        //因为读的是一个page,所以col addr=0
 WrNFAddr(addr);                        //
 WrNFAddr(addr>>8);                //block6,page25的地址
 WrNFCmd(READCMD1);                //READCMD1=0X30
 InitEcc();                                //初始化ECC
 WaitNFBusy();                        //
 for(i=0; i<2048; i++)
 buf = RdNFDat();        //将2k的内容读出
 NFChipDs();
 }
 /*------------------------------------------------------------/
 函数名称:        WritePage
 功能描述:
 传    参:        U32 addr, U8 *buf
 返 回 值:        U32 ~stat
 -------------------------------------------------------------*/
 /*【Nand Flash中的特殊硬件结构】
 1.页寄存器(Page Register):由于Nand Flash读取和编程操作
 来说,一般最小单位是页,所以,nand flash在硬件设计时候,就考虑到
 这一特性,对于每一片,都有一个对应的区域,专门用于存放,将要写入
 到物理存储单元中去的或者刚从存储单元中读取出来的,一页的数据,这
 个数据缓存区,本质上就是一个buffer,但是只是名字叫法不同,datasheet
 里面叫做data Register,实际理解为页缓存,大小应该是等于1个page
 恰当些。而正是因为有些人不了解此内部结构,才容易产生之前遇到的某人
 的误解,以为内存里面的数据,通过Nand Flash的FIFO,写入到Nand Flash
 里面去,就以为立刻实现了实际数据写入到物理存储单元中了。而实际上,
 只是写到了这个页缓存中,只有等你发了对应的编程第二阶段的确认命令0x10
 之后,实际的编程动作才开始,才开始把页缓存中的数据,一点点写到物理存
 储单元中去。*/
 //                        参考datasheet的第23页                        //
 U32 WritePage(U32 addr, U8 *buf)
 {
 U32 i, mecc;
 U8 stat, tmp[7];
 
 
 NFChipEn();                                //
 WrNFCmd(PROGCMD0);                //page program 命令
 WrNFAddr(0);                        //
 WrNFAddr(0);                        //
 WrNFAddr(addr);                        //
 WrNFAddr(addr>>8);                //要写入的page地址
 InitEcc();        //reset mecc and secc
 MEccUnlock();                        //unlock main data area ecc generation
 for(i=0; i<512; i++)        //具体要写入页的数据写入main data area
 WrNFDat(buf);        //将数据输入NAND FLASH的data register中
 //或者可以理解为写入page的缓冲区
 //只有在发送确认命令0x10之后,该内容才被写入物理存储单元。
 MEccLock();                                //unlock it
 mecc = RdNFMEcc();                //mecc赋值等于MAIN DATA AREA ECC0 STATUS ERGISTER的内容
 
 tmp[0] = mecc&0xff;                //[7:0]
 tmp[1] = (mecc>>8)&0xff;//[15:8]
 tmp[2] = (mecc>>16)&0xff;//[23:16]
 tmp[3] = (mecc>>24)&0xff;//[31:24]
 tmp[5] = 0xff;        //mark good block
 
 
 //WrNFDat(0xff);        //2048,坏块标志//此时主数据区已经lock了。如果不等于0xff就说明是坏块
 //sumsung规定在block第一和第二个page的spare area的第一个字节,如果不等于0xff就说明是坏块。
 SEccUnlock();        //校验码写入spare data area
 WrNFDat(0xff);        //改到这里来运行也一样,应该是没做坏块的判断吧?
 WrNFDat(tmp[0]);//ECC校验码
 WrNFDat(tmp[1]);
 WrNFDat(tmp[2]);
 WrNFDat(tmp[3]);//同上,也在页缓冲区
 SEccLock();
 
 WrNFCmd(PROGCMD1);        //确认命令,将以上数据写入物理存储器
 stat = WaitNFBusy();
 NFChipDs();
 
 return ~stat;
 
 
 }
 /*------------------------------------------------------------/
 函数名称:        nandMain
 功能描述:        入口函数
 传    参:        无
 返 回 值:        无
 -------------------------------------------------------------*/
 void nandMain(void)
 {
 U16 ID,i;
 U8 buf[512];
 U32 NFBlockNO=6;
 U32 NFPagesNO = 25;                                         //block6,page25
 U32 status;
 U32 BlockPages;
 BlockPages =(NFBlockNO<<6)+NFPagesNO;         //BlockPages=000110011001
 //左移6位是因为1Block=64Page
 //因此block6的起始地址位:6*64=6<<6
 Uart_Init(115200);
 Uart_Printf("\nthe main is running\n");
 InitNandCfg();                    //初始化函数
 ID=ReadChipId();                        //ID=ECf1 ;;ID=ecda
 Uart_Printf("\nnand flash`s ID is:%x\n",ID);
 
 if(EraseBlock(BlockPages)&0x1==TRUE)
 {
 Uart_Printf("\nblock %d is erased\n",NFBlockNO);
 ReadPage(BlockPages,buf); //读page中的内容
 Uart_Printf("\n/***********************擦除之后flash中的数据****************/\n");
 for(i=0; i<512; i++)
 Uart_Printf("%4x", buf);
 
 Uart_Printf("\n/***********************应写入数据****************/\n");
 | 
 |