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