一、数据手册相关内容
1.地址传输周期
2.命令表
3.在寄存器中,会涉及TACLS,TWRPH0,TWRPH1的设定
这里我们就去看nandflash的数据手册
在这里我们可以清楚的看到,TACLS=TCLS-TWP,TWRPH0=TWP,TWRPH1=TCLH,从下表可以查到时间,并根据主频转换成CPU周期数
二、寄存器
1.NFCONF
这个寄存器的0-3位是硬件控制的,TACLS,TWRPH0,TWRPH1的值也可以怎么设定上面有讲
2.NFCONT
这个寄存器我们先只关心这两位,一个是使能nandflash控制器,一个是使能chip
3.NFCMMD,NFADDR,NFDATA
命令寄存器,地址寄存器,数据寄存器,往里面读取值就行了
4.NFSTAT
这个寄存器第0位表示nandflash是否在忙,1表示不忙可以操作
第2位表示往里面写1就是清除RnB标识位
三、裸机驱动
这个驱动主要实现简单的往nandflash里面进行初始化,擦除,写,读操作,其中第0块是保证不是坏块的,所以我们以此来测试,因为我没有JTAG线,在中间要监测某些值得话我是改成了Linux下面的驱动,用ioremap来操作nandflash,用printk来监测调试的,没有JLINK线确实挺蛋疼的,下面是在ADS下的代码
init.s
AREA init, CODE, READONLY
ENTRY
IMPORT rNF_init
IMPORT rNF_ReadID
IMPORT rNF_Erase
IMPORT rNF_WritePage
IMPORT rNF_ReadPage
start
bl rNF_init
bl rNF_ReadID
mov r0,#
bl rNF_Erase //擦除第0块
mov r0,#
bl rNF_WritePage //写
mov r0,#
bl rNF_ReadPage //读
loop
b loop
END
nandflash.c
#define rNFCONF (*(volatile unsigned long *)0x4e000000)
#define rNFCONT (*(volatile unsigned long *)0x4e000004)
#define rNFCMMD (*(volatile unsigned long *)0x4e000008)
#define rNFADDR (*(volatile unsigned long *)0x4e00000c)
#define rNFDATA (*(volatile unsigned long *)0x4e000010)
#define rNFDATA8 (*(volatile unsigned char *)0x4e000010)
#define rNFSTAT (*(volatile unsigned long *)0x4e000020) #define CMD_READ_CYCLE1 0x00
#define CMD_READ_CYCLE2 0x30
#define CMD_READID 0x90
#define CMD_WRITE_CYCLE1 0x80
#define CMD_WRITE_CYCLE2 0x10
#define CMD_ERASE_CYCLE1 0x60
#define CMD_ERASE_CYCLE2 0xd0
#define CMD_STATUS 0x70
#define CMD_RESET 0xff //这些命令都可以查表得到 #define NF_Chip_En() {rNFCONT &= ~(1<<1);} //Enable chip select
#define NF_Chip_Ds() {rNFCONT |= (1<<1);} //Disable chip select #define Wr_NF_Cmd(cmd) {rNFCMMD = (cmd);}
#define Wr_NF_Addr(addr) {rNFADDR = (addr);} #define Wait_NF_Busy() {while(!(rNFSTAT & 1));} //等待系统不忙
#define DETECT_RB() {while(!(rNFSTAT & (1<<2)))} //RB位被检测到
#define NF_Clear_RB() {rNFSTAT |= (1<<2);} //清除RB位 #define NF_READ_DATA() (rNFDATA)
#define NF_READ_DATA8() (rNFDATA8) //读取一字节的数据 #define NF_WRITE_DATA(data) {rNFDATA = data;}
#define NF_WRITE_DATA8(data) {rNFDATA8 = data;} #define TACLS 1
#define TWRPH0 3
#define TWRPH1 0 #define U32 unsigned int
#define U16 unsigned short
#define U8 unsigned char
初始化:
static void rNF_Reset()
{
NF_Chip_En();
NF_Clear_RB();
Wr_NF_Cmd(CMD_RESET);
Wait_NF_Busy();
NF_Chip_Ds();
} void rNF_init(void)
{
rNFCONF = (TACLS<<)|(TWRPH0<<)|(TWRPH1<<);
rNFCONT = (<<)|(<<)|(<<)|(<<)|(<<);
rNF_Reset();
}
ReadID:
void delay(int num)
{
int i;
for(i=;i<num;i++);
} U8 rNF_ReadID()
{
U8 PMID,PDID,CYCLE3,CYCLE4,CYCLE5; NF_Chip_En();
NF_Clear_RB();
Wr_NF_Cmd(CMD_READID);
Wr_NF_Addr(0x0);
delay();
PMID = NF_READ_DATA8();
PDID = NF_READ_DATA8();
CYCLE3 = NF_READ_DATA8();
CYCLE4 = NF_READ_DATA8();
CYCLE5 = NF_READ_DATA8();
NF_Chip_Ds(); return PDID;
}
我们关心的是PDID,如果返回的PDID和数据手册一致,就表示nandflash设置没有什么问题了
擦除操作:
U8 rNF_Erase(U32 block_num)
{
char state; NF_Chip_En();
NF_Clear_RB();
Wr_NF_Cmd(CMD_ERASE_CYCLE1);
Wr_NF_Addr((block_num<<) & 0xff);
Wr_NF_Addr((block_num>>) & 0xff);
Wr_NF_Addr((block_num>>) & 0xff); //A18到A25,一次读取8位,注意移位
Wr_NF_Cmd(CMD_ERASE_CYCLE2);
delay();
Wr_NF_Cmd(CMD_STATUS); do
{
state = NF_READ_DATA8();
}while(!(state & 0x40)); NF_Chip_Ds();
return 0x66; //0x66表示擦除成功了
}
写操作:
U8 rNF_WritePage(U32 page_num)
{
int i;
char state; NF_Chip_En();
NF_Clear_RB();
Wr_NF_Cmd(CMD_WRITE_CYCLE1);
Wr_NF_Addr(0x00);
Wr_NF_Addr(0x00);
Wr_NF_Addr(page_num & 0xff);
Wr_NF_Addr((page_num>>) & 0xff);
Wr_NF_Addr((page_num>>) & 0xff); for(i=;i<;i++) //一页大小2KB
{
NF_WRITE_DATA8((char)(i+));
} Wr_NF_Cmd(CMD_WRITE_CYCLE2);
delay();
Wr_NF_Cmd(CMD_STATUS); do
{
state = NF_READ_DATA8();
}while(!(state & 0x40)); NF_Chip_Ds();
return 0x66;
}
读操作:
void rNF_ReadPage(U32 page_num)
{
int i;
U8 buf[]; NF_Chip_En();
NF_Clear_RB();
Wr_NF_Cmd(CMD_READ_CYCLE1);
Wr_NF_Addr(0x00);
Wr_NF_Addr(0x00);
Wr_NF_Addr(page_num & 0xff);
Wr_NF_Addr((page_num>>) & 0xff);
Wr_NF_Addr((page_num>>) & 0xff);
Wr_NF_Cmd(CMD_READ_CYCLE2);
Wait_NF_Busy(); for(i=;i<;i++)
{
buf[i] = NF_READ_DATA8();
} NF_Chip_Ds();
}