分类: LINUX
2014-04-26 18:50:30
原文地址:(五)、 存储器控制 作者:machoe
有了前几节的基础,相信大家对ARM程序的开发有了一定的了解和掌握,也会产生浓厚的兴趣。但细心的读者肯定会问:为什么我们每次都能将编译好的程序直接下载到SDRAM中呢?难道它不用我们对其进行操作就可以运行吗?
其实,SDRAM并不是想象的那么神奇,在我们使用它的时候,我们肯定要为他做一些初始化和配置,那为什么我们前几节的代码中没有涉及到SDRAM呢?那是因为我们利用的是天嵌科技的U-BOOT启动的开发板,又利用U-BOOT将程序下载到开发板中,SDRAM初始化和配置等工作都由U-BOOT为我们准备好了,因此,我们就可以直接拿来用了。
本章介绍了一些存储器、存储器控制器的相关概念和具体的TQ2440开发板上SDRAM的使用方法。并通过一个实例来告诉大家如何使用存储器。建议读本章的朋友配合《S3C2440手册》的第5章,进行学习。
、单位
我的TQ2440开发板的硬件配置是256MB的NandFlash、64MB Sdram、2MB NorFlash。这里请大家注意,单位我用的是MB,而有一些场合用的是Mb,这大写的B代表的是BYTE,也就是通常我们说的字节;而小写的b代表的是bit,也就是位。
下面请大家牢记:
括号内表明,我们需要多少个字节来表示这么大的空间,如:1KB,我们需要2^10个Byte来表示。
以后,我推荐大家尽量统一使用一个单位,例如上面的三个单位,我都使用MB,这样免得一不小心看错。
、S3C2440地址空间S3C2440 CPU共有27根地址线,ADDR0~ADDR26,因此它可以访问2^27大小的地址空间,这也正是2^7*2^20大小,128MB。在天嵌的论坛上曾有人提问过,手册上说可以访问1GB的大小,这是怎么做到的呢?
CPU除了这27根地址线外,还有8根“片选”,nGCS0~nGCS7,这8根“片选”也正好对应着CPU的BANK0~BANK7。加上这8根上,正好可以构成一个1GB大小的地址空间。
TQ2440开发板使用存储器控制器来控制外设,说得通俗一点,就是把外设的一些端口,寄存器映射到CPU的内部地址空间中,这样,我们对外设的操作就可以转向对CPU内部地址空间的操作,简化我们的操作,这里我不细讲,免得给大家弄糊涂了,我们每讲一种外设时,我们再对应该外设来详细说明,等所有的外设都讲过了,我相信大家的肯定就会清楚“用存储器控制器来控制外设”这句话的意思了。
、SDARMSDRAM:Synchronous Dynamic Random Access Memory,同步动态随机存储器,同步是指 Memory工作需要同步时钟,内部的命令的发送与数据的传输都以它为基准;动态是指存储阵列需要不断的刷新来保证数据不丢失;随机是指数据不是线性依次存储,而是自由指定地址进行数据读写。
这里给大家做一个知识补充:在我们现在所用的PC机中,所指的内存,其实就是SDRAM,只不过是他的升级版,如DDR内存,DDR2内存,DDR3内存等等,而且很多喜欢玩3D游戏的玩家肯定对显卡也很有研究,其实大部分显卡上的显存也是SDRAM的,那么DDR和SDRAM是什么关系呢?有什么区别呢?简单的说,DDR就是SDRAM的升级版。这里不多说,有兴趣的朋友可以阅读“推荐阅读”版块的内容。
另外,SDRAM在嵌入式开发中起什么作用呢?学过单片机的朋友肯定会知道,程序的运行需要有两个必备条件:一、要有能存储程序代码(BIN文件)的存储器;二、要有能够运行的RAM。单片机(以51单片机为例)内部集成了ROM和RAM,因此外围可以不必再扩展存储器,而对于S3C2440CPU,内部没有集成存储器,因此,我们必须要有外部扩展存储器来存储代码和运行程序。等大家学完了NAND FLASH、Nor FLASH和SDRAM后就会明白各个器件的作用了。
在这里,无论您的学习方向是硬件还是软件,我推荐的学习方法是都要先看一下硬件的连接,原理图,这样有助于理解。TQ2440是选用2片HY57V561620FTP-H组成64MB、32位的内存,每片32MB容量、16位数据总线。
看原理图之前,先来介绍一下CPU提供的一组用于SDRAM的信号:
1. SDRAM的时钟有效信号SCKE;
2. SDRAM的时钟信号SCLK0,SCLK1;
3. 数据掩码信号DQM0,DQM1,DQM2,DQM3;
4. SDRAM片选信号nSCS0(它与nGCS6是同一引脚的两个功能);
5. SDRAM行地址选通脉冲信号nSRAS;
6. SDRAM列地址选通脉冲信号nSCAS;
7. 写允许信号nWE(它不是专用于SDRAM的)。
SDRAM的内部是一个存储阵列,阵列就类似于表格一样,有行、列之分,这样我们要访问(读、写)一个单元,就要先指定一个行地址,一个列地址,这样就找到了该单元,这就是SDRAM的寻址的基本原理。这里的单元我们一般称为存储单元,而整个表格称为逻辑BANK(Logical Bank , L-BANK),一般每个SDRAM都会有4个L-BANK。如下图:有4个L-BANK,每个4Mx16位,并且分为X、Y也就是行和列。
SDRAM相关操作 、CPU操作SDRAM的一般步骤
1. CPU发出片选信号nSCS0,选中SDRAM芯片。
2. 用两根地址线选中L-BANK,对应芯片的BA0、BA1两引脚。
3. 对被选中芯片的L-BANK进行行、列寻址。
TQ2440开发板是由两块16位的SDRAM芯片并联组成32位的位宽,与CPU的32根数据线DATA0~DATA1相连。SDRAM是连接在BANK6上的,起始地址为0x30000000,大小为64MB,根所上面的公式可以得出:
64 MB = Byte
因此,地址空间为:0x30000000----- 0x33FFFFFF。
、存储器控制寄存器使用介绍BANK0~BANK5只需设置BWSCON和BANKCONx两个寄存器;BANK6、BANK7外接SDRAM时,除BWSCON和BANKCONx外,还要设置REFRESH、BANKSIZE、MRSRB6、MRSRB7四个寄存器。
1. BWSCON位宽和等待控制寄存器
该寄存器每4位控制一个BANK,最高4位控制BANK7,最低4位控制BANK0。
1) STx:启动/禁止SDRAM的数据掩码引脚,对于SDRAM,此位为0;
2) WSx:是否使用WAIT信号,通常设为0.
3) DWx:使用两位来选择位宽。00对应8位,01对应16位,10对应32位,11暂时保留。
比较特殊的是BANK0,它没有ST0和WS0,DW0为只读-------它是由硬件来决定的。BANK0只支持16位、32位两种模式,01代表16位,10代表32位。引脚OM[1:0]决定,如下图。
2. BANKCONx BANK控制寄存器
l 当x为0~5,这些寄存器控制相应BANK的外接设备访问时序。
l 当x为6、7时,
MT :用来选择外接设备的类型,00代表SRAM,11代表SDRAM。
Trcd :RAS To CAS delay 推荐使用01。
SCAN:SDRAM的列地址数,要根据硬件的实际情况来选择。00代表8位,01代表9位,10代表10位。
SRAM: 静态随机存储器,相比SDRAM,其优点是速度更快,不用动态刷新。
3. REFRESH 刷新控制寄存器
REFEN :0代表禁止SDRAM的刷新功能;1代表开启刷新功能。
TREFMD:刷新模式的选择,0代表CBR/Auto Refresh,1代表Self Refresh(自刷新,一般在系统休眠时使用)
Trp:时序设置,设为0
Tsrc:时序设置,设为11
Refresh Couner: 即,R_CNT此值需计算得出,公式为:
SDRAM的时钟频率为HCLK,在未使用PLL倍频前,就是晶振频率12MHz;刷新周期为见手册(HY57V561620F(L)T(P) Series)第5页,其中有一句“8,192 Refresh cycles / 64ms”。可以得出:刷新周期=64ms/8192=7.8125uS.最后可以得出:R_CNT=1955
4. BANKSIZE 寄存器
BURST_EN: 0代表ARM核禁止突发传输。1代表ARM核支持突发传输。
SCKE_EN: 0表示不使用SCKE信号令SDRAM进入省电模式;1表示使用SCKE信号令SDRAM进入省电模式。
SCLK_EN: 0表示时时刻刻都发出SCLK信号;1表示只在当访问SDRAM期间才发出SCLK信号。
BK76MAP:用来设置BANK6、BANK7的大小。
010=128MB;001=64MB;000=32MB;111=16MB;110=8MB;101=4MB;100=2MB
5. MRSRBx模式寄存器
这里只能修必CL[6:4]位,这需要根据硬件的实际情况,查手册来修改,此为SDRAM的时序设置。
000 = 1 clock 010 = 2 clock 011 = 3 clock
经过几面几章的复习,我想大家能成功的完成各章节实验。前几节的实验我的建议是利用TFTP手动下载到SDRAM中运行,而SDRAM的初始化工作一直由U-BOOT来完成。现在大家可以使用天嵌科技提供的U-BOOT来将代码直接下载到NAND FLASH中运行,但这里一定要注意,要确保SP的位置,如果直接下载到SDRAM中,确保SP一定要在SDRAM中;如果下载到NAND FLASH中,一定要在NAND FLASH的前4KB中,因此,如果下载到NAND FLASH中,要将SP设置为1024*4,即:“ldr sp,=1024*4”。
下载的方法是利用NOR FLASH启动,然后选择“n”,进入TFTP下载菜单,然后选择“a”键,就可以下载程序到NAND FLASH中了。请大家再次学习天嵌的手册教程,熟悉U-BOOT的使用。大家不要怕弄坏板子或里面烧写好的程序,学习就需要一个失败再尝试的过程,只有在不断的失败中总结经验,才能学到真东西,如果大家遇到麻烦,请天嵌论坛或我个人博客上发帖。
本章例程我将提供两个程序,一个是leds,一个是sdram。其中leds程序是流水灯程序,内容比较简单,只是单纯的实现了流水灯;而sdram程序是包涵了sdram的操作的流水灯程序。二者的区别是:leds下载到nand flash后,只能在nand flash中(4KB大小的SRAM)执行,而sdram程序下载到nand flash后,由于里面包涵了代码搬运和sdram初始化工作后,自动跳转到sdram中运行。
Leds程序相对比较简单,有了前几章的基础后,大家自行学习,我就不再讲了,这里,我主要讲一下sdram程序。下面我先列出代码。
@*************************************************************************
@ File:head.S
@ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@*************************************************************************
.equ MEM_CTL_BASE, 0x48000000 @SDRAM寄存器地址基址
.equ SDRAM_BASE, 0x30000000 @SDRAM连接在BANK6上,此为SDRAM内存空间地址
.text
.global _start
_start:
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
bl memsetup @ 设置存储控制器
bl copy_steppingstone_to_sdram @ 复制代码到SDRAM中
ldr pc, =on_sdram @ 跳到SDRAM中继续执行
on_sdram:
ldr sp, =0x34000000 @ 设置堆栈
bl main
halt_loop:
b halt_loop
disable_watch_dog:
@ 往WATCHDOG寄存器写0即可
mov r1, #0x53000000
mov r2, #0x0
str r2, [r1]
mov pc, lr @ 返回
copy_steppingstone_to_sdram:
@ 将Steppingstone的4K数据全部复制到SDRAM中去
@ Steppingstone起始地址为0x00000000,SDRAM中起始地址为0x30000000
mov r1, #0
ldr r2, =SDRAM_BASE
mov r3, #4*1024
1:
ldr r4, [r1],#4 @ 从Steppingstone读取4字节的数据,并让源地址加4
str r4, [r2],#4 @ 将此4字节的数据复制到SDRAM中,并让目地地址加4
cmp r1, r3 @ 判断是否完成:源地址等于Steppingstone的未地址?
bne 1b @ 若没有复制完,继续
mov pc, lr @ 返回
memsetup:
@ 设置存储控制器以便使用SDRAM等外设
mov r1, #MEM_CTL_BASE @ 存储控制器的13个寄存器的开始地址
adrl r2, mem_cfg_val @ 这13个值的起始存储地址
add r3, r1, #52 @ 13*4 = 54
1:
ldr r4, [r2], #4 @ 读取设置值,并让r2加4
str r4, [r1], #4 @ 将此值写入寄存器,并让r1加4
cmp r1, r3 @ 判断是否设置完所有13个寄存器
bne 1b @ 若没有写成,继续
mov pc, lr @ 返回
.align 4
mem_cfg_val:
@ 存储控制器13个寄存器的设置值
.long 0x22011110 @ 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 0x008C07A3 @ REFRESH
.long 0x000000B2 @ BANKSIZE
.long 0x00000030 @ MRSRB6
.long 0x00000030 @ MRSRB7
程序以_start为入口,先后调用关看门狗子程序、SDRAM寄存器设置子程序、代码搬动子程序,最后进入到SDRAM中调用MAIN函数。
SDRAM寄存器设置子程序采用的方法类似于我们初学单片机时使用的循环查表。R1中存放的是寄存器的基址0x48000000,关于寄存器的地址请大家查看手册,由于每个寄存器占4个字节,而且是挨着的,因此我们可以采用这种循环查表的方法,利用这个技巧,可以简化操作。R2存放的是表的首地址,表中的数据是用.long定义的立即数,具体的数值请大家根据上文的讲述和手册对照查看。R3存放的是第13个寄存器的地址,用来判断是否设置完毕。这里有一句代码“bne 1b”,新手可能会有所疑惑,简单的说,这句的意思就是跳转指令,跳转到哪呢?当然是“1b”了。那“1b”是什么意思呢,这里“1”代表标号,就是我们程序中的“1:”,其中“b”有“behind”的意思,就是说跳转到后面的“1:”处,但请注意,这里的“后面”可不是程序代码的“下面”,反而是“上面”,现在大家明白了吧。另外,除了“b”,还有“f”,代表“forward”,后面我们会用到。
程序中的leds.c文件比较简单,相信大家自己能理解。我就不多说了。这里请大家注意一下,head.s文件中,有一句“ ldr pc, =on_sdram”,这里为什么不用“b”呢?这个问题留给大家,希望大家广泛讨论。答案会在MMU一章公布。
别外重点是为什么经过了上面给pc赋值后就跳转到sdram中去了呢?在Makefile中有一句链接命令:arm-linux-ld –Ttext 0x30000000 head.o sdram.o –o sdram_elf。这里面确定了代码段的地址为0x30000000。这也对应着,链接时,入口(_start)地址为0x30000000,下面每条语句占4个字节,这样算来,“ldr pc,=on_sdram”就正好在0x30000010地址处了。
1. 请大家将leds程序烧写到nand flash中后,直接利用nand flash启动,观察流水灯的变化速率,如果过快,可以自行调整leds.c文件中的延时函数,将延时增大。
2. 再实验leds程序后,大家再将同样延时大小的sdram的程序下载到nand flash中,再观察流水灯的变化速度,这里肯定会有样一个现象:延时函数一样,但流水灯的速度却不一样,这是为什么呢?
3. 再将leds程序修改SP指针,使其指向SDRAM中,“ldr sp,=0x31000000”,再将其通过nor flash启动,烧写到sdram中,观察实验现象。
分析1:对比1和2的实验现象
这是由于程序的运行地址不一样,leds程序运行在nand flash中自带的前4KB的SRAM中,而sdram是将代码搬移到了sdram中运行。SRAM和SDRAM的性能不一样,SRAM速度略优于SDRAM,因此实验效果不一样。
分析2:对比2和3的实验现象
为什么leds下载到sdram中的速度是最快呢?这里我提示大家一下,板子是通过U-BOOT启动的,里面初始化了时钟,具体的原因,会在时钟一章节公布。
1.韦东山 《嵌入式LINUX应用开发完全手册》
2.三星 《S3C2440手册》
3.SDRAM介绍
4.SDRAM介绍
5.SDRAM介绍
6.SRAM介绍