NAND Flash裸板编程
nand flash按照我的理解,在开发板上就类似我们所用的电脑中的硬盘,用来保存系统运行的操作系统,应用程序,数据等,掉电之后还可以永久得保存数据(不包括临时数据)。通过控制或配置NAND Flash的控制器寄存器,即可完成对nand的操作:包括读、写、擦除等。
而控制、配置这些寄存器是根据板子的原理图、用户手册以及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:ldrsp,=4096@设置堆栈bldisable_watch_dog@关闭看门狗blset_mem@设置内存控制器blnand_init@nand初始化ldrr0,=0x30000000ldrr1,=4096ldrr2,=4096@传递参数blnand_read@从nand中拷贝ldrsp,=0x38000000ldrlr,=halt@设置返回地址ldrpc,=mainhalt:bhalt
nand.c
typedefstructs3c2440_nand{unsignedintNFCONF;unsignedintNFCONT;unsignedintNFCMMD;unsignedintNFADDR;unsignedintNFDATA;unsignedintNFMECCD0;unsignedintNFMECCD1;unsignedintNFSECCD;unsignedintNFSTAT;unsignedintNFESTAT0;unsignedintNFESTAT1;unsignedintNFMECC0;unsignedintNFMECC1;unsignedintNFSECC;unsignedintNFSBLK;unsignedintNFEBLK;}s3c2440_nand;//定义nandflash控制器的起始地址statics3c2440_nand*nand_base=(s3c2440_nand*)0x4E000000;//片选voidselect_chip_or_not(intflag)//0不片选,1片选{if(flag==1){nand_base->NFCONT|=(0x1<<1);}if(flag==0){nand_base->NFCONT&=~(0x1<<1);}}voidwrite_command(unsignedcharcmd){volatileunsignedchar*p=(volatileunsignedchar*)&nand_base->NFCMMD;*p=cmd;}voidwrite_addr(unsignedintaddr){inti;volatileunsignedchar*p=(volatileunsignedchar*)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++);}//等待nandflash就绪voidwait_ldle(void){volatileunsignedchar*p=(volatileunsignedchar*)nand_base->NFSTAT;intflag=*p&1;while(!flag){inti;for(i=0;i<20;i++);}}unsignedcharread_data(void){volatileunsignedchar*p=(volatileunsignedchar*)nand_base->NFDATA;return*p;}voidnand_read(unsignedchar*buf,unsignedcharbase_addr,unsignedintsize){inti,j;//片选select_chip_or_not(1);//复制数据for(i=base_addr;i<base_addr+size;){write_command(0);//发送读命令write_addr(i);//发送地址write_command(0x30);wait_ldle();for(j=0;j<512;j++,i++){*buf=read_data();//读取数据,一次读取一页(512个字节)buf++;}}select_chip_or_not(0);//取消片选}voidnand_reset(void){select_chip_or_not(1);//片选write_command(0xff);wait_ldle();select_chip_or_not(0);}voidnand_init(void){nand_base->NFCONF=(0<<12)|(3<<8)|(0<<4);nand_base->NFCONT=(1<<4)|(1<<1)|(1<<0);nand_reset();}
还要说下Makefile
objs:=head.oinit.onand.omain.onand.bin:$(objs)arm-linux-ld-Tnand.lds$^-onand_elfarm-linux-objcopy-Obinary-Snand_elf$@%.o:%.Sarm-linux-gcc-c$<-o$@%.o:%.carm-linux-gcc-c$<-o$@clean:rm-fnand.bin*.onand_elf
平时写的Makefile不一样,这里使用了一个名为nand.lds的链接脚本,这样做主要是为了试验让编译好的程序在链接时存放的地址和理论运行地址都不同且不在同一个存储设备上,方便看试验效果。
nand.lds
SECTIONS{first0x00000000:{head.oinit.onand.o}second0x30000000:AT(4096){main.o}}
链接脚本上的第一段是放head.S init.c nand.c编译出的内容,从0地址开始存放和执行,而main.o则是需要从nand flash手动复制到sdram中去执行。
实现的效果如图:
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。