|
/**********************按鍵實驗*********************************/
// 公司名稱 :飛凌嵌入式技術有限公司
// 描 述 :nandflash
// 版 權 :飛凌嵌入式技術有限公司
// 網 址 :www.witech.com.cn
/***************************************************************/
/*
本實驗接口說明
*/
#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"); |
|