看了一套视频,感觉DDR这个部分将的非常细致也很好,于是把视频内容花了一个多星期作了总结。
这个视频就是不知道是谁讲的,做好事不留名啊~~~那位知道告诉我哈~~
平台:S5PV210
DDR: 兼容 三星的一块芯片——NT5TU64M16GG-DDR2-1G-G-R18-Consumer
//---------28个步骤如下
step1. To provide stable power for controller and memory device,
the controller must assert and hold CKE to a logic low level.
Then apply stable clock. Note: XDDR2SEL should be High level to hold CKE to low.
为了提供稳定的电源给控制器和内存设备,
控制器必须确保CKE维持低电平。
然后提供一个稳定的时钟。注意:XDDR2SEL需保持高来维持CKE为低
说明:XDDR2SEL在电路图设计中,一般直接拉到了VCC。
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step2. Set the PhyControl0.ctrl_start_point and PhyControl0.ctrl_inc bit-fields to correct value according to clock frequency. Set the PhyControl0.ctrl_dll_on bit-field to ‘1’ to turn on the PHY DLL.
根据时钟的频率,设置PhyControl0.ctrl_start_point and PhyControl0.ctrl_inc 字段为正确的值。
设置PhyControl0.ctrl_dll_on字段为1开启PHY DLL。
ldr r1, =0x00101000 @PhyControl0 DLL parameter setting, manual 0x00101000
str r1, [r0, #DMC_PHYCONTROL0]
说明:
1、PhyControl0.ctrl_start_point and PhyControl0.ctrl_inc 手册上说(This value should be 0x10 );ctrl_start_point 其实是开始相移的地方,ctrl_inc 每次相移的格数。
2、PhyControl0.ctrl_dll_on为1,开启dll。但是demo程序中此时并未打开dll,而是把打开这步骤放在了靠后的地方。
3、PhyControl0.ctrl_dfdqs为1,开启差分信号功能(具体需看硬件,支持差分,还是单端)
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step3. DQS Cleaning: Set the PhyControl1.ctrl_shiftc and PhyControl1.ctrl_offsetc bit-fields to correct value according to clock frequency and memory tAC parameters.
DQS清除:设置the PhyControl1.ctrl_shiftc and PhyControl1.ctrl_offsetc
位字段,根据时钟频率和内存TAC参数。
DQS Cleaning 示意图如下:
DQS Cleaning,其实就是想中和调板级的一些延时,如PCB延时等~~
ldr r1, =0x00000086 @PhyControl1 DLL parameter setting, LPDDR/LPDDR2 Case
str r1, [r0, #DMC_PHYCONTROL1]
说明:
1、ctrl_shiftc是粗条,通过控制器的DLL调整DQS的相移。(0x6 when DDR2 @200MHz)
2、ctrl_offsetc是精调,在ctrl_shiftc的基础上通过控制器的DLL调整DQS的相移。
3、ctrl_ref 是DLL同步完成之后需要的一个延时。默认是4这设置成8.
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step4. Set the PhyControl0.ctrl_start bit-field to ‘1’.
开启PhyControl0.ctrl_start 位
在dame代码中此时才打开ctrl_dll_on
ldr r1, =0x00101002 @PhyControl0 DLL on
str r1, [r0, #DMC_PHYCONTROL0]
然后打开ctrl_start
ldr r1, =0x00101003 @PhyControl0 DLL start
str r1, [r0, #DMC_PHYCONTROL0]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在配置,并开启之后,还需要等待一段时间,让DLL工作稳定的,在手册中到了第12步才去检查DLL是否稳定,而在damo程序中将
11和12步的内容提前到了第4步的后面,这样做主要是为了结构上的统一,也就是是一次性将DLL配置完。
而手册里那样做是为了节省配置时间,可以在配置其他的过程中等待DLL稳定。我们就先按照damo程序顺序进行分析,将12步提到前面来~~
step11 and step12
step11 . Wait for the PhyStatus0.ctrl_locked bit-fields to change to ‘1’. Check whether PHY DLL is locked.
step12 . PHY DLL compensates the changes of delay amount caused by Process, Voltage and Temperature (PVT)
variation during memory operation. Therefore, PHY DLL should not be off for reliable operation. It can be off
except runs at low frequency. If off mode is used, set the PhyControl0.ctrl_force bit-field to correct value
according to the PhyStatus0.ctrl_lock_value[9:2] bit-field to fix delay amount. Clear the
PhyControl0.ctrl_dll_on bit-field to turn off PHY DLL.
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
如果PhyStatus0的第3位全部为1,就表示我们之前配置的DLL按照我们设置的偏移(相对CLK的),已经工作稳定了。DLL为了完成这个过程,首先得不停的采集
clk,然后再不停的微调,这个过程是非常耗电的。所以在调整完成之后,DLL不需要在去跟踪clk了而是记录与CLK之前的一个差值,再保持这个差值即可,于是有了下面的程序:
and r1, #0x3fc0 @读出PhyStatus0的[13:14]
mov r2, r1, LSL #18 @左移18位,将PhyStatus0的[13:14]放到PhyControl0[31:24]
orr r2, r2, #0x100000 @恢复PhyControl0.ctrl_inc的值
orr r2 ,r2, #0x1000 @恢复PhyControl0.ctrl_istart_point的值
orr r1, r2, #0x3 @恢复PhyControl0低2位的值
str r1, [r0, #DMC_PHYCONTROL0] @存之
这段代码的含义就是把PhyStatus0的[13:14]为读出,将这段数据放到PhyControl0[31:24].
PhyStatus0的[13:14]的值是锁定完成后DQS与CLK的一个差值,把这个差值读出来之后放到PhyControl0[31:24],那么控制器就不再通过跟踪clk的方式,
而是通过固定延时的方式产生这个差值。
说明:
1、DQS是DLL根据clk产生的信号,这个信号也被称之为数据眼,DQS的主要作用就是告诉控制器何时读/写数据。确保数据的稳定接收和发送。
小节:
到了这里,所以关于DLL的部分就配置完了,主要用到的寄存器只有3个:PhyControl0,PhyControl1,和PhyStatus0。
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
12步之后再才开始之前的第5步:
step5. Set the ConControl. At this moment, an auto refresh counter should be off.
设置ConControl,此时应关闭自刷新计数器。
ldr r1, =0x0FFF2010 @ConControl auto refresh off
str r1, [r0, #DMC_CONCONTROL]
其中aref_en为0时就表示关闭自刷新计数器。
rd_fetch的设置是针对FIFO的读取时间的,设置成2更保险一点~~(默认值是1)
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step6. Set the MemControl. At this moment, all power down modes should be off.
配置MemControl比较重要的就是以下这几位,突发长度,chip个数,总线宽度,内存类型。
其中一个MCD最多可以控制两个chip,这里根据开发板情况进行选择,这里num_chip位设置为1.
#define DMC0_MEMCONTROL 0x00202400 // MemControl BL=4, 1Chip, DDR2 Type, dynamic self
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]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step7. Set the MemConfig0 register. If there are two external memory chips, set the MemConfig1 register.
#define DMC0_MEMCONFIG_0 0x20F01323 // MemConfig0
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]
这个寄存器的每一位都比较重要:
1、chip_base DRR的映射地址,默认0x2000_0000
2、chip_mask 确定一个chip的映射范围大小。1表示屏蔽,0表示不屏蔽。
如chip_mask = F0表示屏蔽高4位,那么映射大小就是:
0X0~0X0FFF_FFFF,也就是256M
如chip_mask = E0表示屏蔽高3位,那么映射大小就是:
0X0~0X1FFF_FFFF,也就是512M
3、chi_map表示内存的排列方式:(一般选择0,线性排列)
4、chip_col 表示列的位数
5、chip_row表示行的位数
6、chip_bank 表示一块芯片的bank数
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step8. Set the PrechConfig and PwrdnConfig registers.
现在可以开始配置PrechConfig预充电寄存器和 Pwrdown寄存器,但是damo程序中把 PwrdnConfig registers.的
配置放到了最后一步,所以这里先只讲述PrechConfig的配置。
ldr r1, =0xFF000000 @PrechConfig
str r1, [r0, #DMC_PRECHCONFIG]
这个寄存器用的其实是默认值,具体位的含义可以参考手册.
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step9. Set the TimingAref, TimingRow, TimingData and TimingPower registers according to memory AC parameters.
9.1 TimingAref
#define DMC0_TIMINGA_REF 0x00000618
ldr r1, =DMC0_TIMINGA_REF @TimingAref
str r1, [r0, #DMC_TIMINGAREF]
因为ddr是需要不断的刷新保持数据的,而这个刷新间隔不能太长,一般ddr这个间隔时间参数就是7.8us,具体时间查看ddr手册。也就是说最长7.8us必须刷新一次。我们不能直接把7.8us告诉arm,必须转换成时钟周期数告诉给arm。及把时钟周期数放到TimingAref.t_refi字段即可。那么周期如何算?首先你得知道此时提供MCD的时钟是多大,比如是133M,那么周期数就是7.8 us * 133 MHz = 1038 = 0x40E;如果时钟是200M那么周期数就是7.8 us * 200MHz = 1,560= 0x618;
9.2 TimingRow,这个寄存器主要是配置一些ddr时序参数了,这些参数需要到具体型号的ddr手册中去一个个的找~~(当然同样,时间要转换为时钟周期数)
#define DMC0_TIMING_ROW 0x28233287 // TimingRow for @200MHz
ldr r1, =DMC0_TIMING_ROW @TimingRow for @200MHz
str r1, [r0, #DMC_TIMINGROW]
9.3 TimingData 这个寄存器和上面寄存器一样,需要到具体型号的ddr手册中去一个个的找
其中需要注意的是cl,也就是CAS,
ddr手册中明确说明CAS可以配置为3,4,5,6这几个时钟周期。值得注意的是,目前我们配置的ddr控制器的CAS,之后还需配置ddr芯片本身的CAS。
所以,我们必须确保这两个CAS一致!
还有就是对于DDR2而言,所以wl这参数不用配置。但是对于低功耗的ddr就必须配置了。
#define DMC0_TIMING_DATA 0x23240304 // TimingData CL=3
ldr r1, =DMC0_TIMING_DATA @TimingData CL=3
str r1, [r0, #DMC_TIMINGDATA]
9.4 TimingPower 也是一样
#define DMC0_TIMING_PWR 0x09C80232 // TimingPower
ldr r1, =DMC0_TIMING_PWR @TimingPower
str r1, [r0, #DMC_TIMINGPOWER]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step10 If QoS scheme is required, set the QosControl0~15 and QosConfig0~15 registers.
现在不用Qos,跳过了~~。。。
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step11 and step12 被移到了第5步之前了~~
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step13. Confirm whether stable clock is issued minimum 200us after power on
由于step11 and step12被提到前面了,所以现在可以不等了~~
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step14~26 这些都是配置ddr芯片(而不是ddr控制器了),都是通过XXX寄存器向ddr芯片发送命令。
step14. Issue a NOP command using the DirectCmd register to assert and to hold CKE to a logic high level.
ldr r1, =0x07000000 @DirectCmd chip0 Deselect
str r1, [r0, #DMC_DIRECTCMD]
发送nop指令将CKE置高
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step15. Wait for minimum 400ns.
因为此前CKE一直为高,所以这里无需再等。
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step16. Issue a PALL command using the DirectCmd register.
ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
step17. Issue an EMRS2 command using the DirectCmd register to program the operating p
该寄存器作用不大,全部置0
ldr r1, =0x00020000 @DirectCmd chip0 EMRS2
str r1, [r0, #DMC_DIRECTCMD]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
18. Issue an EMRS3 command using the DirectCmd register to program the operating p
ldr r1, =0x00030000 @DirectCmd chip0 EMRS3
str r1, [r0, #DMC_DIRECTCMD]
以上四个步骤对应下图:
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
19. Issue an EMRS command using the DirectCmd register to enable the memory DLLs
这说的EMRS 就是EMRS1.
这里感觉主要就是A10设置为1,禁止了差分的DQS,而使用单端。
ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (MEM DLL on, DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
20. Issue a MRS command using the DirectCmd register to reset the memory DLL.
这一步配置MRS寄存器就很重要了~~
A8为1,是因为该步骤说明中明确指明要——reset the memory DLL.
ldr r1, =0x00000542 @DirectCmd chip0 MRS (MEM DLL reset) CL=4, BL=4
str r1, [r0, #DMC_DIRECTCMD]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
21. Issue a PALL command using the DirectCmd register.
再次发送一个PALL指令,和16步一样
ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
22. Issue two Auto Refresh commands using the DirectCmd register.
连续发送两个 Auto Refresh指令
ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
23. Issue a MRS command using the DirectCmd register to program the operating para
the memory DLL.
该步和第20步相同,也是写MRS,唯一的不同是A8这个为不同此时置位1,也就是不再复位DLL。
ldr r1, =0x00000442 @DirectCmd chip0 MRS (MEM DLL unreset)
str r1, [r0, #DMC_DIRECTCMD]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
24. Wait for minimum 200 clock cycles.
damo程序中并未等待~~
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
25. Issue an EMRS command using the DirectCmd register to program the operating pa
calibration is not used, issue an EMRS command to set OCD Calibration Default. Aft
command to exit OCD Calibration Mode and to program the operating parameters.
通过写两次EMRS1配置OCD校准,可以看到第一次将OCD_Corr写成111,之后又写成000
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]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
26. If there are two external memory chips, perform steps 14~25 for chip1 memory device.
如果DMC控制的是两个chip那么还需要配置一次chip1,就是把14~25重复一遍,只不过cmd_chip这个位要置1.
也就是说,到了这一步,关于ddr芯片的配置全部结束了。
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]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
27. Set the ConControl to turn on an auto refresh counter.
到了这一步再次回到ddr控制器的配置。
这一步和第5步只有一处不同,就是aref_en,这里开启了ddr控制器的自刷新功能。
ldr r1, =0x0FF02030 @ConControl auto refresh on
str r1, [r0, #DMC_CONCONTROL]
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
28. If power down modes is required, set the MemControl registers.
还记得第8部吗? Set the PrechConfig and PwrdnConfig registers. 当时damo只配置了PrechConfig 而没有配置PwrdnConfig ,而在这里
damo程序对PwrdnConfig 进行了配置。但基本就是按默认值配置的。
ldr r1, =0xFFFF00FF @PwrdnConfig
str r1, [r0, #DMC_PWRDNCONFIG]
程序再次设置了MemControl,这和第6步完全相同。这个步骤的本意是如果需要power down modes那么就去设置MemControl去使能相应的为,但是damo程序不想
power down modes这个功能,所以即使配置了PrechConfig也只是“做个样子”。
MemControl
ldr r1, =0x00202400 @MemControl BL=4, 1 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
str r1, [r0, #DMC_MEMCONTROL]
最后,总结一下值得注意的地方:
1、damo程序和手册的顺序不是完全一致的,总体来说damo程序是为了程序结构看起来更好做了一些小调整。
2、step1~step13 是对DDR控制器的配置。
step14~step26 是对DDR芯片寄存器进行配置。
step27和28,又再次配置了DDR控制器。
3、 在step1~step13中,前半部分主要是对ddr控制器的DLL进行配置,后半部部分是告诉控制器一些关于ddr的内存的型号大小以及时序参数。
4、step14~step26,主要是通过arm的DirectCmd寄存器对ddr的几个寄存器进行配置。这些寄存器分别是MRS,EMRS1 ,EMRS2 ,EMRS3. 这些被称之为DDR的模式寄存器。
5、模式寄存器用地址线传输数据,而不是数据线,因为所以的memory device地址线共享,这样传送就能一步到位。
6、如何通过arm的DirectCmd寄存器,配置ddr的模式寄存器:
当com_type字段为0时表示要配置ddr的模式寄存器,具体配置那个模式寄存器再看cmd_bank字段,
当cmd_bank = 0 表示配置MRS
当cmd_bank = 1表示配置EMRS1(注意EMRS1就是arm手册中说的EMRS)
当cmd_bank = 2表示配置EMRS2
当cmd_bank = 3表示配置EMRS3