- Nandflash 操作原理
①原理图上nand 和 cpu之间只有数据线,怎么传输地址?
在DATA0-DATA7上既传输数据,又传输地址,当ALE为高电平传输的是地址
②要操作NAND要发出命令,命令怎么传入?
ALE为高电平传输的是地址
CLE为高电平传输的是命令
ALE和CLE都为低电平传输的数据
③数据线既接到NAND 也接到NOR,还会接到DM9000,那怎么避免干扰
这些设备,要想访问必须要线选中,片选信号
④假设烧写NAND ,把命令,数据和地址都发给它,NAND 肯定不会一瞬间完 成,怎么判断烧写完成
通过状态引脚RnB来判断,:高电平表示完成,低电平表示正忙
⑤怎么操作NAND 呢?
一般就是发出命令,发出地址,发出数据/读出数据
读ID时序
cpu nand控制器寄存器
uboot操作NAND
为什么是五个周期的地址呢,因为nand 是256M的,2的28次方,也就是需要28bit数据来表示,那就是4byte数据,为了兼容更大的nand,所以用了五个周期的地址。
2.cpu,nand时序图和代码实现
实现读ID代码:
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
/*设置NAND FLASH的时序*/
NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
/*使能NAND FLASH控制器,初始化ECC,禁止片选*/
NFCONT = (1<<4) | (1<<1) | (1<<0);
}
void nand_select(void)
{
/*使能片选*/
NFCONT &=~(1<<1);
}
void nand_deselect(void)
{
/*禁止片选*/
NFCONT |= (1<<1);
}
void nand_cmd(unsigned char cmd)
{
volatile int i;
NFCCMD = cmd;
for(i=0; i<10; i++);/*延时使得信号更加稳定*/
}
void nand_addr_byte(unsigned char addr)
{
volatile int i;
NFADDR = addr;
for(i=0; i<10; i++);
}
unsigned char nand_data(void)
{
return NFDATA;
}
void nand_chip_id(void)
{
unsigned char buf[5]={0};
nand_select();
nand_cmd(0x90);
nand_addr_byte(0x00);
buf[0] = nand_data();
buf[1] = nand_data();
buf[2] = nand_data();
buf[3] = nand_data();
buf[4] = nand_data();
nand_deselect();
printf("maker id = 0x%x\n\r",buf[0]);
printf("device id = 0x%x\n\r",buf[1]);
printf("3rd byte = 0x%x\n\r",buf[2]);
printf("4th byte = 0x%x\n\r",buf[3]);
printf("page size = %d kb\n\r",1 << (buf[3] & 0x03));
printf("block size = %d kb\n\r",64 << ((buf[3] >> 4) & 0x03));
printf("5th byte = 0x%x\n\r",buf[4]);
}
3.nand read operation
NAND READ 实现:
void nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
{
int i = 0;
int page = addr / 2048;
int col = addr & (2048 - 1);
nand_select();
while (i < len)
{
/* 发出00h命令 */
nand_cmd(00);
/* 发出地址 */
/* col addr */
nand_addr_byte(col & 0xff);
nand_addr_byte((col>>8) & 0xff);
/* row/page addr */
nand_addr_byte(page & 0xff);
nand_addr_byte((page>>8) & 0xff);
nand_addr_byte((page>>16) & 0xff);
/* 发出30h命令 */
nand_cmd(0x30);
/* 等待就绪 */
wait_ready();
/* 读数据 */
for (; (col < 2048) && (i < len); col++)
{
buf[i++] = nand_data();
}
if (i == len)
break;
col = 0;
page++;
}
nand_deselect();
}
更改代码支持NAND启动:
void copy2sdram(void)
{
/* 要从lds文件中获得 __code_start, __bss_start
* 然后从0地址把数据复制到__code_start
*/
extern int __code_start, __bss_start;
volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
volatile unsigned int *src = (volatile unsigned int *)0;
int len;
len = ((int)&__bss_start) - ((int)&__code_start);
if (isBootFromNorFlash())
{
while (dest < end)
{
*dest++ = *src++;
}
}
else
{
nand_init();
nand_read(src, dest, len);?//如果len大于4k怎么办
}
}
int isBootFromNorFlash(void)
{
volatile unsigned int *p = (volatile unsigned int *)0;
unsigned int val = *p;
*p = 0x12345678;
if (*p == 0x12345678)
{
/* 写成功, 对应nand启动 */
*p = val;
return 0;
}
else
{
return 1;
}
}
NAND ERASE 和NAND WRITE
code erase实现:
/*以块为单位进行擦除*/
int nand_erase(unsigned int addr, unsigned int len)
{
int page = addr / 2048;
if (addr & (0x1FFFF))
{
printf("nand_erase err, addr is not block align\n\r");
return -1;
}
if (len & (0x1FFFF))
{
printf("nand_erase err, len is not block align\n\r");
return -1;
}
nand_select();
while (1)
{
page = addr / 2048;
nand_cmd(0x60);
/* row/page addr */
nand_addr_byte(page & 0xff);
nand_addr_byte((page>>8) & 0xff);
nand_addr_byte((page>>16) & 0xff);
nand_cmd(0xD0);
wait_ready();
len -= (128*1024);
if (len == 0)
break;
addr += (128*1024);
}
nand_deselect();
return 0;
}
code write 实现:
void nand_write(unsigned int addr, unsigned char *buf, unsigned int len)
{
int page = addr / 2048;
int col = addr & (2048 - 1);
int i = 0;
nand_select();
while (1)
{
nand_cmd(0x80);
/* 发出地址 */
/* col addr */
nand_addr_byte(col & 0xff);
nand_addr_byte((col>>8) & 0xff);
/* row/page addr */
nand_addr_byte(page & 0xff);
nand_addr_byte((page>>8) & 0xff);
nand_addr_byte((page>>16) & 0xff);
/* 发出数据 */
for (; (col < 2048) && (i < len); )
{
nand_w_data(buf[i++]);
}
nand_cmd(0x10);
wait_ready();
if (i == len)
break;
else
{
/* 开始下一个循环page */
col = 0;
page++;
}
}
nand_deselect();
}