1、所有相关的nand flash寄存器构成一个结构体,便于操作
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCONT;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFMECCD0;
S3C24X0_REG32 NFMECCD1;
S3C24X0_REG32 NFSECCD;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFESTAT0;
S3C24X0_REG32 NFESTAT1;
S3C24X0_REG32 NFMECC0;
S3C24X0_REG32 NFMECC1;
S3C24X0_REG32 NFSECC;
S3C24X0_REG32 NFSBLK;
S3C24X0_REG32 NFEBLK;
} S3C2440_NAND;
2、发出片选信号
void s3c2440_nand_select_chip(void){
int i;
//s3c2440nand是自定义的结构体指针,首地址是nand flash寄存器的首寄存器的地址。(S3C2440_NAND *)是将地址0x4e000000强制转换成结构体S3C2440_NAND的指针。
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
// 下面一句程序是指将s3c2440nand结构体指针下的NFCONT成员的第11位取0,查阅2440手册可知此位为片选位,低电平有效。
s3c2440nand->NFCONT &= ~(1<<1);
for(i=0; i<10; i++);}
3、取消片选信号
void s3c2440_nand_deselect_chip(void)
{
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
与发出片选信号函数不同的地方在于把NFCONT寄存器的第1位设为1.s3c2440nand->NFCONT |= (1<<1);
}
4、发命令
static void s3c2440_write_cmd(int cmd)
{
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
//定义一个无符号字符型指针指向s3c2440nand结构体指针的数据成员NFCMD的地址
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
//把传进来的命令值写到NFCMD寄存器中
*p = cmd;
}
5、发地址
(1)以下是本芯片手册的5个周期的地址,列(column)地址是寄存器的开始地址,里面的*L必须设置为低电平。
本nand flash芯片忽略任何额外的输入地址周期,也就是说地址大于5个周期,都以5个周期地址取值。
(2)程序
void s3c2440_write_addr_lp(unsigned int addr)
{
int i;
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
//无符号字符型指针p指向NFADDR寄存器的地址。
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
int col, page;
//这里NAND_BLOCK_MASK_LP取2047,由于&是按位与的意思,取得列地址,也就是对应nand flash某一页的某个地址。
col = addr & NAND_BLOCK_MASK_LP;
//这里NAND_SECTOR_SIZE_LP取2048,地址值求比值,也就是要知道此地址对应nand flash的第几页。
page = addr / NAND_SECTOR_SIZE_LP;
//第1和第二周期用于提取列地址(对应nand flash 的某一页的某个地址),由于是12位数据,因而第一个周期先取第八位值,第二个周期把col向右移8位,再进行与运算,也就是取高四位值。
*p = col & 0xff;/* Column Address A0~A7 */
for(i=0; i<10; i++);
*p = (col >> 8) & 0x0f; /* Column Address A8~A11 */
for(i=0; i<10; i++);
//第3~5周期用于提取行地址(对应nand flash的哪一页),第3个周期先取页地址的低8位数据,第4个周期再取页地址的次高8位数据,第五个周期再取高8位数据的最后两位值。
*p = page & 0xff;/* Row Address A12~A19 */
for(i=0; i<10; i++);
*p = (page >> 8) & 0xff;/* Row Address A20~A27 */
for(i=0; i<10; i++);
*p = (page >> 16) & 0x03;/* Row Address A28~A29 */
for(i=0; i<10; i++);
}
6、空闲等待
static void s3c2440_wait_idle(void)
{
int i;
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
//定义一个无符号字符型指针指向状态寄存器NFSTAT的地址。
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
//BUSY定义为1,要退出while循环,需要!(*p & BUSY)取0,也就是(*p & BUSY)取1,由于&是按位与运算,因而*p值必须为1,也就是说指针p对应的内容必须为1,联系上面的语句可知,状态寄存器NFSTAT的第0位为1。
while(!(*p & BUSY))
for(i=0; i<10; i++);
}
7、读取数据寄存器的值
static unsigned char s3c2440_read_data(void)
{
S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
//读取数据寄存器NFDATA的值
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
return *p;
}