一:Nandflash驱动设计写的流程
1, 知道要读的东西 即:芯片选择为nandflash 方式:NFCOPNT-》对应位使有效;
2 清除RnB 即:使其进入空闲状态 方式:NFCONF—》对应位是空闲(清除要写入1才能变0)
3 发送页读指令周期0x00 方式: NFCMMD=0x00
4 发送列地址和行地址 方式:NFADDR=addr
注: 行地址是页号,列地址是页内偏移,若是页读则列地址发送0x00就行
若是随机读取则需要定位列地址和行地址
5 发送页读命令周期0x30 方式:NFCMMD=0x30
6 等待RnB 即;等待CPU将前面的工作完成之后使RnB进入忙 方式:检测NFSTAT 中对应位是否为1,为1等待结束,为0等待继续
7 读取数据 方式: 将NFDATA中的数据传给制定缓冲 eg buff[i]=NFDATA
8 取消nandflash芯片选择 方式: NFCONT 使对应为无效
我理解的发送两次页读命令周期:第一次发送0x00 是进行读前的准备工作 即找读的地址 等 第二次发送0x30 是进行真正的将数据从nandflash中读取到缓冲中 同理到其他的周期命令中:一般第一次是准备工作,第二次是进行工作
二: 一切工作看似已经完成,其实还有,这个可能还是用与其他大部分的驱动程序。那就 是在使用一个设备时要先初始化这个设备,在次 我们要初始化的是nandflash
其实在之前初始化的东西很多,比如在用C编写的话要初始化堆栈。还有要初始化SDRAM 总之一句话那就是用到什么就要先初始化什么
1 初始化NFCONFF 其实是初始化NFCONF中的三个位即 TACLS TWRPH0 TWRPH1
因为他们三个基本决定了读取数据的一些重要时间:(具体大小需要按照不同类型的nandflash进行计算,但一般原则是它们的值大一点比较稳定)
2 初始化NFCONT 设置REG_nCE位为1 MOND位为1 即 使片选信号无效
并开启控制器
3 复位
A 选中nandflash芯片 同上
B 清除RnB 同上
C 发送命令 0xff(reset 命令周期)
D 等待 RnB 同上
E 取消选中nandflash
三: 在汇编语言中即程序入口处调用读取页的函数,并用相应的寄存器传参;
四:nandflash驱动的写和读差不多:
参考的芯片手册与文档:S3C2440文档;K9GAG08U0D(nandflash芯片文档)
6410与210都差不多就是寄存器地址与相应的位需要变一下;
代码如下:
#define NFCONF (*(volatile unsigned long*)0x4E000000)
#define NFCONT (*(volatile unsigned long*)0x4E000004)
#define NFSTAT (*(volatile unsigned char*)0x4E000020)
#define NFCMD (*(volatile unsigned char*)0x4E000008)
#define NFADDR (*(volatile unsigned char*)0x4E00000C)
#define NFDATA (*(volatile unsigned char*)0x4E000010)
#define TACLS 1
#define TWRPH0 2
#define TWRPH1 1
void select_chip()
{
NFCONT &= ~(1<<1);
}
void deselect_chip()
{
NFCONT |= (1<<1);
}
void clear_RnB()
{
NFSTAT |= (1<<2);
}
void send_cmd(unsigned cmd)
{
NFCMD = cmd;
}
void send_addr(unsigned addr)
{
NFADDR = addr;
}
void wait_RnB()
{
while (!(NFSTAT&(1<<2)))
{
;
}
}
void nand_reset()
{
//选中flash
select_chip();
//清除RnB
clear_RnB();
//发送0xff命令
send_cmd(0xff);
//等待RnB
wait_RnB();
//取消选中flash
deselect_chip();
}
void nand_init()
{
//初始化NFCONF
NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
//初始化NFCONT
NFCONT = (1<<0) | (1<<1);
//复位
nand_reset();
}
void NF_PageRead(unsigned long addr,unsigned char* buff)
{
int i;
//选中nandflash芯片
select_chip();
//清除RnB
clear_RnB();
//发送命令0x00
send_cmd(0x00);
//发送列地址
send_addr(0x00);
send_addr(0x00);
//发送行地址
send_addr(addr&0xff);
send_addr((addr>>8)&0xff);
send_addr((addr>>16)&0xff);
//发送命令0x30
send_cmd(0x30);
//等待RnB
wait_RnB();
//读取数据
for(i=0;i<2048;i++)
{
buff[i] = NFDATA;
}
//取消选中nandflash芯片
deselect_chip();
}
void nand_to_ram(unsigned long start_addr, unsigned char* sdram_addr, int size)
{
int i;
for( i=(start_addr >>11); size>0;)
{
NF_PageRead(i,sdram_addr);
size -= 2048;
sdram_addr += 2048;
i++;
}
}
void NF_Erase(unsigned long addr)
{
int ret;
//选中flash芯片
select_chip();
//清除RnB
clear_RnB();
//发送命令0x60
send_cmd(0x60);
//发送行地址
send_addr(addr&0xff);
send_addr((addr>>8)&0xff);
send_addr((addr>>16)&0xff);
//发送命令D0
send_cmd(0xD0);
//等待RnB
wait_RnB();
//发送命令0x70
send_cmd(0x70);
//读取擦除结果
ret = NFDATA;
//取消选中flash芯片
deselect_chip();
return ret;
}
int NF_WritePage(unsigned long addr, unsigned char* buff)
{
int ret;
int i;
//选中flash芯片
select_chip();
//清除RnB
clear_RnB();
//发送命令0x80
send_cmd(0x80);
//发送列地址
send_addr(0x00);
send_addr(0x00);
//发送行地址
send_addr(addr&0xff);
send_addr((addr>>8)&0xff);
send_addr((addr>>16)&0xff);
//写入数据
for(i=0;i<2048;i++)
{
NFDATA = buff[i];
}
//发送命令0x10
send_cmd(0x10);
//等待RnB
wait_RnB();
//发送命令0x70
send_cmd(0x70);
//读取写入结果
ret = NFDATA;
//取消选中flash芯片
deselect_chip();
return ret;
}