JZ2440 SDRAM的使用
文章目录
在学习SDRAM之前,最好看一遍这篇经典的关于SDRAM工作原理的介绍:
高手进阶,终极内存技术指南——完整.pdf
链接:https://pan.baidu.com/s/1XPwdu-Gcd7j8YLHbOH53yg
提取码:judz
然后再去配置S3C2440上的内存控制器就会觉得很简单。
S3C2440的内存地址映射
地址 | 非NAND启用 | NAND启动 |
---|---|---|
0X40000000 | Boot internal SRAM (4KB) | ------ |
0X38000000 | SROM/SDRAM(nGCS7) | SROM/SDRAM(nGCS7) |
0X30000000 | SROM/SDRAM(nGCS6) | SROM/SDRAM(nGCS6) |
0X28000000 | SROM(nGCS5) | SROM(nGCS5) |
0X20000000 | SROM(nGCS4) | SROM(nGCS4 |
0X18000000 | SROM(nGCS3) | SROM(nGCS3 |
0X10000000 | SROM(nGCS2) | SROM(nGCS2) |
0X08000000 | SROM(nGCS1) | SROM(nGCS1) |
0X00000000 | SROM(nGCS0) | Boot internal SRAM (4KB) |
启动方式 | OM[1:0]=01,10 | OM[1:0]=00 |
JZ2440上的SDRAM大小为64M,挂载在BANK6上,片选引脚为nGCS6。
内控控制器的配置
BWSCON
BWSCON的全称是BUS WIDTH & WAIT CONTROL REGISTER,用于内存带宽和等待信号的配置。用到的SDMRAM在BANK6上,因此只需配置ST6、WS6、DW6三个域。
ST6:当使用SRAM时才考虑这个域的配置,使用SDRAM时按默认配置就好。
WS6:等待信号的使能,由于现在的内存速度足够快,在读数据时不需要内存控制器等待,选择0。
DW6:BANK6的带宽,选择32位。
BANK7没有用到,可以配置为和BANK6一样,也可以不配置。
最后BWSCON=0X22000000或0X02000000
BANKCON0~BANKCON5
不需要配置
BANKCON6
MT:BANK6的存储类型,用的是SDRAM,选择11B
配置MT=11B后就只需要关注BANKCON6的低4位了。
Trcd:这个域的配置表示的是发送行有效命令到列有效命令之间的时间间隔。
在发送列读写命令时必须要与行有效命令有一个间隔,这个间隔被定义为tRCD,即RAS to CAS Delay(RAS至CAS延迟),可以理解为行选通周期,这应该是根据芯片存储阵列电子元件响应时间(从一种状态到另一种状态变化的过程)所制定的延迟。
芯片手册上说明tRCD的最大值为20ns,这里设定为最大值,SDRAM使用的时钟是HCLK,频率为100MHz,因此Trcd=00B即设定为20ns。
SCAN:列地址的位数。直接在芯片手册(EM63A165TS)搜索column address,可以得到:
即A0~A8是列地址,因此为9位。SACN设置为01B。
最后BANKCON6=0X00018001。
BANKCON7=BANKCON6。
REFRESH
之所以称为DRAM,就是因为它要不断进行刷新(Refresh)才能保留住数据,因此它是DRAM最重要的操作。
REFRE:肯定要使能刷新操作。
TREFMD:
刷新操作分为两种:自动刷新(Auto Refresh,简称AR)与自刷新(Self Refresh,简称SR)。
对于AR, SDRAM内部有一个行地址生成器(也称刷新计数器)用来自动的依次生成行地址。
SR则主要用于休眠模式低功耗状态下的数据保存,这方面最著名的应用就是STR(Suspend to RAM,休眠挂起于内存)。
这里不使用低功耗模式,故TREFMD=0B,使用自动刷新。
Trp:预充电时间。其实就是读取不同行之间的时间间隔。
L-Bank关闭现有工作行,准备打开新行的操作就是预充电(Precharge)。
在发出预充电命令之后,要经过一段时间才能允许发送RAS行有效命令打开新的工作行,这个间隔被称为tRP(Precharge command Period,预充电有效周期)。
直接在芯片手册上搜索trp,有一个相关值的推荐表:
设定tRP为20ns,即Trp=00B.
Tsrc:这个值经过搜索只有在S3C2440出现,芯片手册上没有,看一下Description:
Trc=Tsrc+Trp,其中Trc如下:
那就把tRC设定为70ns,然后反解出Tsrc=50ns,则Tsrc=01B.
Refresh Conuter:
这里主要是在芯片手册上查看Refresh period的值:
8192个刷新周期是64ms,则一个刷新周期是7.8μs,计算出Refresh count是1269=0x4F5.
最后REFRESH=0x008404f5。
BANKSIZE
BURST_EN:使能突发传输
突发(Burst)是指在同一行中相邻的存储单元连续进行数据传输的方式,连续传输所涉及到存储单元(列)的数量就是突发长度(Burst Lengths,简称BL)。
SCKE_EN:设置为1,不解释
SCLK_EN:设置为推荐值1
BK76MAP:SDRAM大小为64M,选择001B
最后BANKSIZE=0XB1。
MRSR
WBL:突发长度选择固定,第二个值为reserved,也没得选
TM:只能选00B
CL:CL是SDRAM很重要的参数
在选定列地址后,就已经确定了具体的存储单元,剩下的事情就是数据通过数据I/O通道(DQ)输出到内存总线上了。但是在CAS发出之后,仍要经过一定的时间才能有数据输出,从CAS与读取命令发出到第一笔数据输出的这段时间,被定义为CL(CAS Latency,CAS潜伏期)。由于CL只在读取时出现,所以CL又被称为读取潜伏期(RL,Read Latency)。CL的单位与tRCD一样,为时钟周期数,具体耗时由时钟频率决定。
一般这么重要的参数在芯片手册的“KEY FEATURES ”就能看到:
设置CL为2个时钟周期。CL=010B。
BT:只能选0
BL:只能选0
MRSR=0x00000020。
SDRAM初始化函数
void sdram_init(void)
{
BWSCON = 0X22000000;
BANKCON6 = 0X00018001;
BANKCON7 = 0X00018001;
REFRESH = 0X008404F5;
BANKSIZE = 0X000000B1;
MRSRB6 = 0X00000020;
MRSRB7 = 0X00000020;
}
测试SDRAM是否初始化成功
如果初始化成功了就能往SDRAM上写值和读值。
int sdram_test(void)
{
volatile unsigned char *p = (volatile unsigned char *)0X30000000;
int i;
for (i = 0; i < 1000; i++)
p[i] = 0X55;
for (i = 0; i < 1000; i++) {
if (p[i] != 0X55)
return -1;
}
return 0;
}
有关Makefile的注意事项
Makefile文件如下:
all:
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o init.o init.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 start.o led.o uart.o init.o main.o -o sdram.elf
arm-linux-objcopy -O binary -S sdram.elf sdram.bin
arm-linux-objdump -D sdram.elf > sdram.dis
clean:
rm *.bin *.dis *.elf *.o
要注意链接那一行一定要将start.o放在最开始,链接应该默认是按.o文件的顺序来的。