《朱老师物联网大讲堂》学习笔记
学习地址:www.zhulaoshi.org
汇编初始化SDRAM
在这里,我们的那个链接脚本中想要重定位的地址修改了,这个地址是SDRAM中的地址,
修改为0x20000000
在我们那个start.S文件中,我们在开关icache和重定位代码之间,增加了初始化SDRAM的代码,
是通过函数sdram_asm_init来实现的,
在正式讲解这个函数之前,先说明一下,
汇编实现的函数,返回要手动去做,
比如可以这样:mov pc, lr
DDR的初始化和SOC(里面的DDR控制器)有关,比如寄存器,
也和开发板使用的DDR芯片有关,不过这个问题不大,因为芯片标准比较一致,而且一般都是原厂给设置参数,
和开发板设计时的连接方式也有关,比如我们这里是4片内存芯片,不过连接方式和对内存需要会有所不同。
初始化步骤在数据手册里面,
有27个步骤,见P598.
在我们这个S5PV210开发板上,初始化分DRAM0 和DRAM1
下面的图就是设置步骤,步骤还是挺多的,不过里面涉及时序等的计算,其实已经不是我们这里的主题了。
下面是DRAM初始化的代码,很多,而且由于很多参数,我们难以去计算,
都是参考原厂提供的代码,因此能看多少是多少,
#include "s5pv210.h"
#if 1
#define DMC0_MEMCONTROL 0x00202400 // MemControl BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off
#define DMC0_MEMCONFIG_0 0x20F01323 // MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_1 0x30F00312 // MemConfig1 默认值
#define DMC0_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
#define DMC0_TIMING_ROW 0x28233287 // TimingRow for @200MHz
#define DMC0_TIMING_DATA 0x23240304 // TimingData CL=3
#define DMC0_TIMING_PWR 0x09C80232 // TimingPower
#define DMC1_MEMCONTROL 0x00202400 // MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
#define DMC1_MEMCONFIG_0 0x40F01323 // MemConfig0 512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC1_MEMCONFIG_1 0x60E00312 // MemConfig1
#define DMC1_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
#define DMC1_TIMING_ROW 0x28233289 // TimingRow for @200MHz
#define DMC1_TIMING_DATA 0x23240304 // TimingData CL=3
#define DMC1_TIMING_PWR 0x08280232 // TimingPower
#endif
#if 0
#define DMC0_MEMCONTROL 0x00212400 // MemControl BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off
#define DMC0_MEMCONFIG_0 0x20E01323 // MemConfig0 512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_1 0x40F01323 // MemConfig1
#define DMC0_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
#define DMC0_TIMING_ROW 0x28233287 // TimingRow for @200MHz
#define DMC0_TIMING_DATA 0x23240304 // TimingData CL=3
#define DMC0_TIMING_PWR 0x09C80232 // TimingPower
#define DMC1_MEMCONTROL 0x00202400 // MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
#define DMC1_MEMCONFIG_0 0x40C01323 // MemConfig0 512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC1_MEMCONFIG_1 0x00E01323 // MemConfig1
#define DMC1_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
#define DMC1_TIMING_ROW 0x28233289 // TimingRow for @200MHz
#define DMC1_TIMING_DATA 0x23240304 // TimingData CL=3
#define DMC1_TIMING_PWR 0x08280232 // TimingPower
#endif
.global sdram_asm_init
sdram_asm_init:
ldr r0, =0xf1e00000
ldr r1, =0x0
str r1, [r0, #0x0]
像这种寄存器的设置,你在数据手册中,
找不到有意义的描述,
可以理解为怎么设置都行?
/* DMC0 Drive Strength (Setting 2X) */
设置IO端口驱动强度,
总线的物理表现就是很多个引脚,
设置合适的驱动以抗干扰,
数据手册P200
ldr r0, =ELFIN_GPIO_BASE
此处ro = 0xE0200000,
可以理解为定了一个基地址,
还有很多类似的宏定义在我们的.h文件里面
#include "s5pv210.h"
ldr r1, =0x0000AAAA
str r1, [r0, #MP1_0DRV_SR_OFFSET]
0xAAAA = 1010 1010 1010 1010
高16位,没说,就设为0吧,
寄存器中对应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]
这些驱动强度的设置,设置方法都是一样的,
/* DMC0 initialization at single Type*/
设置时钟,对着手册来看这些值,看都对应吧
这里的功能主要是开启DLL(dram pll)
然后等待锁存,
对应27步中的2~4步。
注意00101000这个数值,你怎么样从数据手册中看到,
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 #18
orr r2, r2, #0x100000
orr r2 ,r2, #0x1000
orr r1, r2, #0x3 @Force Value locking
str r1, [r0, #DMC_PHYCONTROL0]
#if 0 /* Memory margin test 10.01.05 */
orr r1, r2, #0x1 @DLL off
str r1, [r0, #DMC_PHYCONTROL0]
#endif
/* setting DDR2 */
ldr r1, =0x0FFF2010 @ConControl auto refresh off
str r1, [r0, #DMC_CONCONTROL]
ldr r1, =DMC0_MEMCONTROL @MemControl BL=4, 1 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
str r1, [r0, #DMC_MEMCONTROL]
ldr r1, =DMC0_MEMCONFIG_0 @MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
str r1, [r0, #DMC_MEMCONFIG0]
ldr r1, =DMC0_MEMCONFIG_1 @MemConfig1
str r1, [r0, #DMC_MEMCONFIG1]
ldr r1, =0xFF000000 @PrechConfig
str r1, [r0, #DMC_PRECHCONFIG]
ldr r1, =DMC0_TIMINGA_REF @TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
str r1, [r0, #DMC_TIMINGAREF]
ldr r1, =DMC0_TIMING_ROW @TimingRow for @200MHz
str r1, [r0, #DMC_TIMINGROW]
ldr r1, =DMC0_TIMING_DATA @TimingData CL=3
str r1, [r0, #DMC_TIMINGDATA]
ldr r1, =DMC0_TIMING_PWR @TimingPower
str r1, [r0, #DMC_TIMINGPOWER]
ldr r1, =0x07000000 @DirectCmd chip0 Deselect
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00020000 @DirectCmd chip0 EMRS2
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00030000 @DirectCmd chip0 EMRS3
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (MEM DLL on, DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00000542 @DirectCmd chip0 MRS (MEM DLL reset) CL=4, BL=4
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00000442 @DirectCmd chip0 MRS (MEM DLL unreset)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00010780 @DirectCmd chip0 EMRS1 (OCD default)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (OCD exit)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x07100000 @DirectCmd chip1 Deselect
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01100000 @DirectCmd chip1 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00120000 @DirectCmd chip1 EMRS2
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00130000 @DirectCmd chip1 EMRS3
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00110400 @DirectCmd chip1 EMRS1 (MEM DLL on, DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00100542 @DirectCmd chip1 MRS (MEM DLL reset) CL=4, BL=4
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01100000 @DirectCmd chip1 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05100000 @DirectCmd chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05100000 @DirectCmd chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00100442 @DirectCmd chip1 MRS (MEM DLL unreset)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00110780 @DirectCmd chip1 EMRS1 (OCD default)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00110400 @DirectCmd chip1 EMRS1 (OCD exit)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x0FF02030 @ConControl auto refresh on
str r1, [r0, #DMC_CONCONTROL]
ldr r1, =0xFFFF00FF @PwrdnConfig
str r1, [r0, #DMC_PWRDNCONFIG]
ldr r1, =0x00202400 @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
str r1, [r0, #DMC_MEMCONTROL]
// 上面是DRAM0初始化步骤
/*******************************************************************************************/
// 下面是DRAM1初始化步骤,两者没有联系,是并列的。
/* DMC1 initialization */
ldr r0, =APB_DMC_1_BASE
ldr r1, =0x00101000 @Phycontrol0 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL0]
ldr r1, =0x00000086 @Phycontrol1 DLL parameter setting
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_val1:
ldr r1, [r0, #DMC_PHYSTATUS] @Load Phystatus register value
and r2, r1, #0x7
cmp r2, #0x7 @Loop until DLL is locked
bne find_lock_val1
and r1, #0x3fc0
mov r2, r1, LSL #18
orr r2, r2, #0x100000
orr r2, r2, #0x1000
orr r1, r2, #0x3 @Force Value locking
str r1, [r0, #DMC_PHYCONTROL0]
#if 0 /* Memory margin test 10.01.05 */
orr r1, r2, #0x1 @DLL off
str r1, [r0, #DMC_PHYCONTROL0]
#endif
/* settinf fot DDR2 */
ldr r0, =APB_DMC_1_BASE
ldr r1, =0x0FFF2010 @auto refresh off
str r1, [r0, #DMC_CONCONTROL]
ldr r1, =DMC1_MEMCONTROL @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
str r1, [r0, #DMC_MEMCONTROL]
ldr r1, =DMC1_MEMCONFIG_0 @MemConfig0 512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
str r1, [r0, #DMC_MEMCONFIG0]
ldr r1, =DMC1_MEMCONFIG_1 @MemConfig1
str r1, [r0, #DMC_MEMCONFIG1]
ldr r1, =0xFF000000
str r1, [r0, #DMC_PRECHCONFIG]
ldr r1, =DMC1_TIMINGA_REF @TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
str r1, [r0, #DMC_TIMINGAREF]
ldr r1, =DMC1_TIMING_ROW @TimingRow for @200MHz
str r1, [r0, #DMC_TIMINGROW]
ldr r1, =DMC1_TIMING_DATA @TimingData CL=3
str r1, [r0, #DMC_TIMINGDATA]
ldr r1, =DMC1_TIMING_PWR @TimingPower
str r1, [r0, #DMC_TIMINGPOWER]
ldr r1, =0x07000000 @DirectCmd chip0 Deselect
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00020000 @DirectCmd chip0 EMRS2
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00030000 @DirectCmd chip0 EMRS3
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (MEM DLL on, DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00000542 @DirectCmd chip0 MRS (MEM DLL reset) CL=4, BL=4
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00000442 @DirectCmd chip0 MRS (MEM DLL unreset)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00010780 @DirectCmd chip0 EMRS1 (OCD default)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (OCD exit)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x07100000 @DirectCmd chip1 Deselect
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01100000 @DirectCmd chip1 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00120000 @DirectCmd chip1 EMRS2
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00130000 @DirectCmd chip1 EMRS3
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00110440 @DirectCmd chip1 EMRS1 (MEM DLL on, DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00100542 @DirectCmd chip1 MRS (MEM DLL reset) CL=4, BL=4
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x01100000 @DirectCmd chip1 PALL
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05100000 @DirectCmd chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05100000 @DirectCmd chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00100442 @DirectCmd chip1 MRS (MEM DLL unreset)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00110780 @DirectCmd chip1 EMRS1 (OCD default)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x00110400 @DirectCmd chip1 EMRS1 (OCD exit)
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x0FF02030 @ConControl auto refresh on
str r1, [r0, #DMC_CONCONTROL]
ldr r1, =0xFFFF00FF @PwrdnConfig
str r1, [r0, #DMC_PWRDNCONFIG]
ldr r1, =DMC1_MEMCONTROL @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
str r1, [r0, #DMC_MEMCONTROL]
// 函数返回
mov pc, lr
下面是dram相关数据手册的一些资料,
The controller includes an advanced embeddedscheduler(调度器) to utilize(使用) memory device efficiently and an optimized(最佳化)pipeline(流水线)stage(阶段) to minimize latency(延迟).
•Compatible(兼容) with JEDEC DDR2, low power DDR and low power DDR2 SDRAMspecification(规范)
• Supports QoSscheme(方案) to ensure low latency for some applications
•Supports excellent chip/bankinterleaving(交错) and memory interrupting
•Supports outstanding exclusive(暂且解释为:专用的,独家的) accesses
An Initialization procedure consists of PHY(物理的) DLL initialization,
the controller must assert(维护) and hold CKE to a logic low level.
bit-fields(字段,位域)
13. Confirm whether stable clock isissued(发出) minimum 200us after power on
17. Issue an EMRS2command using the DirectCmd register to program(设置,编排) the operating parameters(参数).
26. If there are two external memory chips, perform(执行) steps 14~25 for chip1 memory device.
If OCD calibration(校准) is not used, issue an EMRS command to set OCD Calibration Default.
The difference between the linear(线性) mapping(映射) method and the interleaved(交叉存取) method is that the bank and
row order is different.