(3)信号引脚:
/*nandflash相关寄存器定义*/ #define NFCONF 0x70200000 #define NFCONT 0x70200004 #define NFCMMD 0x70200008 #define NFADDR 0x7020000C #define NFDATA 0x70200010 #define NFDATA8 (*(volatile unsigned char *)0x70200010) #define NFSTAT 0x70200028 int nand_erase(unsigned int block_addr); int Nand_PageWrite(unsigned long start_addr,char *buf);
/**************************** @File:nand.c @ @Tiny6410裸机上学期代码 @nandflash变硬盘 @Author:小君君 @****************************/ #include "common.h" #define NF_SetCommand(cmd) {(vi NFCMMD) = (cmd);} #define NF_SetAddr(addr) {(vi NFADDR) = (addr);} #define NF_SetData(data) {NFDATA8 = (data);} #define Chip_Select() {(vi NFCONT) &= ~(1 << 1);} #define Chip_DisSelect() {(vi NFCONT) |= (1 << 1);} #define NF_EnableRB() {(vi NFSTAT) |= (1 <<2);} #define NF_ChekBusy() {while(!((vi NFSTAT) & (1 <<0)));} /*复位函数*/ void nand_reset() { /*1.选中nandflash*/ Chip_Select(); /*2.清除RB标志位,开启忙信号检测功能*/ NF_EnableRB(); /*3.发送0xff复位命令*/ NF_SetCommand(0xFF); /*4.等待RnB信号,检测忙信号*/ NF_ChekBusy(); /*5.取消选中nandflash,为了省电*/ Chip_DisSelect(); } /*初始化nandflash控制器*/ void nand_init() { /*0.引脚功能配置*/ /*1.初始化NFCONF,设置时序参数*/ (vi NFCONF) = ( (0x2<<12)|(0xf<<8)|(0x7<<4) ); /*2.初始化NFCONT,取消片选,使能nandflash控制器*/ (vi NFCONT) = (0x3<<0); /*3.清除状态寄存器*/ (vi NFSTAT) = 0; /*4.复位操作*/ nand_reset(); } /*按页读取函数*/ void Nand_PageRead(unsigned long start_addr,char *buf) { int i; int page_size = 2048; /*(1)选中nandflash*/ Chip_Select(); /*(2)清除RB标志*/ NF_EnableRB(); /*(3)写入0x00读数据命令*/ NF_SetCommand(0x00); /*(4)发送列地址,两次(但是由于是页读的方式,所以列地址,即页中的偏移量就是0)*/ NF_SetAddr(0x00); NF_SetAddr(0x00); /*(5)发送页编号,即行地址,分三次完成*/ NF_SetAddr((start_addr) & 0xFF); NF_SetAddr((start_addr >> 8) & 0xFF); NF_SetAddr((start_addr >> 16) & 0xFF); /*(6)发送0x30命令*/ NF_SetCommand(0x30); /*(7)等待RB信号变为ready*/ NF_ChekBusy(); /*(8)读出数据,每次都取出数据寄存器的值,他会自动更新自己的值*/ for(i=0; i < page_size; i++) { *buf++ = NFDATA8; } /*(9)取消选中nandflash*/ Chip_DisSelect(); } /* 从NAND中拷贝代码到DRAM*/ int copy2ddr(unsigned int nand_start, unsigned long ddr_start, unsigned int len) { char *buf = (char *)ddr_start; unsigned int i; unsigned int page_shift = 11; // 1.发片选 Chip_Select(); // 2.使len为2048的整数倍 len = (len/2048+1)*2048; // 3.循环拷贝,每次拷贝一页数据 for (i = nand_start; i < nand_start + (len>>page_shift); i++, buf+=(1<<page_shift)) { // 读一页,即2048byte Nand_PageRead(i, buf); } return 0; } /*写入之前要擦除,参数是要擦除的页地址,擦除的是指定的页所在的块*/ int nand_erase(unsigned int block_addr) { unsigned int start_addr; int ret; start_addr = block_addr << 6; /*(1)选中nandflash*/ Chip_Select(); /*(2)清除RB标志*/ NF_EnableRB(); /*(3)写入0x60命令*/ NF_SetCommand(0x60); /*(4)发送页编号,即行地址,分三次完成*/ NF_SetAddr((start_addr) & 0xFF); NF_SetAddr((start_addr >> 8) & 0xFF); NF_SetAddr((start_addr >> 16) & 0xFF); /*(5)发送0xD0命令*/ NF_SetCommand(0xD0); /*(6)等待RB信号变为ready*/ NF_ChekBusy(); /*(7)发送命令0x70*/ NF_SetCommand(0x70); /*(8)读取擦出结果*/ ret = (NFDATA8); /*(9)取消选中nandflash*/ Chip_DisSelect(); /*(10)返回擦除结果*/ return ret; } int Nand_PageWrite(unsigned long start_addr,char *buf) { int i = 0,ret; /*(1)选中nandflash*/ Chip_Select(); /*(2)清除RB标志*/ NF_EnableRB(); /*(3)写入0x80命令*/ NF_SetCommand(0x80); /*(4)发送列地址,两次(但是由于是页读的方式,所以列地址,即页中的偏移量就是0)*/ NF_SetAddr(0x00); NF_SetAddr(0x00); /*(5)发送页编号,即行地址,分三次完成*/ NF_SetAddr((start_addr) & 0xFF); NF_SetAddr((start_addr >> 8) & 0xFF); NF_SetAddr((start_addr >> 16) & 0xFF); /*(6)写入数据,用循环*/ for(i = 0; i < 2048;i++) NF_SetData(*buf++); /*(7)发送0x10命令*/ NF_SetCommand(0x10); /*(8)等待RB信号变为ready*/ NF_ChekBusy(); /*(9)发送命令0x70,*/ NF_SetCommand(0x70); /*(10)读取写入结果,从数据寄存器读*/ ret = (NFDATA8); /*(11)取消选中nandflash*/ Chip_DisSelect(); /*(12)返回写入结果*/ return ret; }
13.测试文件
/**************************** @File:main.c @ @Tiny6410裸机上学期代码 @Nandflash测试文件 @Author:小君君 @****************************/ #include "common.h" int main(void) { unsigned int i = 500000; char buf[2048]; //mmu_init();//MMU初始化,这里不使用MMU led_init();//LED的GPIO初始化 button_init();//按键初始化 irq_init();//中断初始化 led_on();//点亮4颗LED while(i--); buf[1] = 100; nand_erase(5);//擦除第五块 Nand_PageWrite(64*5+1,buf);//每一块有64页,这里我们给的是页地址,所以要乘64,+1与否都是可以的。+1以后是第五块的第二页,否则是第五块的第一页 buf[1] = 10; Nand_PageRead(64*5+1,buf);//验证读取出来的数据是不是之前写进去的100,是的话就闪烁LED if(100 == buf[1]){ for(i = 0; i < 1000;i++){ led_off(); i = 500000; while(i--); led_on(); i = 500000; while(i--); } } while(1) ; return 0; }
14.在start.s调用代码搬移子函数
@将bin文件从_start开始到bss_start结束的数据搬移到_start指定的链接地址(0x50008000) copy_to_ddr: mov r0, #0x00 ldr r1, =_start ldr r2, =bss_start sub r2,r2,r1 mov ip,lr bl copy2ddr mov lr,ip mov pc,lr