我相信上一篇**已经对nand flash的操作有了一定的了解,下面一起看一下程序实例:
#include "include.h"
extern void Uart_Printf(char *fmt,...);
extern void Uart_Init(int baud);
//extern void Uart_Select(int ch);
static void InitNandCfg(void)
{
rGPACON = (rGPACON &~(0x3f<<17)) | (0x3f<<17); //配置芯片引脚,因为GPACON复位后各位的值为1,所以此步也可没有
//TACLS为1个HCLK,TWRPH0为5个HCLK,TWRPH1为2个HCLK,数据宽度8位
rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
//禁止紧锁,软件禁止上锁,禁止非法访问中断,禁止RnB 中断,RnB检测上升沿,锁定备份ECC,锁定主数据区域ECC生成,初始化ECC 编码器/译码器,
//强制nFCE 为高(禁止片选),NAND Flash 控制器使能
rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
}
static U32 WaitNFBusy(void) // R/B 未接好?
{
U8 stat;
WrNFCmd(QUERYCMD);//0x70,读状态命令
do
{
stat = RdNFDat();//读取NFDATA
}
while (!(stat&0x40));//,第6位,判断是否在忙
WrNFCmd(READCMD0);//写页读命令周期0
return stat&1; //注意0为操作成功
}
static U32 ReadChipId(void)
{
U32 id,k;
NFChipEn(); //使能片选
WrNFCmd(RdIDCMD);//读ID命令
WrNFAddr(0);//写入地址0
while(NFIsBusy()); //等待不忙
id = RdNFDat()<<8;//应该是只读的厂商ID
for(k=0;k<500;k++);//延时
id |= RdNFDat();//低8位为设备ID
NFChipDs(); //关闭片选
return id;//返回ID值
}
static U16 ReadStatus(void)
{
U16 stat;
NFChipEn(); //片选使能
WrNFCmd(QUERYCMD); //读状态命令
stat = RdNFDat(); //读取状态值
NFChipDs();//关闭片选
return stat;
}
U32 EraseBlock(U32 addr)//输入参数是具体的页数,擦除的是页数所在的块
{
U8 stat;
addr &= ~0x3f;//为了将地址赋给A18~A19
NFChipEn(); //片选使能
WrNFCmd(ERASECMD0); //擦除命令周期0
WrNFAddr(addr);//写地址写3个行周期A18~A19
WrNFAddr(addr>>8);//A20~A27
WrNFAddr(addr>>16);//A28
WrNFCmd(ERASECMD1); // 擦除命令周期1
stat = WaitNFBusy();//等待不忙
NFChipDs();//关闭片选
return ~stat;//返回1则操作成功
}
void ReadPage(U32 addr, U8 *buf)//并没有使用ECC校验
{
U16 i;
NFChipEn();//片选使能
WrNFCmd(READCMD0);//读命令周期0
WrNFAddr(0);//写列地址A0~A7
WrNFAddr(0);//写列地址A8~A11
WrNFAddr(addr);//行地址A12~A19
WrNFAddr(addr>>8);//行地址A20~A27
WrNFAddr(addr>>16);//行地址A28
WrNFCmd(READCMD1);//读命令周期1
InitEcc();//复位ECC
WaitNFBusy();
for(i=0; i<2048; i++)
buf = RdNFDat();//读取数据存入buf中
NFChipDs();//关闭片选
}
U32 WritePage(U32 addr, U8 *buf)
{
U32 i, mecc;
U8 stat, tmp[7];
NFChipEn();
WrNFCmd(PROGCMD0);//页写命令周期1
WrNFAddr(0);
WrNFAddr(0);
WrNFAddr(addr);
WrNFAddr(addr>>8);
WrNFAddr(addr>>16);
InitEcc(); //reset mecc and secc
MEccUnlock();//ECC解锁
for(i=0; i<2048; i++)
WrNFDat(buf);//写数据
MEccLock();//锁定ECC值
mecc =RdNFMEcc();//读取ECC码
//把ECC码转化为字节型
tmp[0] = mecc&0xff;
tmp[1] = (mecc>>8)&0xff;
tmp[2] = (mecc>>16)&0xff;
tmp[3] = (mecc>>24)&0xff;
tmp[5] = 0xff; //mark good block
WrNFDat(0xff);//2048,坏块标志
SEccUnlock();//解锁spare区ECC
WrNFDat(tmp[0]);//把main区的ECC写入spare区的前4个字节
WrNFDat(tmp[1]);
WrNFDat(tmp[2]);
WrNFDat(tmp[3]);
SEccLock();//锁定spare区ECC
WrNFCmd(PROGCMD1);//页写命令周期1
stat = WaitNFBusy();
NFChipDs();
return ~stat;
}
void nandMain(void)
{
U16 ID,i;
U8 buf[2048];
U32 NFBlockNO=6;
U32 NFPagesNO = 25; //第6块第25页
U32 status;
U32 BlockPages;
BlockPages =(NFBlockNO<<6)+NFPagesNO; //转化为总页数
Uart_Init(115200);
Uart_Printf("\nthe main is running\n");
InitNandCfg(); //初始化函数
ID=ReadChipId();//ID 我的是现代的FLash,ID为:adda
Uart_Printf("\nnand flash`s ID is:%x\n",ID);
if(EraseBlock(BlockPages)&0x1==TRUE)//因为EraseBlock()的输入参数是页数,所以输入的是BlockPages
{
Uart_Printf("\nblock %d is erased\n",NFBlockNO);//打印擦除的是那一块
ReadPage(BlockPages,buf);//读取擦除后的数据
Uart_Printf("\n\n");
for(i=0; i<2048; i++)
Uart_Printf("%4x", buf); //将读出的数据进行打印
Uart_Printf("\n\n");
for(i=0; i<2048; i++)
{
buf = i;
Uart_Printf("%4x", buf);
}
Uart_Printf("\nWrite data[%d block, %d page].\n", NFBlockNO,NFPagesNO);
status = WritePage(BlockPages,buf);//写入数据
if(status&0x1==TRUE )//返回成功值
Uart_Printf("\nWrite OK.\n");
else
Uart_Printf("\nWrite Error.\n");
for(i=0; i<2048; i++)
buf = 1; //为验证后边数组中的数据是来自flash,实际上相当于是在数组中擦除了flash的数据,因为如果flash擦除时内容就全为1
ReadPage(BlockPages,buf); //将读取的数据存入buf中
Uart_Printf("\nRead data[%d block, %d page].\n", NFBlockNO,NFPagesNO);//输出块号和页号
Uart_Printf("\n\n");
for(i=0; i<2048; i++)
Uart_Printf("%4x", buf);//打印所读取的数据
}
else
Uart_Printf("\nblock %4x erased is bad\n",NFBlockNO); //否则是坏块,并打印信息
while(1);
}
本工程中用到的其他文件:
include.h:
#define rNFCONF (*(volatile unsigned *)0x4E000000)
#define rNFCONT (*(volatile unsigned *)0x4E000004)
#define rNFCMD (*(volatile unsigned *)0x4E000008)
#define rNFADDR (*(volatile unsigned *)0x4E00000C)
#define rNFCMMD (*(volatile unsigned *)0x4E000008)
#define rNFDATA (*(volatile unsigned *)0x4E000010)
#define rNFDATA8 (*(volatile unsigned char *)0x4E000010)
#define rNFMECC0 (*(volatile unsigned *)0x4E00002c)
#define rNFSTAT (*(volatile unsigned *)0x4E000020)
#define rNFESTAT0 (*(volatile unsigned *)0x4E000024)
#define rGPACON (*(volatile unsigned *)0x56000000)
#define rUTRSTAT0 (*(volatile unsigned *)0x50000010) //UART 0 Tx/Rx status
#define rULCON0 (*(volatile unsigned *)0x50000000) //UART 0 Line control
#define rUCON0 (*(volatile unsigned *)0x50000004) //UART 0 Control
#define rUFCON0 (*(volatile unsigned *)0x50000008) //UART 0 FIFO control
#define rUBRDIV0 (*(volatile unsigned *)0x50000028) //UART 0 Baud rate divisor
#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch)
#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 TACLS 1//7 // 1-clk(0ns)
#define TWRPH0 4//7 // 3-clk(25ns)
#define TWRPH1 1//7 // 1-clk(10ns) //TACLS+TWRPH0+TWRPH1>=50ns
#define U32 unsigned int
#define U16 unsigned short
#define S32 int
#define S16 short int
#define U8 unsigned char
#define S8 char
#define TRUE 1
#define FALSE 0
#define OK 1
#define FAIL 0
///////////////////////////////////////////////////////////////////////////////////////////////
uart.c
#include "include.h"
#include <stdarg.h>
void Uart_Init(int baud)
{
int i;
rUFCON0 = 0x0; //UART channel 0 FIFO control register, FIFO disable
//UART0
rULCON0 = 0x3; //Line control register : Normal,No parity,1 stop,8 bits
// [10] [9] [8] [7] [6] [5] [4] [3:2] [1:0]
// Clock Sel, Tx Int, Rx Int, Rx Time Out, Rx err, Loop-back, Send break, Transmit Mode, Receive Mode
// 0 1 0 , 0 1 0 0 , 01 01
// PCLK Level Pulse Disable Generate Normal Normal Interrupt or Polling
rUCON0 = 0x805; // Control register
rUBRDIV0=( (int)(50000000/16./baud+0.5) -1 ); //Baud rate divisior register 0
//UART1
for(i=0;i<100;i++);
}
//=====================================================================
void Uart_SendByte(int data)
{
if(data=='\n')
{
while(!(rUTRSTAT0 & 0x2));
// Delay(1); //because the slow response of hyper_terminal
WrUTXH0('\r');
}
while(!(rUTRSTAT0 & 0x2)); //Wait until THR is empty.
// Delay(1);
WrUTXH0(data);
}
//====================================================================
void Uart_SendString(S8 *pt)
{
while(*pt)
Uart_SendByte(*pt++);
}
//=====================================================================
//If you don't use vsprintf(), the code size is reduced very much.
void Uart_Printf(S8 *fmt,...)
{
va_list ap;
S8 str[255];
va_start(ap,fmt);
vsprintf(str,fmt,ap);
Uart_SendString(str);
va_end(ap);
}
另外还要加上初始化文件以跳转到nandMain
以上就是一个完整的工程 |
|