nand flash按照我的理解,在开发板上就类似我们所用的电脑中的硬盘,用来保存系统运行的操作系统,应用程序,数据等,掉电之后还可以永久得保存数据(不包括临时数据)。通过控制或配置NAND Flash的控制器寄存器,即可完成对nand的操作:包括读、写、擦除等。
恩阳ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为成都创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:028-86922220(备注:SSL证书合作)期待与您的合作!而控制、配置这些寄存器是根据板子的原理图、用户手册以及nand flash芯片手册上的说明来配置的。
通过原理图,可见nand flash与cpu之间的数据传输主要是通过LDDATA0~7这8根引脚线,其中传输的“数据”可以是地址、数据,也可以是命令,这就要靠CLE、ALE引脚的状态进行选择。
对于命令的传输,主要是对NFCMD寄存器写以上相对应的命令值,但这个命令是分两个周期进行的。
而对于数据的传输,在数据传输模式下,传输数据也是要根据以上的格式去进行传输,分5个周期,每一个周期传输的数据都十分讲究,这就要求要有一个符合这种格式的巧妙算法(在接下来的代码中体现)。
了解了这些命令、数据的传输格式之后,就是要对具体的寄存器进行相应的配置了。首先要介绍这些寄存器的作用(数据手册上对各寄存器都有说明):
(1)NFCONF:用来设置时序参数,设置位宽。
(2)NFCMD:命令寄存器。
(3)NFADDR:地址寄存器。
(4)NFDATA:数据寄存器,用于读写数据。
(5)NFSTAT:状态寄存器,只用到最低1位,表示是否忙碌。
编程举例:
实现从nand flash中拷贝程序到sdram中运行,其中涉及到启动代码的编程,初始化内存控制器,读取并拷贝nand flash上的数据。(只展示部分核心代码)
head.S
.text .global _start _start: ldr sp,=4096 @设置堆栈 bl disable_watch_dog @关闭看门狗 bl set_mem @设置内存控制器 bl nand_init @nand初始化 ldr r0,=0x30000000 ldr r1,=4096 ldr r2,=4096 @传递参数 bl nand_read @从nand中拷贝 ldr sp,=0x38000000 ldr lr, =halt @设置返回地址 ldr pc, =main halt: b halt
nand.c
typedef struct s3c2440_nand { unsigned int NFCONF; unsigned int NFCONT; unsigned int NFCMMD; unsigned int NFADDR; unsigned int NFDATA; unsigned int NFMECCD0; unsigned int NFMECCD1; unsigned int NFSECCD; unsigned int NFSTAT; unsigned int NFESTAT0; unsigned int NFESTAT1; unsigned int NFMECC0; unsigned int NFMECC1; unsigned int NFSECC; unsigned int NFSBLK; unsigned int NFEBLK; }s3c2440_nand; //定义nandflash控制器的起始地址 static s3c2440_nand* nand_base = (s3c2440_nand*)0x4E000000; //片选 void select_chip_or_not(int flag)//0不片选,1片选 { if(flag == 1) { nand_base->NFCONT |= (0x1<<1); } if(flag == 0) { nand_base->NFCONT &= ~(0x1<<1); } } void write_command(unsigned char cmd) { volatile unsigned char *p = (volatile unsigned char *)&nand_base->NFCMMD; *p = cmd; } void write_addr(unsigned int addr) { int i; volatile unsigned char* p = (volatile unsigned char *)nand_base->NFADDR; *p = addr & 0xff; for(i=0; i<10; i++); *p = (addr >> 9) & 0xff; for(i=0; i<10; i++); *p = (addr >> 17) & 0xff; for(i=0; i<10; i++); *p = (addr >> 25) & 0xff; for(i=0; i<10; i++); } //等待nand flash就绪 void wait_ldle(void) { volatile unsigned char* p = (volatile unsigned char*)nand_base->NFSTAT; int flag = *p & 1; while(!flag) { int i; for(i=0;i<20;i++); } } unsigned char read_data(void) { volatile unsigned char *p= (volatile unsigned char*)nand_base->NFDATA; return *p; } void nand_read(unsigned char* buf,unsigned char base_addr,unsigned int size) { int i,j; //片选 select_chip_or_not(1); //复制数据 for(i=base_addr;iNFCONF = (0<<12)|(3<<8)|(0<<4); nand_base->NFCONT = (1<<4)|(1<<1)|(1<<0); nand_reset(); }
还要说下Makefile
objs := head.o init.o nand.o main.o nand.bin : $(objs) arm-linux-ld -Tnand.lds $^ -o nand_elf arm-linux-objcopy -O binary -S nand_elf $@ %.o : %.S arm-linux-gcc -c $< -o $@ %.o : %.c arm-linux-gcc -c $< -o $@ clean : rm -f nand.bin *.o nand_elf
平时写的Makefile不一样,这里使用了一个名为nand.lds的链接脚本,这样做主要是为了试验让编译好的程序在链接时存放的地址和理论运行地址都不同且不在同一个存储设备上,方便看试验效果。
nand.lds
SECTIONS { first 0x00000000 : {head.o init.o nand.o} second 0x30000000 : AT(4096) {main.o} }
链接脚本上的第一段是放head.S init.c nand.c编译出的内容,从0地址开始存放和执行,而main.o则是需要从nand flash手动复制到sdram中去执行。
实现的效果如图:
创新互联www.cdcxhl.cn,专业提供香港、美国云服务器,动态BGP最优骨干路由自动选择,持续稳定高效的网络助力业务部署。公司持有工信部办法的idc、isp许可证, 机房独有T级流量清洗系统配攻击溯源,准确进行流量调度,确保服务器高可用性。佳节活动现已开启,新人活动云服务器买多久送多久。