本文使用的开发板是九鼎创展的X210 iNand版本。
一、查阅原理图中SDRAM相关部分
从以上原理图中可以得出以下信息:
(1)开发板上使用的SDRAM编码是K4T1G164QQ
(2)开发板上包括4片内存芯片,每片内存的数据总线都是16位的
(3)横向的两颗内存芯片是并联的(并联时地址总线的接法一样,但数据总线要加起来),这样连接相当于在逻辑上可以把这两颗内存芯片看成是一个32位的内存芯片
(4)每个内存端口都由3类总线构成:地址总线(Xm1_ADDR0~Xm1_ADDR13、Xm2_ADDR0~Xm2_ADDR13)+ 控制总线 + 数据总线(Xm1_DATA0~Xm1_DATA31、Xm2_DATA0~Xm2_DATA31)
二、查阅SDRAM数据手册
由上图可得出K4T1G164QQ的含义如下:
K:三星内存
4:DRAM
T:DDR2 SDRAM
1G:1Gb(128MB)
16:单芯片16位宽
4:8 Banks
由上图可得出以下信息:
(1)S5PV210的内存端口信号中有BA0~BA2,接在内存芯片的BA0~BA2上,这些引脚用来选择Bank
(2)每个Bank内部有128Mb,通过Row Address(14位)+ Column Address(10位)的方式来综合寻址
(3)一共能寻址的范围是:2的24次方,也就是16MB(128Mb)的内存
三、查阅数据手册中内存映射相关部分
从上图可得出以下信息:
(1)S5PV210共有两个内存端口,分别是DRAM0和DRAM1
(2)DRAM0的内存地址范围是0x20000000~0x3FFFFFFF(512MB)
(3)DRAM1的内存地址范围是0x40000000~0x7FFFFFFF(1024MB)
由此,得出结论:
(1)S5PV210最多支持1.5GB的内存,如果给它更多的内存,CPU就无法识别
(2)S5PV210最多支持1.5GB的内存,但实际开发板上不一定有这么多。例如X210开发板就只有512MB的内存(DRAM0端口分布256MB,DRAM1端口分布256MB)
(3)X210开发板上内存的合法地址是0x20000000~0x2FFFFFFF(256MB)+ 0x40000000~0x4FFFFFFF(256MB)
综合以上信息,进一步得出结论:
(1)X210开发板共使用了4片内存,每片1Gb(128MB),共512MB
(2)DRAM0对应的引脚是Xm1_xxxx
(3)DRAM1对应的引脚是Xm2_xxxx
(4)从数据总线的位数可知,X210开发板用的是32位的内存
四、查阅数据手册中DDR2初始化相关部分
由上图可知:初始化DDR2共需27个步骤。
综合前文所述,初始化DRAM时分为2部分:第一部分初始化DRAM0,第二部分初始化DRAM1。
编码实现部分只实现DRAM0的初始化,DRAM1的初始化步骤相同。
五、代码实现
1、led.c
#define GPJ0CON 0xE0200240 #define GPJ0DAT 0xE0200244 #define rGPJ0CON *((volatile unsigned int *)GPJ0CON) #define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT) void delay(void); void led_blink(void) { rGPJ0CON = 0x11111111; while(1) { // led亮 rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5)); // 延时 delay(); // led灭 rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5)); // 延时 delay(); } } void delay(void) { volatile unsigned int i = 900000; while (i--); }
2、link.lds
SECTIONS { . = 0x20000000; .text : { start.o sdram_init.o * (.text) } .data : { * (.data) } bss_start = .; .bss : { * (.bss) } bss_end = .; }
3、Makefie
led.bin: start.o led.o sdram_init.o arm-linux-ld -Tlink.lds -o led.elf $^ arm-linux-objcopy -O binary led.elf led.bin arm-linux-objdump -D led.elf > led_elf.dis gcc mkv210_image.c -o mkx210 ./mkx210 led.bin 210.bin %.o : %.S arm-linux-gcc -o $@ $< -c -nostdlib %.o : %.c arm-linux-gcc -o $@ $< -c -nostdlib clean: rm *.o *.elf *.bin *.dis mkx210 -f
4、start.S
#define SVC_STACK 0xD0037D80 .global _start _start: ldr sp, =SVC_STACK // 初始化DDR bl sdram_asm_init // 重定位 adr r0, _start ldr r1, =_start ldr r2, =bss_start cmp r0, r1 beq clean_bss copy_loop: ldr r3, [r0], #4 str r3, [r1], #4 cmp r1, r2 bne copy_loop clean_bss: ldr r0, =bss_start ldr r1, =bss_end cmp r0, r1 beq run_on_dram mov r2, #0 clear_loop: str r2, [r0], #4 cmp r0, r1 bne clear_loop run_on_dram: ldr pc, =led_blink b .
5、sdram_init.S
#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) */ 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, =0x000