4.1 nand flash启动u-boot
nand flash 启动的时候,CPU 需要将 nand flash 中前面 4KB 的内容复制到 SRAM 中执行,然后将 NAND Flash 中的所有内容拷贝到 SDRAM中。
前4 KB 的拷贝 是硬件自动执行的。
4.1.1 地址空间
原理图如下:
nand flash 只有数据总线,并没有像 SDRAM 一样有地址总线。这样就有两种寻址方式就不同。
SDRAM 或 网卡、片内4K内存 都是地址总线接到 2440 上,他们的地址都是 CPU可以看到的,都是CPU发出来的,这为 CPU 统一编址。
nand flash 上页存在地址空间(0~256 M),nand flash 上的 0 地址 和 CPU 上的 0地址是不同的。
nand flash 地址都是通过 数据总线来发送的。
JZ2440板子上用的是大页的 nand flash,大页是指一个页里面有 2K 字节,小页只有 512 字节。结构如下图:
一页分为 2K 字节 + 64字节的OOB,一块的大小为 128K + 4K byte,128/2 = 64 页组成一块。
OOB 在大多数时候不参与编址。
4.1.2 nand flash 操作
CPU 先发出命令给 nandflash 要寻址,然后发送地址,然后再发送 读或写命令,在读或写数据。
nand flash 的命令如下图:
nandflash 引脚功能
- 从硬件上访问 NAND
- 发出命令:CLE引脚,命令发送到数据总线上
- 发出地址:ALE引脚,地址发送到数据总线上
- 传输数据:R/W
- 2440 控制
- 发出命令,寄存器 NFCMMD 寄存器
- 发出地址,寄存器 NFADDR 寄存器
- 读写数据,NFDATA
- 状态,NFSTAT
读流程如下:(其他流程见 nand flash 的芯片手册的第三章)
4.1.3 代码
nand.lds
1 SECTIONS { 2 // head.o init.o nand.o 存放在地址 0x0000 0000 处 3 firtst 0x00000000 : { head.o init.o nand.o} 4 // main.o 存放在地址 0x3000 0000 处 SDRAM 5 second 0x30000000 : AT(4096) { main.o } 6 }
head.S
1 @****************************************************************************** 2 @ File:head.s 3 @ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行 4 @****************************************************************************** 5 6 .text 7 .global _start 8 _start: 9 @函数disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定义 10 ldr sp, =4096 @设置堆栈,栈指向SRAM顶端 11 bl disable_watch_dog @关WATCH DOG 12 bl memsetup @初始化SDRAM 13 bl nand_init @初始化NAND Flash 14 15 @将NAND Flash中地址4096开始的1024字节代码(main.c编译得到)复制到SDRAM中 16 @nand_read_ll函数需要3个参数: 17 ldr r0, =0x30000000 @1. 目标地址=0x30000000,这是SDRAM的起始地址 18 mov r1, #4096 @2. 源地址 = 4096,连接的时候,main.c中的代码都存在NAND Flash地址4096开始处 19 mov r2, #2048 @3. 复制长度= 2048(bytes),对于本实验的main.c,这是足够了 20 bl nand_read @调用C函数nand_read 21 22 ldr sp, =0x34000000 @设置栈 23 ldr lr, =halt_loop @设置返回地址 24 ldr pc, =main @b指令和bl指令只能前后跳转32M的范围,所以这里使用向pc赋值的方法进行跳转 25 halt_loop: 26 b halt_loop
init.c
1 /* WOTCH DOG register */ 2 #define WTCON (*(volatile unsigned long *)0x53000000) 3 4 /* SDRAM regisers */ 5 #define MEM_CTL_BASE 0x48000000 6 7 void disable_watch_dog(); 8 void memsetup(); 9 10 /*上电后,WATCH DOG默认是开着的,要把它关掉 */ 11 void disable_watch_dog() 12 { 13 WTCON = 0; 14 } 15 16 /* 设置控制SDRAM的13个寄存器 */ 17 void memsetup() 18 { 19 int i = 0; 20 unsigned long *p = (unsigned long *)MEM_CTL_BASE; 21 22 /* SDRAM 13个寄存器的值 */ 23 unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON,这里将所有的内存配置都设置了,我们关注SDRAM DW6 0010 即可,为16位 24 0x00000700, //BANKCON0, 25 0x00000700, //BANKCON1 26 0x00000700, //BANKCON2 27 0x00000700, //BANKCON3 28 0x00000700, //BANKCON4 29 0x00000700, //BANKCON5 30 0x00018005, //BANKCON6,SDRAM 的设置,对照寄存器查看参数 31 0x00018005, //BANKCON7 32 0x008C07A3, //REFRESH,刷新寄存器,使能,刷新模式为自刷新,RAS改变时间为2个时钟, 33 //SDRAM Semi Row cycle time 为7个时钟 34 //Refresh Counte 为 11 1010 0011 = 931,Refresh period = (211-refresh_count+1)/HCLK 35 0x000000B1, //BANKSIZE,SDRAM 大小设置为 64M 36 0x00000030, //MRSRB6,SDRAM 模式设置 37 0x00000030, //MRSRB7 38 }; 39 40 for(; i < 13; i++) 41 p[i] = mem_cfg_val[i]; // 为每一个 内存控制器的寄存器设置参数 42 }