NF_ADDR=(page_address>>8)&0xff; 3rd.Cycle
NF_ADDR=(page_address>>16)&0xff; 4th.Cycle
其中NF_CMD和NF_ADDR分别是NandFlash的命令寄存器和地址寄存器的地址解引用,我一般这样定义它们,
#define rNFCMD (*(volatile unsigned char *)0x4e000004) //NADD Flash command
#define rNFADDR (*(volatile unsigned char *)0x4e000008) //NAND Flash address
事实上,当NF_CMD=0x01时,地址寄存器中的第8位(A8)将被设置为1(如上文分析,A8位不在我们传递的地址中,这个位其实就是硬件电路根据 01h或是00h这两个命令来置高位或是置低位),这样我们传递column_addr的值256随然由于数据溢出变为1,但A8位已经由于NF_CMD =0x01的关系被置为1了,所以我们传到地址寄存器里的值变成了
A0 A1 A2 A3 A4 A5 A6 A7 A8
1 0 0 0 0 0 0 0 1
这8个位所表示的正好是256,这样读操作将从此页的第256号byte(2nd half的第0号byte)开始读取数据。 nand_flash.c中包含3个函数
void nf_reset(void);
void nf_init(void);
void nf_read(unsigned int src_addr,unsigned char *desc_addr,int size);
nf_reset()将被nf_init()调用。nf_init()是nand_flash的初始化函数,在对nand flash进行任何操作之前,nf_init()必须被调用。
nf_read(unsigned int src_addr,unsigned char *desc_addr,int size);为读函数,src_addr是nand flash上的地址,desc_addr是内存地址,size是读取文件的长度。
在nf_reset和nf_read函数中存在两个宏
NF_nFCE_L();
NF_nFCE_H();
你可以看到当每次对Nand Flash进行操作之前NF_nFCE_L()必定被调用,操作结束之时NF_nFCE_H()必定被调用。这两个宏用于启动和关闭Flash芯片的工作(片选/取消片选)。至于nf_reset()中的
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
这一行代码是对NandFlash的控制寄存器进行初始化配置,rNFCONF是Nand Flash的配置寄存器,各个位的具体功能请参阅s3c2410数据手册。
现在举一个例子,假设我要从Nand Flash中的第5000字节处开始读取1024个字节到内存的0x30000000处,我们这样调用read函数
nf_read(5000, 0x30000000,1024);
我们来分析5000这个src_addr.
根据
column_addr=src_addr%512;
page_address=(src_addr>>9);
我们可得出column_addr=5000%512=392
page_address=(5000>>9)=9
于是我们可以知道5000这个地址是在第9页的第392个字节处,于是我们的nf_read函数将这样发送命令和参数
column_addr=5000%512;
>page_address=(5000>>9);
NF_CMD=0x01; 从2nd half开始读取
NF_ADDR= column_addr &0xff; 1st Cycle
NF_ADDR=page_address&0xff; 2nd.Cycle
NF_ADDR=(page_address>>8)&0xff; 3rd.Cycle
NF_ADDR=(page_address>>16)&0xff; 4th.Cycle
向NandFlash的命令寄存器和地址寄存器发送完以上命令和参数之后,我们就可以从rNFDATA寄存器(NandFlash数据寄存器)读取数据了.
我用下面的代码进行数据的读取.
for(i=column_addr;i<512;i++)
{
*buf++=NF_RDDATA();
}
每当读取完一个Page之后,数据指针会落在下一个Page的0号Column(0号Byte).
下面是源代码:
/*
www.another-prj.com
author: caiyuqing
本代码只属于交流学习,不得用于商业开发
*/
#include "s3c2410.h"
#include "nand_flash.h"
static unsigned char seBuf[16]={0xff};
//--------------------------------------------------------------------------------------
unsigned short nf_checkId(void)
{
int i;
unsigned short id;
NF_nFCE_L(); //chip enable
NF_CMD(0x90); //Read ID
NF_ADDR(0x0);
for(i=0;i<10;i++); //wait tWB(100ns)
id=NF_RDDATA()<<8; // Maker code(K9S1208V:0xec)
id|=NF_RDDATA(); // Devide code(K9S1208V:0x76)
NF_nFCE_H(); //chip enable
return id;
}
//--------------------------------------------------------------------------------------
static void nf_reset(void)
{
int i;
NF_nFCE_L(); //chip enable
NF_CMD(0xFF); //reset command
for(i=0;i<10;i++); //tWB = 100ns.
NF_WAITRB(); //wait 200~500us;
NF_nFCE_H(); //chip disable
}
//--------------------------------------------------------------------------------------
void nf_init(void)
{
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
// 1 1 1 1 1 xxx r xxx, r xxx
// En r r ECCR nFCE=H tACLS tWRPH0 tWRPH1
nf_reset();
}
//--------------------------------------------------------------------------------------
void nf_read(unsigned int src_addr,unsigned char *desc_addr,int size)
{
int i;
unsigned int column_addr = src_addr % 512; // column address
unsigned int page_address = (src_addr >> 9); // page addrress
unsigned char *buf = desc_addr;
while((unsigned int)buf < (unsigned int)(desc_addr) + size)
{
NF_nFCE_L(); // enable chip
/*NF_ADDR和NF_CMD为nand_flash的地址和命令寄存器的解引用*/
if(column_addr > 255) // 2end halft
NF_CMD(0x01); // Read2 command. cmd 0x01: Read command(start from 2end half page)
else
NF_CMD(0x00); // 1st halft?
NF_ADDR(column_addr & 0xff); // Column Address
NF_ADDR(page_address & 0xff); // Page Address
NF_ADDR((page_address >> 8) & 0xff); // ...
NF_ADDR((page_address >> 16) & 0xff); // ..
for(i = 0; i < 10; i++); // wait tWB(100ns)/??????
NF_WAITRB(); // Wait tR(max 12us)
// Read from main area
for(i = column_addr; i < 512; i++)
{
*buf++= NF_RDDATA();
}
NF_nFCE_H(); // disable chip
column_addr = 0;
page_address++;
}
return ;
}