看了一套視頻,感覺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