Nand Flash 硬件以及初始化
请看Nand Flash 硬件图:

nand flash 拥有DATA0~DATA7 1个字节的传输宽度,在此 DATA和地址线是共用的 当ALE为高电平的时候Data线会变成地址总线
下面介绍各个引脚的用处:
1. Rnb : READY/BUSY OUTPUT 当为低电平的时候表示正在nandflash 忙状态
2. CLE 命令/数据标志引脚 当为高电平 的时候是写命令 低电平的时候是写数据
3. nFCE: 选择芯片引脚 Chip select
4. ALE: 当ALE为高电平的时候DATA线会变成地址线
5. nFWE 当这个引脚是低电平的时候 写使能
6.nFRE:当为低电平的时候读使能。
此外 在写使能和读使能都是在上升沿的时候读取和写入有效的数值
我们的S2C2440拥有Nandflash控制器所以只要合理的配置控制器的参数就可以读写其中的数据
首先我们先要实现nandflash 的初始化工作:

上图描述的是nand flash 写命令和写地址的时序 名词解释如下:
1. TACLS: CLE & ALE duration setting value 命令或者地址线建立的时间
2. TWRPH0: 写地址或者命令的时间
2. TWRPH1:写使能无效到CLE或者ALE无效的时间
这三个是我们需要初始化的时钟
注意 我们看到HLCK的周期是10ns 也就是说明这三个建立或者无效的时间都可以在一个时钟周期完成,此时是10ns
下图是芯片手册给的时序和时间参考信息:


1. 从此图看出TACLS = TCLS - TWP 而TCLS和TWP都是12ns 所以TACLS为0
2. TWRPH0 : 在手册里面是TWP 所以是12ns
3. TWRPH1:TALH和tCH的最大值 表中可知是5ns 所以是5ns
我们得出结论:
1. TACLS 是0
2. TWRPH0:12ns
3 TWRPH1 :5ns
在结合CPU芯片手册做计算:

TACLS = 0
12ns = 10 * x+1; x = 1 TWRPH 0 = 1
5ns = (x+1)*10 x = 0; TWRPH1 = 0;
下面是nandflash的初始化代码:
void nand_flash_Init(void)
{
NFCONF = (0<<12) | (1<<8)|(0<<4);
NFCONT = (1<<1)|(1<<4)|(1<<0);
}
设置TACLS和TWRPH0 TWRPH1 的延时 然后使能EEC和nandfalsh
读nandflash
1. 选择nandflash
2. 写入col的LSB和MSB
3. 写入page的LSB Middle SB 和MSB
4. 写入0x30
5. 读取nandflash里面的数据 不过每一次只能读从0~2047的数据 所以读下一页的时候需要重新重复写0x00
6,取消选择nandflash
void nand_read(unsigned int addr, unsigned int *buff, unsigned int NumToRead)
{
unsigned int i = 0;
unsigned int page = addr >> 11; //get page location
unsigned int col = addr & 2047; //get collumn location
nand_select();
while(i < NumToRead)
{
nand_cmd(0);
/*send col addr */
nand_addr_byte(col&0xFF);
nand_addr_byte((col>>8)&0xFF);
/*send row addr 1,2,3*/
nand_addr_byte(page&0xFF);
nand_addr_byte((page>>8)&0xFF);
nand_addr_byte((page>>16)&0xFF);
nand_cmd(0x30);
Wait_ready();
for(; (col < 2048)&(i<NumToRead); col++)
{
buff[i++] = nand_data();
}
if(i == NumToRead)
break;
col = 0;
page++;
}
nand_deselect();
}
写nandflash
1. 选择nandflash
2.写入0x80
3. 写col
4. 写page
5. 写入数据
6.写入0x10
注意每一次只能写到2047 这个地址如果大于这个数字 则需要重新发送0x80
void nand_write(unsigned int addr, unsigned char *buff, unsigned int len)
{
unsigned int page = addr / 2048;
unsigned int col = addr & (2048-1);
unsigned int i = 0;
nand_select();
while(1)
{
nand_cmd(0x80);
nand_addr_byte(col & 0xff);
nand_addr_byte((col >> 8)&0xff);
nand_addr_byte(page & 0xff);
nand_addr_byte((page>>8) & 0xff);
nand_addr_byte((page>>16) & 0xff);
for(; (col < 2048)&& (i < len); col++)
{
nand_w_data(buff[i++]);
}
nand_cmd(0x10);
Wait_ready();
if(i == len)
break;
col = 0;
page++;
}
}
擦除nandflash
1. 选择nandflash
2.写入0x60
3. 写入要擦除的块(注意块的大小是128k 所以说每一次擦除128k的内容)
4.写入0xD0
5.等待擦除完毕
6. 取消选择nandflash
int nand_flash_earse(unsigned int addr, unsigned int len)
{
int page = addr / 2048;
if(addr & (0x1FFFF))
return -1;
if((len & 0x1FFFF))
return -1;
nand_select();
while(1)
{
page = addr / 2048;
nand_cmd(0x60);
nand_cmd(page & 0xff);
nand_cmd((page >> 8)&0xff);
nand_cmd((page>>16)&0xff);
nand_cmd(0xD0);
Wait_ready();
len -= 128 * 1024;
if(len == 0)
break;
addr += 128 * 1024;
}
nand_deselect();
return 0;
}
来源:https://www.cnblogs.com/shwzh1990/p/12132333.html