天嵌 ARM开发社区

 找回密码
 注册
查看: 3258|回复: 0

TQ210裸机编程(11)——DDR

[复制链接]
freewing 发表于 2014-6-8 01:07:24 | 显示全部楼层 |阅读模式
DDR虽然复杂,但是在芯片手册《S5PV210_UM_REV1.1》中为我们列出了配置步骤,只要按照步骤一步一步配置,就可以。里面很多时间参数查看DDR内存芯片手册,都很容易找到。

S5PV210芯片手册列出的DDR初始化步骤:

1.  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.
2. Set the PhyControl0.ctrl_start_pointand PhyControl0.ctrl_incbit-fields to correct value according to clock  
  frequency. Set the PhyControl0.ctrl_dll_onbit-field to ‘1’ to turn on the PHY DLL.
3.  DQS Cleaning: Set the PhyControl1.ctrl_shiftcand PhyControl1.ctrl_offsetcbit-fields to correct value  
  according to clock frequency and memory tAC parameters.
4. Set the PhyControl0.ctrl_startbit-field to ‘1’.  
5. Set the ConControl. At this moment, an auto refresh counter should be off.  
6. Set the MemControl. At this moment, all power down modes should be off.
7. Set the MemConfig0register. If there are two external memory chips, set the MemConfig1 register.
8. Set the PrechConfigand PwrdnConfigregisters.
9. Set the TimingAref, TimingRow, TimingDataand TimingPowerregisters according to memory AC  
  parameters.
10. If QoS scheme is required, set the QosControl0~15and QosConfig0~15registers.
11. Wait for the PhyStatus0.ctrl_lockedbit-fields to change to ‘1’. Check whether PHY DLL is locked.
12. PHY DLL compensates the changes of delay amountcaused 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_forcebit-field to correct value  
  according to the PhyStatus0.ctrl_lock_value[9:2]bit-field to fix delay amount. Clear the  
PhyControl0.ctrl_dll_onbit-field to turn off PHY DLL.
13. Confirm whether stable clock is issued minimum 200us after power on
14. Issue a NOPcommand using the DirectCmdregister to assert and to hold CKE to a logic high level.15. Wait for minimum 400ns.
16. Issue a PALLcommand using the DirectCmdregister.
17. Issue an EMRS2command using the DirectCmdregister to program the operating parameters.
18. Issue an EMRS3command using the DirectCmdregister to program the operating parameters.
19. Issue an EMRScommand using the DirectCmdregister to enable the memory DLLs.
20. Issue a MRScommand using the DirectCmdregister to reset the memory DLL.
21. Issue a PALLcommand using the DirectCmdregister.
22. Issue two Auto Refreshcommands using the DirectCmdregister.
23. Issue a MRScommand using the DirectCmdregister to program the operating parameters without resetting  
the memory DLL.
24. Wait for minimum 200 clock cycles.
25. Issue an EMRScommand using the DirectCmdregister to program the operating parameters. If OCD  
  calibration is not used, issue an EMRScommand to set OCD Calibration Default. After that, issue an EMRS
  command to exit OCD Calibration Mode and to program the operating parameters.
26. If there are two external memory chips, perform steps 14~25 for chip1 memory device.
27. Set the ConControlto turn on an auto refresh counter. 28. If power down modes is required, set the  
MemControlregisters.
15. Wait for minimum 400ns.
16. Issue a PALLcommand using the DirectCmdregister.
17. Issue an EMRS2command using the DirectCmdregister to program the operating parameters.
18. Issue an EMRS3command using the DirectCmdregister to program the operating parameters.
19. Issue an EMRScommand using the DirectCmdregister to enable the memory DLLs.
20. Issue a MRScommand using the DirectCmdregister to reset the memory DLL.
21. Issue a PALLcommand using the DirectCmdregister.
22. Issue two Auto Refreshcommands using the DirectCmdregister.
23. Issue a MRScommand using the DirectCmdregister to program the operating parameters without resetting  
the memory DLL.
24. Wait for minimum 200 clock cycles.
25. Issue an EMRScommand using the DirectCmdregister to program the operating parameters. If OCD  
  calibration is not used, issue an EMRScommand to set OCD Calibration Default. After that, issue an EMRS
  command to exit OCD Calibration Mode and to program the operating parameters.
26. If there are two external memory chips, perform steps 14~25 for chip1 memory device.
27. Set the ConControlto turn on an auto refresh counter. 28. If power down modes is required, set the  
MemControlregisters.





首先贴出TQ210的内存接线图:



S5PV210有2个独立的DRAM控制器和端口(引脚):DMC0和DMC1。DMC0最大支持512MByte,DMC1最大支持1GByte,两个控制器必须使用相同类型的内存。




TQ210开发板板载8片K4T1G084QQ,每片128MByte,共计1GByte内存。

其中4片挂接在DMC0,使用相同的地址线xm1ADDR[13:0],串联使用数据线xm1DATA[31:0],数据位宽32位;

另外4片挂接在DMC1,使用相同的地址线xm2ADDR[13:0],串联使用数据线xm2DATA[31:0],数据位宽32位;




下面贴出S5PV210给出的芯片接线配置方案




从K4T1G084QQ芯片手册得知该芯片具有8个BANK,需要3根BANK选择线,具有14根地址线(其中14根行地址和10根列地址复用),见下图中的128Mbx8那列




所以使用的是S5PV210中给出的方案3,其中使用一根片选Xm1(2)CSn[0]





关键寄存器配置说明(DMC0和DMC1的配置完全一样,除了AXI Base Address):

MEMCONTROL


num_chip[19:16]:从上面的配置方案3得出这里配置为0x0 = 1 chip,因为只使用了一个片选信号。

mem_width[15:12]:数据位宽0x2 = 32-bit




MEMCONFIG0

chip_base[31:24]:S5PV210可以自定义内存基地址,这里使用默认的0x20,

从S5PV210芯片手册的2.1  MEMORY ADDRESS MAP 一节可以得知DRAM0的地址范围为0x2000_0000~0x3FFF_FFFF,DRAM1的地址范围为0x4000_0000~0x7FFF_FFFF。


chip_mask[23:16]:DMC将AXI发来的地址的高8位与chip_mask按位与,如果与chip_base相等,则打开相应的片选。


例如:

DMC0_MEMCONFIG0   chip_base =  0x20      chip_mask=0xF8

DMC0_MEMCONFIG1   chip_base =  0x28      chip_mask=0xF8
当AXI发来0x2000_0000~0x27FF_FFFF(128MByte)时,高8位按位与0xF8=0x20,则打开DMC0的片选CS0,
当AXI发来0x2800_0000~0x27FF_FFFF(128MByte)时,高8位按位与0xF8=0x28,则打开DMC0的片选CS1,

TQ210开发板只有一个片选CS0,DMC0的地址范围0x2000_0000~0x3FFF_FFFF(512MByte),DMC1的地址范围0x4000_0000~0x5FFF_FFFF(512MByte),


DMC0_MEMCONFIG0  chip_base =  0x20     chip_mask=0xE0


DMC1_MEMCONFIG0  chip_base =  0x40     chip_mask=0xE0

当AXI发来0x2000_0000~0x3FFF_FFFF时,高8位按位与0xE0=0x20,则打开DMC0的片选CS0,
当AXI发来0x4000_0000~0x5FFF_FFFF时,高8位按位与0xE0=0x40,则打开DMC1的片选CS0,





这里要提一点,之前的时钟配置没有针对内存的配置,这里需要补充一下。具体见代码。

这次实验把之前的代码重定位改为重定位到DDR,重定位到0x20000000地址处。

start.S




[cpp] view plaincopy
01..global br_str              /* 声明全局标号 */  
02..global ar_str  
03..global _start  
04._start:  
05.    bl clock_init           /* 时钟初始化 */  
06.    bl uart_init            /* 串口初始化 */  
07.    bl ddr_init             /* DDR初始化 */  
08.  
09.    adr r0, br_str          /* 取得br_str的当前地址(重定位之前) */  
10.    /* 调用C函数before_relocate,接收一个参数 */  
11.    bl before_relocate  
12.  
13.    /* 重定位 */  
14.    adr r0, _start          /* 相对寻址:取得_start的当前地址0xD0020010 */  
15.    ldr r1, =_start         /* 绝对寻址:取得_start的链接地址0x20000000 */  
16.    ldr r2, =bss_start      /* bss段的起始地址 */  
17.    cmp r0, r1              /* 如果取得_start的当前地址和链接地址相等,则说明程序已经位于它的链接地址 */  
18.    beq clean_bss  
19.      
20.copy_loop:  
21.    ldr r3, [r0], #4    // 源  
22.    str r3, [r1], #4    // 目的  
23.    cmp r1, r2  
24.    bne copy_loop  
25.  
26.  
27.    /* 清bss段 */  
28.clean_bss:  
29.    ldr r0, =bss_start                    
30.    ldr r1, =bss_end  
31.    cmp r0, r1  
32.    beq relocate_done  
33.    /* 为什么这里要比较呢?
34.    ** 因为如果相等,则bss段没有数据,而这时如果进行下面的清bss段操作
35.    ** 首先执行“str r2, [r0], #4”后,r0加4,再执行“cmp r0, r1”就不相等了,这样一直循环。
36.    */  
37.  
38.    mov r2, #0  
39.1:  
40.    str r2, [r0], #4  
41.    cmp r0, r1  
42.    bne 1b          /* b是back的意思,代表向后跳转;如果向前跳转则使用f意思是forward */  
43.  
44.    /* 跳转 */  
45.relocate_done:  
46.    ldr sp, =0x60000000     /* 内存的最高地址 */         
47.    ldr pc, =main  
48.  
49.halt:  
50.    b halt  
51.  
52./* 定义一个字符串:.asciz会自动添加一个'\0',而ascii不会 */  
53.br_str:  
54.    .asciz "\nbefore relocate\n"  






clock.c





[cpp] view plaincopy
01.#define APLLCON0        *((volatile unsigned int *)0xE0100100)  
02.#define MPLLCON         *((volatile unsigned int *)0xE0100108)  
03.#define EPLLCON0        *((volatile unsigned int *)0xE0100110)  
04.#define VPLLCON         *((volatile unsigned int *)0xE0100120)  
05.  
06.#define CLK_SRC0        *((volatile unsigned int *)0xE0100200)  
07.#define CLK_SRC1        *((volatile unsigned int *)0xE0100204)  
08.#define CLK_SRC2        *((volatile unsigned int *)0xE0100208)  
09.#define CLK_SRC3        *((volatile unsigned int *)0xE010020C)  
10.#define CLK_SRC4        *((volatile unsigned int *)0xE0100210)  
11.#define CLK_SRC5        *((volatile unsigned int *)0xE0100214)  
12.#define CLK_SRC6        *((volatile unsigned int *)0xE0100218)  
13.  
14.#define CLK_DIV0        *((volatile unsigned int *)0xE0100300)  
15.#define CLK_DIV1        *((volatile unsigned int *)0xE0100304)  
16.#define CLK_DIV2        *((volatile unsigned int *)0xE0100308)  
17.#define CLK_DIV3        *((volatile unsigned int *)0xE010030C)  
18.#define CLK_DIV4        *((volatile unsigned int *)0xE0100310)  
19.#define CLK_DIV5        *((volatile unsigned int *)0xE0100314)  
20.#define CLK_DIV6        *((volatile unsigned int *)0xE0100318)  
21.#define CLK_DIV7        *((volatile unsigned int *)0xE010031C)  
22.  
23.void clock_init()  
24.{  
25.    /* 1、设置PLL_LOCK寄存器(这里使用默认值) */  
26.    /* 2、设置PLL_CON寄存器(使用芯片手册推荐的值) */  
27.    APLLCON0    = (1 << 0) | (3 << 8) | (125 << 16) | (1 << 31);    /* FOUTAPLL = 1000MHz */  
28.    MPLLCON     = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);   /* FOUTMPLL = 667MHz */  
29.    EPLLCON0    = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);   /* FOUTEPLL = 96MHz */  
30.    VPLLCON     = (3 << 0) | (6 << 8) | (108 << 16) | (1 << 31);    /* FOUTVPLL = 54MHz */  
31.      
32.    /* 3、选择PLL为时钟输出 */  
33.    /* MOUT_MSYS = SCLKAPLL = 1000MHz
34.    ** MOUT_DSYS = SCLKMPLL = 667MHz
35.    ** MOUT_PSYS = SCLKMPLL = 667MHz
36.    */  
37.    CLK_SRC0 = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 12);  
38.  
39.    /* 选择SCLKA2M作为DMC0的时钟源 */  
40.    CLK_SRC6 &= ~(0x3 << 24);  
41.      
42.    /* 4、设置系统时钟分频值 */  
43.    /* freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz / (0 + 1) = 1000MHz
44.    ** freq(A2M) = SCLKAPLL / (A2M_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz
45.    ** freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz
46.    ** freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 200MHz / (1 + 1) = 100MHz
47.    ** freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 667 / (3 + 1) = 166MHz
48.    ** freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 166 / (1 + 1) = 83MHz
49.    ** freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 667 / (4 + 1) = 133MHz
50.    ** freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 133 / (1 + 1) = 66MHz
51.    */  
52.    CLK_DIV0 = (0 << 0) | (4 << 4) | (4 << 8) | (1 << 12) | (3 << 16) | (1 << 20) | (4 << 24) | (1 << 28);  
53.}  

types.h





[cpp] view plaincopy
01.#ifndef TYPES_H_  
02.#define TYPES_H_  
03.  
04.typedef volatile char           s8;  
05.typedef volatile short          s16;  
06.typedef volatile int            s32;  
07.  
08.typedef volatile unsigned char  u8;  
09.typedef volatile unsigned short u16;  
10.typedef volatile unsigned int   u32;  
11.  
12.#endif  

uart.c





[cpp] view plaincopy
01.#include <stdarg.h>  
02.#include "types.h"  
03.  
04.#define GPA0CON     *((volatile unsigned int *)0xE0200000)  
05.#define ULCON0      *((volatile unsigned int *)0xE2900000)  
06.#define UCON0       *((volatile unsigned int *)0xE2900004)  
07.#define UFCON0      *((volatile unsigned int *)0xE2900008)  
08.#define UTRSTAT0    *((volatile unsigned int *)0xE2900010)  
09.#define UTXH0       *((volatile unsigned int *)0xE2900020)  
10.#define URXH0       *((volatile unsigned int *)0xE2900024)  
11.#define UBRDIV0     *((volatile unsigned int *)0xE2900028)  
12.#define UDIVSLOT0   *((volatile unsigned int *)0xE290002C)  
13.  
14./*
15.** UART0初始化
16.*/  
17.void uart_init()  
18.{  
19.    /*
20.    ** 配置GPA0_0为UART_0_RXD
21.    ** 配置GPA0_1为UART_0_TXD
22.    */  
23.    GPA0CON &= ~0xFF;  
24.    GPA0CON |= 0x22;  
25.  
26.    /* 8-bits/One stop bit/No parity/Normal mode operation */  
27.    ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6);  
28.  
29.    /* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/  
30.    UCON0 = 1 | (1 << 2) | (0 << 10);  
31.  
32.    /* 静止FIFO */  
33.    UFCON0 = 0;  
34.  
35.    /*
36.    ** 波特率计算:115200bps
37.    ** PCLK = 66MHz
38.    ** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
39.    ** UBRDIV0 = 34(DIV_VAL的整数部分)
40.    ** (num of 1's in UDIVSLOTn)/16 = 0.8
41.    ** (num of 1's in UDIVSLOTn) = 12
42.    ** UDIVSLOT0 = 0xDDDD (查表)
43.    */  
44.    UBRDIV0 = 34;  
45.    UDIVSLOT0 = 0xDDDD;  
46.}  
47.  
48./* 输出一字节的数据到终端 */  
49.void uart_send_byte(u8 byte)  
50.{  
51.    while (!(UTRSTAT0 & (1 << 2)));   /* 等待发送缓冲区为空 */  
52.    UTXH0 = byte;                   /* 发送一字节数据 */         
53.}  
54.  
55./* 从终端接收一字节数据 */  
56.u8 uart_recv_byte()  
57.{  
58.    while (!(UTRSTAT0 & 1));    /* 等待接收缓冲区有数据可读 */  
59.    return URXH0;               /* 接收一字节数据 */         
60.}  
61.  
62./* 打印字符c到终端 */  
63.void putchar(u8 c)  
64.{  
65.    uart_send_byte(c);  
66.    if (c == '\n')  
67.        uart_send_byte('\r');  
68.}  
69.  
70./* 打印字符串s到终端 */  
71.void puts(s8 *s)  
72.{  
73.    s8 *p = s;  
74.    while (*p)  
75.        putchar(*p++);  
76.}  
77.  
78./* 打印整数v到终端 */  
79.void put_int(u32 v)  
80.{  
81.    int i;  
82.    u8 a[10];  
83.    u8 cnt = 0;  
84.  
85.    if (v == 0)  
86.    {  
87.        putchar('0');  
88.        return;  
89.    }  
90.  
91.    while (v)  
92.    {  
93.        a[cnt++] = v % 10;  
94.        v /= 10;   
95.    }  
96.  
97.    for (i = cnt - 1; i >= 0; i--)  
98.        putchar(a + 0x30);  
99.    /*
100.    ** 整数0-9的ASCII分别为0x30-0x39
101.    */  
102.}  
103.  
104./* 将一字节十六进制数按十六进制显示打印到终端 */  
105.void put_hex(u8 v, u8 small)  
106.{  
107.    /* 注意:必须用volatile修饰,否则会出错 */  
108.    u8 h, l;        /* 高4位和第4位(这里按二进制算) */  
109.    char *hex1 = "0123456789abcdef";        /* 这里放在数据段中 */  
110.    char *hex2 = "0123456789ABCDEF";  
111.  
112.    h = v >> 4;  
113.    l = v & 0x0F;  
114.  
115.    if (small)  /* 小写 */  
116.    {  
117.        putchar(hex1[h]);   /* 高4位 */  
118.        putchar(hex1[l]);   /* 低4位 */  
119.    }  
120.    else        /* 大写 */  
121.    {  
122.        putchar(hex2[h]);   /* 高4位 */  
123.        putchar(hex2[l]);   /* 低4位 */  
124.    }  
125.}  
126.  
127./* 将int型整数按16进制打印到终端 */  
128.void put_int_hex(u32 v, u8 small)  
129.{  
130.    if (v >> 24)  
131.    {  
132.        put_hex(v >> 24, small);  
133.        put_hex((v >> 16) & 0xFF, small);  
134.        put_hex((v >> 8) & 0xFF, small);  
135.        put_hex(v & 0xFF, small);  
136.    }  
137.    else if ((v >> 16) & 0xFF)  
138.    {  
139.        put_hex((v >> 16) & 0xFF, small);  
140.        put_hex((v >> 8) & 0xFF, small);  
141.        put_hex(v & 0xFF, small);  
142.    }  
143.    else if ((v >> 8) & 0xFF)  
144.    {  
145.        put_hex((v >> 8) & 0xFF, small);  
146.        put_hex(v & 0xFF, small);  
147.    }  
148.    else  
149.        put_hex(v & 0xFF, small);  
150.}  
151.  
152./* 格式化输出到终端 */  
153.int printf(const char *fmt, ...)  
154.{  
155.    va_list ap;  
156.    s8 c;  
157.    s8 *s;  
158.    u32 d;  
159.    u8 small;  
160.  
161.    va_start(ap, fmt);  
162.    while (*fmt)  
163.    {  
164.        small = 0;  
165.        c = *fmt++;  
166.        if (c == '%')  
167.        {  
168.            switch (*fmt++)  
169.            {  
170.            case 'c':              /* char */  
171.                c = (char) va_arg(ap, int);  
172.                putchar(c);  
173.                break;  
174.            case 's':              /* string */  
175.                s = va_arg(ap, char *);  
176.                puts(s);  
177.                break;  
178.            case 'd':              /* int */  
179.            case 'u':  
180.                d = va_arg(ap, int);  
181.                put_int(d);  
182.                break;  
183.            case 'x':  
184.                small = 1;  // small  
185.            case 'X':  
186.                d = va_arg(ap, int);  
187.                put_int_hex(d, small);  
188.                break;  
189.            }  
190.        }  
191.        else  
192.            putchar(c);  
193.    }  
194.    va_end(ap);  
195.}  

ddr.c





[cpp] view plaincopy
01.#define MP1_0DRV (*(volatile unsigned long*)0xE02003CC)  
02.#define MP1_1DRV (*(volatile unsigned long*)0xE02003EC)  
03.#define MP1_2DRV (*(volatile unsigned long*)0xE020040C)  
04.#define MP1_3DRV (*(volatile unsigned long*)0xE020042C)  
05.#define MP1_4DRV (*(volatile unsigned long*)0xE020044C)  
06.#define MP1_5DRV (*(volatile unsigned long*)0xE020046C)  
07.#define MP1_6DRV (*(volatile unsigned long*)0xE020048C)  
08.#define MP1_7DRV (*(volatile unsigned long*)0xE02004AC)  
09.#define MP1_8DRV (*(volatile unsigned long*)0xE02004CC)  
10.  
11.#define DMC0_BASE           0xF0000000  
12.#define DMC1_BASE           0xF1400000  
13.  
14.#define DMC0_CONCONTROL     *((volatile unsigned int *)(DMC0_BASE + 0x00))  
15.#define DMC0_MEMCONTROL     *((volatile unsigned int *)(DMC0_BASE + 0x04))  
16.#define DMC0_MEMCONFIG0     *((volatile unsigned int *)(DMC0_BASE + 0x08))  
17.#define DMC0_MEMCONFIG1     *((volatile unsigned int *)(DMC0_BASE + 0x0C))  
18.#define DMC0_DIRECTCMD      *((volatile unsigned int *)(DMC0_BASE + 0x10))  
19.#define DMC0_PRECHCONFIG    *((volatile unsigned int *)(DMC0_BASE + 0x14))  
20.#define DMC0_PHYCONTROL0    *((volatile unsigned int *)(DMC0_BASE + 0x18))  
21.#define DMC0_PHYCONTROL1    *((volatile unsigned int *)(DMC0_BASE + 0x1C))  
22.#define DMC0_PWRDNCONFIG    *((volatile unsigned int *)(DMC0_BASE + 0x28))  
23.#define DMC0_TIMINGAREF     *((volatile unsigned int *)(DMC0_BASE + 0x30))  
24.#define DMC0_TIMINGROW      *((volatile unsigned int *)(DMC0_BASE + 0x34))  
25.#define DMC0_TIMINGDATA     *((volatile unsigned int *)(DMC0_BASE + 0x38))  
26.#define DMC0_TIMINGPOWER    *((volatile unsigned int *)(DMC0_BASE + 0x3C))  
27.#define DMC0_PHYSTATUS      *((volatile unsigned int *)(DMC0_BASE + 0x40))  
28.#define DMC0_CHIP0STATUS    *((volatile unsigned int *)(DMC0_BASE + 0x48))  
29.#define DMC0_CHIP1STATUS    *((volatile unsigned int *)(DMC0_BASE + 0x4C))  
30.#define DMC0_AREFSTATUS     *((volatile unsigned int *)(DMC0_BASE + 0x50))  
31.#define DMC0_MRSTATUS       *((volatile unsigned int *)(DMC0_BASE + 0x54))  
32.  
33.#define DMC1_CONCONTROL     *((volatile unsigned int *)(DMC1_BASE + 0x00))  
34.#define DMC1_MEMCONTROL     *((volatile unsigned int *)(DMC1_BASE + 0x04))  
35.#define DMC1_MEMCONFIG0     *((volatile unsigned int *)(DMC1_BASE + 0x08))  
36.#define DMC1_MEMCONFIG1     *((volatile unsigned int *)(DMC1_BASE + 0x0C))  
37.#define DMC1_DIRECTCMD      *((volatile unsigned int *)(DMC1_BASE + 0x10))  
38.#define DMC1_PRECHCONFIG    *((volatile unsigned int *)(DMC1_BASE + 0x14))  
39.#define DMC1_PHYCONTROL0    *((volatile unsigned int *)(DMC1_BASE + 0x18))  
40.#define DMC1_PHYCONTROL1    *((volatile unsigned int *)(DMC1_BASE + 0x1C))  
41.#define DMC1_PWRDNCONFIG    *((volatile unsigned int *)(DMC1_BASE + 0x28))  
42.#define DMC1_TIMINGAREF     *((volatile unsigned int *)(DMC1_BASE + 0x30))  
43.#define DMC1_TIMINGROW      *((volatile unsigned int *)(DMC1_BASE + 0x34))  
44.#define DMC1_TIMINGDATA     *((volatile unsigned int *)(DMC1_BASE + 0x38))  
45.#define DMC1_TIMINGPOWER    *((volatile unsigned int *)(DMC1_BASE + 0x3C))  
46.#define DMC1_PHYSTATUS      *((volatile unsigned int *)(DMC1_BASE + 0x40))  
47.#define DMC1_CHIP0STATUS    *((volatile unsigned int *)(DMC1_BASE + 0x48))  
48.#define DMC1_CHIP1STATUS    *((volatile unsigned int *)(DMC1_BASE + 0x4C))  
49.#define DMC1_AREFSTATUS     *((volatile unsigned int *)(DMC1_BASE + 0x50))  
50.#define DMC1_MRSTATUS       *((volatile unsigned int *)(DMC1_BASE + 0x54))  
51.  
52.  
53.void ddr_init()  
54.{  
55.    /* DMC0 */  
56.    DMC0_PHYCONTROL0 = 0x00101000;  
57.    DMC0_PHYCONTROL0 = 0x00101002;          /* DLL on */  
58.    DMC0_PHYCONTROL1 = 0x00000086;  
59.    DMC0_PHYCONTROL0 = 0x00101003;          /* DLL start */  
60.  
61.    while ((DMC0_PHYSTATUS & 0x7) != 0x7);  /* wait DLL locked */  
62.  
63.    DMC0_CONCONTROL = 0x0FFF2350;           /* Auto Refresh Counter should be off */  
64.    DMC0_MEMCONTROL = 0x00202430;           /* Dynamic power down should be off */  
65.    DMC0_MEMCONFIG0 = 0x20E01323;  
66.  
67.    DMC0_PRECHCONFIG = 0xFF000000;  
68.    DMC0_PWRDNCONFIG = 0xFFFF00FF;  
69.  
70.    DMC0_TIMINGAREF = 0x00000618;           /* 7.8us * 200MHz = 1560 = 0x618  */  
71.    DMC0_TIMINGROW = 0x19233309;  
72.    DMC0_TIMINGDATA = 0x23240204;  
73.    DMC0_TIMINGPOWER = 0x09C80232;  
74.  
75.    DMC0_DIRECTCMD = 0x07000000;            /* NOP */  
76.    DMC0_DIRECTCMD = 0x01000000;            /* PALL */  
77.    DMC0_DIRECTCMD = 0x00020000;            /* EMRS2 */  
78.    DMC0_DIRECTCMD = 0x00030000;            /* EMRS3 */  
79.    DMC0_DIRECTCMD = 0x00010400;            /* EMRS enable DLL*/  
80.    DMC0_DIRECTCMD = 0x00000542;            /* DLL reset */  
81.    DMC0_DIRECTCMD = 0x01000000;            /* PALL */  
82.    DMC0_DIRECTCMD = 0x05000000;            /* auto refresh */  
83.    DMC0_DIRECTCMD = 0x05000000;            /* auto refresh */  
84.    DMC0_DIRECTCMD = 0x00000442;            /* DLL unreset */  
85.    DMC0_DIRECTCMD = 0x00010780;            /* OCD default */  
86.    DMC0_DIRECTCMD = 0x00010400;            /* OCD exit */  
87.  
88.    DMC0_CONCONTROL = 0x0FF02030;           /* auto refresh on */  
89.    DMC0_PWRDNCONFIG = 0xFFFF00FF;  
90.    DMC0_MEMCONTROL = 0x00202400;  
91.  
92.    /* DMC1 */  
93.    DMC1_PHYCONTROL0 = 0x00101000;  
94.    DMC1_PHYCONTROL0 = 0x00101002;  
95.    DMC1_PHYCONTROL1 = 0x86;  
96.    DMC1_PHYCONTROL0 = 0x00101003;  
97.  
98.    while((DMC0_PHYSTATUS&0x7) != 0x7);  
99.  
100.    DMC1_CONCONTROL = 0x0FFF2350;           /* Auto Refresh Counter should be off */  
101.    DMC1_MEMCONTROL = 0x00202430;           /* Dynamic power down should be off */  
102.    DMC1_MEMCONFIG0 = 0x40E01323;  
103.  
104.    DMC1_PRECHCONFIG = 0xFF000000;  
105.    DMC1_PWRDNCONFIG = 0xFFFF00FF;  
106.  
107.    DMC1_TIMINGAREF = 0x00000618;           /* 7.8us * 200MHz = 1560 = 0x618  */  
108.    DMC1_TIMINGROW = 0x19233309;  
109.    DMC1_TIMINGDATA = 0x23240204;  
110.    DMC1_TIMINGPOWER = 0x09C80232;  
111.  
112.    DMC1_DIRECTCMD = 0x07000000;  
113.    DMC1_DIRECTCMD = 0x01000000;  
114.    DMC1_DIRECTCMD = 0x00020000;  
115.    DMC1_DIRECTCMD = 0x00030000;  
116.    DMC1_DIRECTCMD = 0x00010400;  
117.    DMC1_DIRECTCMD = 0x00000542;  
118.    DMC1_DIRECTCMD = 0x01000000;  
119.    DMC1_DIRECTCMD = 0x05000000;  
120.    DMC1_DIRECTCMD = 0x05000000;  
121.    DMC1_DIRECTCMD = 0x00000442;  
122.    DMC1_DIRECTCMD = 0x00010780;  
123.    DMC1_DIRECTCMD = 0x00010400;  
124.  
125.    DMC1_CONCONTROL = 0x0FF02030;  
126.    DMC1_PWRDNCONFIG = 0xFFFF00FF;  
127.    DMC1_MEMCONTROL = 0x00202400;  
128.}  

main.c





[cpp] view plaincopy
01.#include "uart.h"  
02.#include "types.h"  
03.  
04.void delay(u32 t)  
05.{  
06.    u32 t2 = 0xFFFF;  
07.    while (t--)  
08.        for (; t2; t2--);  
09.}  
10.  
11.void before_relocate(u32 addr)  
12.{  
13.    char *p = (char *)addr;  
14.    puts(p);  
15.}  
16.  
17.int main()  
18.{     
19.    u32 val = 0;  
20.    while (1)  
21.    {  
22.        printf("val = %d\n", val++);  
23.        delay(500000);  
24.    }  
25.    return 0;  
26.}  

link.lds





[cpp] view plaincopy
01.SECTIONS  
02.{  
03.    . = 0x20000000;  
04.      
05.    .text : {  
06.        start.o  
07.        * (.text)  
08.    }  
09.              
10.    .data : {  
11.        * (.data)  
12.    }  
13.      
14.    bss_start = .;   
15.    .bss : {  
16.        * (.bss)  
17.    }  
18.      
19.    bss_end  = .;     
20.}  

Makefile





[cpp] view plaincopy
01.uart.bin: start.o clock.o uart.o ddr.o main.o  
02.    arm-linux-ld -Tlink.lds -o uart.elf $^  
03.    arm-linux-objcopy -O binary uart.elf $@  
04.    arm-linux-objdump -D uart.elf > uart.dis  
05.      
06.%.o : %.c  
07.    arm-linux-gcc -c $< -o $@  
08.%.o : %.S  
09.    arm-linux-gcc -c $< -o $@  
10.      
11.clean:  
12.    rm *.o *.elf *.bin *.dis  



烧写过程见《TQ210裸机编程(5)——系统时钟配置》

转载请注明来源:http://blog.csdn.net/zjhsucceed_329/
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号 )

GMT+8, 2024-4-19 22:47 , Processed in 1.046875 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表