根据韦东山修改的mini2440 nand flash裸机程序
时间:11-21
来源:互联网
点击:
说明
开发板:mini2440
Nand flash:K9F2G08U0B2,56M
本程序实现功能:我是参考韦东山的第8章的裸机程序,但是他的nand flash型号是64MB的K9F12080M,所以我依照他的程序加以修改,下载到nand flash,从nand flash实现将main.c程序复制到sdram中执行。
参考书:《嵌入式应用开发完全手册》
《ARM处理器裸机开发实战---机制而非策略》
知识点梳理
页的绝对地址与相对地址
在nand.c中有一个函数void RdNF2SDRAM(),它的功能是将nand flah的内容复制到sdram,如下:
![](../img/eep/emb/emb-58936e0lld04ya5a.jpg)
nand flash的页读取函数原型是void nf_readpage(unsigned int block,unsigned int page,unsigned char *dstaddr),它的功能是从nand flash的第block块的第page页读取1页(对于K9F2G来说,1页等于2KB)的内容,存放到指针dstaddr所指的地址处。有的人可能就会说了,既然nf_readpage可以读取1页的数据到指定的地址处,而sdram的地址是0x30000000,那直接可以使用它将nand flash的代码复制到sdram去啊,答案当然是可以啊!但是有个前提,复制到sdram的内容必须在2KB以内,一旦超过了2KB,那就需要借用RdNF2SDRAM()函数了,相信这样解释就能明白这两个函数的区别于联系了。
再说说绝对地址与相对地址,首先知道k9f2g有2048个块,每个块有64个页,每页有2K字节。我们平常所说的第几块第几页就是相对地址,比如第2块第3页是相对地址。而绝对地址=块号*64+页号,例如前边的第2块第3页换成绝对地址就是131(131=2*64+3)。
下面解释一下RdNF2SDRAM()函数:
113行:从117行可以看出,这里的i指的是相对地址
114行:在nand flash内的起始地址,这里的4096表示的是字节,k9f2g内存大小是256Mbyte,这里之所以令start_addr=4096,是因为咱们在nand.lds文件中,将main.c文件的地址定义在了4096处。如下图:
![](../img/eep/emb/emb-58937gsfjjscmggk.jpg)
如果AT(4096)改为AT(5120),那么这里start_addr就等于5120。还要注意这里4096byte也就是4KB,为什么把他定义在nand flash的4KB之后呢,因为硬件电路会自动将nand flash里的前4KB的内容搬移到stepping stone中去执行,如果定义在3KB之后,main.c函数直接就执行了,哪里还用复制。
115行:定义了读取的nand flash的内容存放的位置,这里0x30000000是sdram的物理地址。
116行:定义了一共读取nand flash多少字节,这里定义的是1M,当然小小的一个main.c代码也就是不到2KB。
117-123行:这才是该函数的关键。因为nf_readpage函数是以页为单位进行读取的,每次读取2KB数据,因此,数据指针的移动是页对齐的,即每次移动一页。
117行:因为每page大小为2KB即2048Byte,这里start_addr>>11位,相当于start_addr/2048,这样就得到了给定地址多对应的页。
119行:这里的i是绝对地址,因为每块包含64页,i/64得到给定地址处于哪一块;id是该页在块内的第几页。
NAND FLASH地址周期:
下面咱们讲讲地址周期。对于mini2440的开发板,它的nand flash的接口电路如下图:
![](../img/eep/emb/emb-58938dk2odmuynpl.jpg)
![](../img/eep/emb/emb-58939hpbw2wh0vih.jpg)
从接口电路可以看到,地址线和数据线是复用的,接口线宽是8位,因此每次只能发送一个字节,又因为nand flash的地址是28位的,需要5个地址周期才能将地址发送完毕,如图1所示。发送完地址后,NAND FLASH内部的地址译码电路会自动将收到的地址进行组合,不需要我们关心,但是需要注意发送的顺序,按照先发送低地址,再发送高地址的顺序发送。
那么为什么是29根地址线,而不是28根或者30根呢?这里肯定有它的原因的。通常来说,nand flash的地址的表示形式为:
对于k9f2g来说,它有2048个块,故用11根地址线寻址(2^11=2048);每个块有64页,故用6根地址线寻址(2^6=64);每页有2048字节的数据和64字节的信息,也就是说它有2112字节,故用12根地址线寻址。理解了这里的话就很容易明白下面的发送地址了。
不论是在nand flash页读取函数还是也写入函数内,都需要向地址寄存器送地址,如下图:
![](../img/eep/emb/emb-58940enmb512oaif.jpg)
为什么是这样呢?由于页读取和写入函数均是以页为单位进行的,所以每次都要在页的第0个字节开始,也就是说页内偏移地址为0,所以对地址线的低12位设为0即可,如第93行,94行。
第95行,此时处于第3个地址周期因此需要发送blockpage(此时blockpage是页的绝对地址)的A12-A19位,因此,将blockpage与0xff相与即可。一定要注意页的绝对地址是A28-A12共同表示的,与A11-A0无关。
第96行,此时处于第3个地址周期因此需要发送blockpage(此时blockpage是页的绝对地址)的A20-A27位,因此,将blockpage右移8位,与0xff相与即可。
第97行,此时处于第3个地址周期因此需要发送blockpage(此时blockpage是页的绝对地址)的A28位,从图1可以看到,此时虽然是发送8位,但是只有第0位是有效的,其他位无效。因此,将blockpage右移16位,然后再与0x1相与,只保留第0位。
nand.lds代码解释:
如果代码小于4096字节,那么开发板启动后它们被自动复制进“Steppingstone”中;本实例的目的就是把一部分代码存放在NAND Flash地址4096之后,当程序启动通过NAND Flash控制器将它们读出来、执行。nand.lds就是实现这个目的的,即连接脚本nand.lds把代码分为两部分,nand.lds代码如下:
![](../img/eep/emb/emb-58941wwmuxfp2sfi.jpg)
第2行表示head.o、init.o、nand.o这3个文件的运行地址为0,它们在生成的映像文件中的偏移地址也为0(从0开始存放)
第3行表示main.o的运行地址为0x30000000,它在生成的映像文件中的偏移地址为4096。
此时生成的bin文件大小为4.10KB。
如果将第3行的AT(4096)去掉,其他的文件程序不变的话,make生成的bin文件大小为1.7KB。这样子对比就可以看出来AT真的起作用了。
mini2440开发板的时钟
Fin=12MHz FCLK=400MHz HCLK=100MHz PCLK=50MHz
所以FCLK:HCLK:PCLK=1:4:8,CLKdiv_VAL=5
Mdiv=127 Pdiv=2 Sdiv=1
编译生成bin文件,下载运行
本实验一共包含6个文件,分别为Makefile,head.S,init.c,main.c,nand.c,nand.lds,最后会把文件源代码全部贴出来。
将6个文件复制到虚拟机的linux系统中,然后make编译生成nand.bin文件,通过supervivi的v命令,结合DNW将它下载到板子中,然后板子从nand flash启动,可以看到4个
知识点梳理
![](../img/eep/emb/emb-58936e0lld04ya5a.jpg)
nand flash的页读取函数原型是void nf_readpage(unsigned int block,unsigned int page,unsigned char *dstaddr),它的功能是从nand flash的第block块的第page页读取1页(对于K9F2G来说,1页等于2KB)的内容,存放到指针dstaddr所指的地址处。有的人可能就会说了,既然nf_readpage可以读取1页的数据到指定的地址处,而sdram的地址是0x30000000,那直接可以使用它将nand flash的代码复制到sdram去啊,答案当然是可以啊!但是有个前提,复制到sdram的内容必须在2KB以内,一旦超过了2KB,那就需要借用RdNF2SDRAM()函数了,相信这样解释就能明白这两个函数的区别于联系了。
再说说绝对地址与相对地址,首先知道k9f2g有2048个块,每个块有64个页,每页有2K字节。我们平常所说的第几块第几页就是相对地址,比如第2块第3页是相对地址。而绝对地址=块号*64+页号,例如前边的第2块第3页换成绝对地址就是131(131=2*64+3)。
下面解释一下RdNF2SDRAM()函数:
113行:从117行可以看出,这里的i指的是相对地址
114行:在nand flash内的起始地址,这里的4096表示的是字节,k9f2g内存大小是256Mbyte,这里之所以令start_addr=4096,是因为咱们在nand.lds文件中,将main.c文件的地址定义在了4096处。如下图:
![](../img/eep/emb/emb-58937gsfjjscmggk.jpg)
如果AT(4096)改为AT(5120),那么这里start_addr就等于5120。还要注意这里4096byte也就是4KB,为什么把他定义在nand flash的4KB之后呢,因为硬件电路会自动将nand flash里的前4KB的内容搬移到stepping stone中去执行,如果定义在3KB之后,main.c函数直接就执行了,哪里还用复制。
![](../img/eep/emb/emb-58938dk2odmuynpl.jpg)
![](../img/eep/emb/emb-58939hpbw2wh0vih.jpg)
地址线 | [A28:A18] | [A17:A12] | [A11:A0] |
地址表示 | 块地址 | 页地址 | 页内偏移地址 |
不论是在nand flash页读取函数还是也写入函数内,都需要向地址寄存器送地址,如下图:
![](../img/eep/emb/emb-58940enmb512oaif.jpg)
为什么是这样呢?由于页读取和写入函数均是以页为单位进行的,所以每次都要在页的第0个字节开始,也就是说页内偏移地址为0,所以对地址线的低12位设为0即可,如第93行,94行。
第95行,此时处于第3个地址周期因此需要发送blockpage(此时blockpage是页的绝对地址)的A12-A19位,因此,将blockpage与0xff相与即可。一定要注意页的绝对地址是A28-A12共同表示的,与A11-A0无关。
第96行,此时处于第3个地址周期因此需要发送blockpage(此时blockpage是页的绝对地址)的A20-A27位,因此,将blockpage右移8位,与0xff相与即可。
第97行,此时处于第3个地址周期因此需要发送blockpage(此时blockpage是页的绝对地址)的A28位,从图1可以看到,此时虽然是发送8位,但是只有第0位是有效的,其他位无效。因此,将blockpage右移16位,然后再与0x1相与,只保留第0位。
![](../img/eep/emb/emb-58941wwmuxfp2sfi.jpg)
mini2440开发板的时钟
编译生成bin文件,下载运行
mini2440nandflash裸机程 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)