1.DDR介绍
DDR,是SDRAM的改进,是双通道的SDRAM,
SDRAM是同步动态随机访问存储器。
SDRAM与SRAM相对于,二者的特点是:
SDRAM 需要初始化,使用时许访问,价格便宜。
SRAM 不需要初始化,价格贵。
与之相似的还有 Norflash 和 Nandflash
RAM之所掉电丢失数据,是因为RAM使用电容实现0,1二进制表示。
最后,还需要了解,地球上制造RAM的公司多,但是一线大厂只有几家,一线大厂的RAM各有不同,但是二线厂商的RAM都向一线厂商靠,所以二线厂商的DDR如果是使用三星的SoC,那么直接使用三星的DDR初始化程序都可能成功初始化二线厂商的DDR。
2.初始化DDR
(1)首先看原理图
看原理图的目的:
获得板子上的DDR芯片名
知道板子上的DDR是怎么接的
下面是 SoC 上给DDR的接口:
可以看出:
这款SoC有三个接口,
每个接口的先分为三类:数据线,地址线,时序线,
另外注意到地址线并不是 32根,而是14根,这说明一个接口可以连接的内存片存储最大值为 2^14B
然后再看接的内存片的原理图:
可以看出:
实际使用SoC内存接口为:Port1, Port2
芯片正好与SoC的接口对齐,也分为:数据线,地址线,时序线,并且注意BA0,BA1,BA2位片选线(后面会用)
芯片无晶振,说明使用SoC提供频率,由于SoC频率低,所以芯片本身需要倍频,
一片内存位宽为16位,使用两片构成32位。
芯片信号:K4T1G164QQ
总结:
通过查看原理图,了解开发板上芯片和SoC的连接情况,和芯片编号。
接下来利用芯片编号,找到芯片的手册,大致了解下芯片情况。
芯片编号为 K4T1G164QQ
芯片手册是各种规格的集合,需要根据芯片编号得知自己的芯片规格,再看对应的说明
芯片编号的解读方法如下:
K4T1G164QQ
1 :K 说明是三星的
2: 4 说明是DRAM
3:T 是 DDR2
4:1G 密度和刷新速度,为 1Gb也就是 128MB
5:16 位宽为16bit
6:4 8Bank
7:电压
后面没用了
总结为 : DDR2 1Gb 16bit 8Bank
根据上面数据找到这张图
现在需要知道内存是如何确定每个 bit 的位置的。
内存是多个 Bank组成,每个Bank是个二维地址有col和row确定的存储单元,这样就构成了三维的矩阵。
所以每个bit先要确定 Bank,然后再是 row 和 col。
对应上面的图可以知道,一共17根线传输这些地址数据,3位用来选Bank(BA0,BA1,BA2),也就 8 Bank
10位 Col,14位Row,所以 1Bank 就是 2^24 B = 16MB
8Bank = 128MB
注意Col,Row确定一个Byte,内存的最小单位是Byte,那为什么我们可以操作bit呢?原因是我们使用寄存器和移位器来操作bit,与DDR无关。
完成了上面工作,对板子上的内存芯片就有了足够的认识,
就下来应该结合 SoC UM 和 参考代码进行分析,
因为知道使用的是DDR2,所以看SoC UM 对DDR2初始化的部分,一共有27步,应该结合参考代码看。
(1)设置驱动强度
/* DMC0 Drive Strength (Setting 2X) */ ldr r0, =ELFIN_GPIO_BASE ldr r1, =0x0000AAAA str r1, [r0, #MP1_0DRV_SR_OFFSET] // 寄存器中对应0b10,就是2X ldr r1, =0x0000AAAA str r1, [r0, #MP1_1DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP1_2DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP1_3DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP1_4DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP1_5DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP1_6DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP1_7DRV_SR_OFFSET] ldr r1, =0x00002AAA str r1, [r0, #MP1_8DRV_SR_OFFSET] /* DMC1 Drive Strength (Setting 2X) */ ldr r0, =ELFIN_GPIO_BASE ldr r1, =0x0000AAAA str r1, [r0, #MP2_0DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP2_1DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP2_2DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP2_3DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP2_4DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP2_5DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP2_6DRV_SR_OFFSET] ldr r1, =0x0000AAAA str r1, [r0, #MP2_7DRV_SR_OFFSET] ldr r1, =0x00002AAA str r1, [r0, #MP2_8DRV_SR_OFFSET]
(2)设置PLL,因为DDR使用SoC提供时钟,频率太低,需要倍频,所以需要使用PLL
/* DMC0 initialization at single Type*/ ldr r0, =APB_DMC_0_BASE ldr r1, =0x00101000 @PhyControl0 DLL parameter setting, manual 0x00101000 str r1, [r0, #DMC_PHYCONTROL0] ldr r1, =0x00000086 @PhyControl1 DLL parameter setting, LPDDR/LPDDR2 Case str r1, [r0, #DMC_PHYCONTROL1] ldr r1, =0x00101002 @PhyControl0 DLL on str r1, [r0, #DMC_PHYCONTROL0] ldr r1, =0x00101003 @PhyControl0 DLL start str r1, [r0, #DMC_PHYCONTROL0] find_lock_val: ldr r1, [r0, #DMC_PHYSTATUS] @Load Phystatus register value and r2, r1, #0x7 cmp r2, #0x7 @Loop until DLL is locked bne find_lock_val and r1, #0x3fc0 mov r2, r1, LSL # orr r2, r2, #0x100000 orr r2 ,r2, #0x1000 orr r1, r2, #0x3 @Force Value locking str r1, [r0, #DMC_PHYCONTROL0]
这一步和时序相关,看不懂
ldr r1, =0x0FFF2010 @ConControl auto refresh off str r1, [r0, #DMC_CONCONTROL]
对应文档中的这几步
接下来
#define DMC0_MEMCONFIG_0 0x20F01323 // MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed#define DMC1_MEMCONTROL 0x00202400 // MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
ldr r1, =DMC0_MEMCONTROL @MemControl BL=4, 1 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
strr1, [r0, #DMC_MEMCONTROL]
ldrr1, =DMC0_MEMCONFIG_0@MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
strr1, [r0, #DMC_MEMCONFIG0]
这里按照硬件连接情况设置。
接下来比较重要
ldr r1, =DMC0_MEMCONFIG_1 @MemConfig1 #define DMC0_MEMCONFIG_1 0x30F00312 // MemConfig1 默认值 str r1, [r0, #DMC_MEMCONFIG1]
看UM
可以看出,31-24设置内存的基地址,基地址该如何设置应该看SoC安排的Memory Map
地址向上生长,DRAM0使用 0x3000_0000
23-16是使用掩码的方式设置长度,根据 Memory Map 可以看出DRAM0长度最大0x3FFF_FFFF,这里设置的也是这个
其他的按照前面查的数据填。
其他的代码基本上时序,没得可以变的,也看不懂。
这样 DDR的初始化就完了。
总结:
通过这次初始化,学习如何使用芯片手册,SoC手册,参考代码,原理图。
简单说是:
先看原理图,了解SoC和芯片实际连接,和使用的芯片类型。
再看芯片手册,了解下芯片,当然前提需要知道硬件的基本常识。
再依照参考代码看SoC手册,期间需要结合芯片手册确定某些特殊数据。
可以看出 DDR 的初始化基本上没得可以改的,也不会改,
需要注意的就是内存的起始地址和长度的设置部分,这里可以变通。