大,为什么要在规定的小空间里和自己过不去呢!开发板上也一样,之前一直在一个4K大的Stepping stone里打转转,
可惜了那64MB的内存了。那么,今天就到拥有更广阔的天地里折腾一番吧。
s3c2440对外引出了27根地址线ADDR0~ADDR26,最多能寻址2的27次方,也就是128MB,但实际上s3c2440能够
寻址1G的地址空间,这是因为它还有8根片选信号线nGCS0~nGCS7,每根信号线对应一个128MB地址空间,这个空间被称作
BANK,所以s3c2440共有8个BANK -- BANK0~BANK7,当访问某个BANK时,其对应的nGCS信号引脚电平拉低,这和单
片机上的扩展IO的操作类同。s3c2440是32位的芯片,理论上支持2的32次方,即4GB的地址空间,除去上面8个BANK用掉的
1GB地址空间外,特殊功能寄存器占用了0x48000000~0x5b00001c这段地址空间,其它的地址空间没有被使用。
BANK0~BANK5可以连接ROM和SRAM类型的存储器,BANK6~BANK7可以连接ROM、SRAM、SDRAM类型的存储器,
最大支持256MB,mini2440将两片32MB,16bits位宽的SDRAM连接在了BANK6和BANK7上,并联构成64MB、32位宽的
内存。
在处理SDRAM内部的数据时需要先指定行,再指定列,即可访问到需要的数据,由行和列构成的矩阵称为存储阵列,
大家一般会把它叫作"L-BANK",但SDRAM里面不会只有一个存储阵列,这是因为如果只做一个存储阵列会造成严重的寻址
冲突并大幅度降低内存效率。所以一般人们都将内存分为4个存储阵列(这也是SDRAM规范中的最高L-BANK数量),访问时
每次只能访问一个,具体访问那个L-BANK可以通过内存的两个外接引脚BA0和BA1来决定,mini2440将addr24连接BA0、
addr25连接BA1,通过地址线24和地址线25来选择存储单元的4个L-BANK。
SDRAM只有13根地址线A0~A12,只能寻址8MB(2的13次方)的内存空间,由于每个内存内部划分成四个L-BANK,所以
通过addr24和addr25的配合,就可以寻址一个内存芯片的全部空间。开发板上一共有两片并联的32MB的SDRAM,每发送一次
地址信号,两片芯片都可以同时接收到,之后其中一片返回低16bits的数据,另一片返回高16bits的数据。下面是内存芯片和
cpu的引脚的连接表:
--------------------------------------------------------------------------------------------------------------------cpu引脚 内存芯片引脚 描述--------------------------------------------------------------------------------------------------------------------A2~A14 A0~A12 地址线--------------------------------------------------------------------------------------------------------------------D0~D31 DQ0~DQ31 数据线,其中一片的DQ0~DQ15连接D0~D15,另一片的DQ0~DQ15连接D16~D31--------------------------------------------------------------------------------------------------------------------A24,A25 BA0,BA1 L-BANK选择信号--------------------------------------------------------------------------------------------------------------------DQM0~DQM3 LDQM,UDQM 高低字节数据掩码信号--------------------------------------------------------------------------------------------------------------------SCKE SCKE 输入时钟有效信号--------------------------------------------------------------------------------------------------------------------SCLK SCLK 输入时钟--------------------------------------------------------------------------------------------------------------------nSCS0 nSCS 片选信号(和nGCS6是同一个引脚,只是功能不同)--------------------------------------------------------------------------------------------------------------------nSRAS nSRAS 行地址选通信号--------------------------------------------------------------------------------------------------------------------nSCAS nSCAS 列地址选通信号--------------------------------------------------------------------------------------------------------------------nWE nWE 写入有效信号--------------------------------------------------------------------------------------------------------------------
存储控制器的寄存器部分这里略过。
下面是启动代码:
@*************************************************************************@ File:head.S@ 功能:关闭看门狗,初始化时钟,初始化内存,将Stepping stone的数据@复制到SDRAM, 然后跳到内存中继续运行main函数,循环点亮led灯。@************************************************************************* @看门狗寄存器.equ WTCON, 0x53000000 @看门狗控制寄存器.equ WTDAT, 0x53000004 @看门狗数据寄存器.equ WTCNT, 0x53000008 @看门狗计数寄存器@系统时钟寄存器.equ LOCKTIME, 0x4c000000 @变频锁定时间寄存器.equ MPLLCON, 0x4c000004 @MPLL寄存器.equ CLKDIVN, 0x4c000014 @分频比寄存器@内存寄存器.equ MEM_CTL_BASE, 0x48000000.equ SDRAM_BASE, 0x30000000 @定义64MB内存开始的地址.equ SDRAM_END, 0x34000000 @定义64MB内存结束的地址.text.global _start_start: bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 bl init_clock @初始化系统时钟 bl memsetup @ 设置存储控制器 bl copy2sdram @ 复制代码到SDRAM中 ldr pc, =on_sdram @ 跳到SDRAM中继续执行on_sdram: ldr sp, =SDRAM_END @ 设置堆栈,堆栈由高地址向低地址生长 bl mainhalt_loop: b halt_loopdisable_watch_dog: mov r1, #WTCON mov r2, #0x0 @ 往WATCHDOG寄存器写0即可 str r2, [r1] mov pc, lr @ 返回init_clock: @ 设置锁频时间 ldr r0, =LOCKTIME @取得LOCKTIME寄存器地址 ldr r1, =0x00ffffff @设置锁定时间 str r1, [r0] @将r1中的数据写入r0 @设置FCLK,HCLK,PCLK三者之间的比例,本来还需要设置CAMDIVN寄存器, @但这里设置成1:4:8,所以CAMDIVN使用默认值就可以了! ldr r0, =CLKDIVN @取得CLKDIVN寄存器地址 mov r1, #0x05 @设定比例 str r1, [r0] @修改CPU总线模式 mrc p15, 0, r1, c1, c0, 0 orr r1, r1, #0xc0000000 mcr p15, 0, r1, c1, c0, 0 @倍频到400MHz ldr r0, =MPLLCON @MPLL控制寄存器 ldr r1, =0x0005c011 str r1, [r0] mov pc, lr @ 返回copy2sdram: @ 将Steppingstone的4K数据全部复制到SDRAM中去 @ Steppingstone起始地址为0x00000000,SDRAM中起始地址为0x30000000 mov r1, #0 ldr r2, =SDRAM_BASE mov r3, #4*1024copyloop: ldr r4, [r1],#4 @ 从Steppingstone读取4字节的数据,并让源地址加4 str r4, [r2],#4 @ 将此4字节的数据复制到SDRAM中,并让目地地址加4 cmp r1, r3 @ 判断是否完成:源地址等于Steppingstone的未地址? bne copyloop @ 若没有复制完,继续 mov pc, lr @ 返回memsetup: @ 设置存储控制器以便使用SDRAM等外设 mov r1, #MEM_CTL_BASE @ 存储控制器的13个寄存器的开始地址 adrl r2, mem_cfg_val @ 这13个值的起始存储地址 add r3, r1, #52 @ 13*4 = 54initmemloop: ldr r4, [r2], #4 @ 读取设置值,并让r2加4 str r4, [r1], #4 @ 将此值写入寄存器,并让r1加4 cmp r1, r3 @ 判断是否设置完所有13个寄存器 bne initmemloop @ 若没有写成,继续 mov pc, lr @ 返回@4字节对齐.align 4 mem_cfg_val: @ 存储控制器13个寄存器的设置值 .long 0x22000000 @ BWSCON .long 0x00000700 @ BANKCON0 .long 0x00000700 @ BANKCON1 .long 0x00000700 @ BANKCON2 .long 0x00000700 @ BANKCON3 .long 0x00000700 @ BANKCON4 .long 0x00000700 @ BANKCON5 .long 0x00018005 @ BANKCON6 .long 0x00018005 @ BANKCON7 .long 0x008E04F5 @ REFRESH .long 0x000000B1 @ BANKSIZE .long 0x00000030 @ MRSRB6 .long 0x00000030 @ MRSRB7@******************************************************************************
C程序还是使用上次那个leds.c程序,这里就不再列出代码了!
然后是编译用的Makefile.
#******************************************************************************#Makefile#******************************************************************************sdram.bin : head.S leds.c arm-linux-gcc -c -o head.o head.S arm-linux-gcc -c -o leds.o leds.c arm-linux-ld -Ttext 0x30000000 head.o leds.o -o sdram_elf arm-linux-objcopy -O binary -S sdram_elf sdram.bin arm-linux-objdump -D -m arm sdram_elf > sdram.disclean: rm -f sdram.dis sdram.bin sdram_elf *.o#******************************************************************************
编译之后得到sdram.bin,下载到开发板上运行。可以看到led闪烁的速度比上次慢了很多,
这是因为外部的SDRAM的性能比内部的SRAM差很多。但内部的SRAM只有4k,如果程序大于4k,
就需要想办法将存储在NAND中的代码复制到SDRAM中去运行。
注意:上面的代码只是把SRAM中的代码复制到SDRAM中运行,并不是将NAND Flash中的