设置好时序参数后,发送命令直接写NFCCMD,发送地址直接写NFADDR,写数据直接写NFDATA,读数据直接读NFDATA,控制器会发出相应的时序波形,从而控制NAND FLASH。
Ø 初始化
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);
}
Ø 读ID
片选->发送命令0x90->发送地址0x00->读五次->取消片选
Ø 读数据
注:2112 = 2048 + 64,2048为某一页page的数据,64位OOB
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();
}
此实验中,bin文件烧写到nandflash,从nand启动,上电后使用nand_read函数将程序从nand读到sdram,然后跳到sdram执行代码。如果程序执行正确,则nand_read函数正确。编译程序时需要把nand文件靠前,保证在前4k内容中包含nand函数。
int isBootFromNorFlash(void)
{
volatile unsigned int *p = (volatileunsigned int *)0;
unsigned int val = *p;
*p = 0x12345678;
if (*p == 0x12345678)
{
/* 写成功, 对应nand启动 */
*p = val;
return 0;
}
else
{
return 1;
}
}
void copy2sdram(void)
{
/* 要从lds文件中获得__code_start, __bss_start
* 然后从0地址把数据复制到__code_start
*/
extern int __code_start, __bss_start;
volatile unsigned int *dest = (volatileunsigned int *)&__code_start;
volatile unsigned int *end = (volatileunsigned int *)&__bss_start;
volatile unsigned int *src = (volatileunsigned 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);
}
}
Ø 烧写与擦除
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;
}
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();
}