TQ2440的地址分为0~7八个bank,每个bank可以外接一个存储设备,初始化既是初始化每个bank的寄存器
SDRAM初始化其实就是设置下其13个寄存器(视实际情况而定),
具体分析看代码
汇编代码start.S
@led start @2010-01-16 @jay .globl _start _start: b reset @预留着以后扩展中断向量表 reset: @disable watchdog ldr r0,=0x53000000 mov r1,#0 str r1,[r0] /* 以前用于设置堆栈指针的,现在废弃了 @setup stack ldr r0,=1024*4 mov sp,r0 */ @init SDRAM 调用初始化sdram函数 bl memsetup @cope the code to sdram 将代码copy到初始化好的sdram中 bl cp_to_SDRAM ldr pc,=load_sd @注意这句指令,将load_sd标签的地址装载进pc,load_sd的值将会是0x3000000xx @load_sd的值依赖于arm-linux-ld的链接地址,这个可以看下反汇编文件 比较好理解 @是将load_sd的编译地址赋给了pc,而这个编译地址就被外面定义在了sdram内,自然的 @我们就顺理成章的跳进了sdram中去了 load_sd: ldr sp,=0x34000000 @设置堆栈指针,将其设置在外面初始化好的sdram中 bl led_test @调用led跑马灯程序 b . @loop 一个死循环 @copy to sdram cp_to_SDRAM: @ adr r0,_start mov r0,#0 @r0为复制开始的位置 add r1,r0,#4096 @r1为复制结束的位置,我们要复制4096个字节4k,此cpu的片内ram只有4k大 ldr r2,=0x30000000 @r2为我们需要复制到的位置 sdram中 lp: ldmia r0!,{r3-r11} @ldmia将从r0地址处的储存的内容分别装载进r3-r11,一共4*8=32个字节 stmia r2!,{r3-r11} @stmia将r3-r11装载的内容存进r2地址开始处 cmp r0,r1 @比较 没有复制完就接着循环 ble lp mov pc,lr @返回
汇编代码low_init.S
#include"memsetup.h" /*宽度 用于决定bankx的宽度*/ .EQU DW8, 0x00 .EQU DW16, 0x01 .EQU DW32, 0x02 /*等待 */ .EQU WAIT, (1<<2) .EQU UBLB, (1<<3) @BWSCON config /*bank0的位宽由硬件决定 不需要我们去配置 bank1~7的宽度都是可以软件控制的 至于为什么要这样配置还不清楚,以后知道了补上 这些宏的定义是为了方便配置对应寄存器的每一位,具体作用需要看cpu的datasheet 不建议直接为寄存器赋值0x000123之类的,第一不容易理解,第二不便于移植 BWSCON寄存器是位宽与等待寄存器,每四位控制一个对应的bank,bank0不需要配置 */ .EQU B1_BWSCON, DW32 .EQU B2_BWSCON, DW16 .EQU B3_BWSCON, DW16 .EQU B4_BWSCON, DW16 .EQU B5_BWSCON, DW16 .EQU B6_BWSCON, DW32 @2块16bit的合并为32bit .EQU B7_BWSCON, DW32 /*bank0~7 control register 每一个bank都有一个对应的control register,在不了解其他存储器之前 外面只配置sdram,其他的用默认值,以后学到了再配置 */ .EQU B0_Tacs, 0x0 .EQU B0_Tcos, 0x0 .EQU B0_Tacc, 0x7 .EQU B0_Tcoh, 0x0 .EQU B0_Tcah, 0x0 .EQU B0_Tacp, 0x0 .EQU B0_PMC, 0x0 .EQU B1_Tacs, 0x0 .EQU B1_Tcos, 0x0 .EQU B1_Tacc, 0x7 .EQU B1_Tcoh, 0x0 .EQU B1_Tcah, 0x0 .EQU B1_Tacp, 0x0 .EQU B1_PMC, 0x0 .EQU B2_Tacs, 0x0 .EQU B2_Tcos, 0x0 .EQU B2_Tacc, 0x7 .EQU B2_Tcoh, 0x0 .EQU B2_Tcah, 0x0 .EQU B2_Tacp, 0x0 .EQU B2_PMC, 0x0 .EQU B3_Tacs, 0x0 .EQU B3_Tcos, 0x0 .EQU B3_Tacc, 0x7 .EQU B3_Tcoh, 0x0 .EQU B3_Tcah, 0x0 .EQU B3_Tacp, 0x0 .EQU B3_PMC, 0x0 .EQU B4_Tacs, 0x0 .EQU B4_Tcos, 0x0 .EQU B4_Tacc, 0x7 .EQU B4_Tcoh, 0x0 .EQU B4_Tcah, 0x0 .EQU B4_Tacp, 0x0 .EQU B4_PMC, 0x0 .EQU B5_Tacs, 0x0 .EQU B5_Tcos, 0x0 .EQU B5_Tacc, 0x7 .EQU B5_Tcoh, 0x0 .EQU B5_Tcah, 0x0 .EQU B5_Tacp, 0x0 .EQU B5_PMC, 0x0 /*sdram的配置必须一样,且sdram只需要配置这几位 mt是选中sdram,Trcd是行扫描到列扫描的延时,sdram其实 是一个矩阵表,通过行列扫描来定位,具体设置要看datasheet。 scan是列的数目 */ .EQU B6_MT, 0x3 .EQU B6_Trcd, 0x1 .EQU B6_SCAN, 0x1 .EQU B7_MT, 0x3 .EQU B7_Trcd, 0x1 .EQU B7_SCAN, 0x1 /*以下4个寄存器是针对sdram专用的*/ /* REFRESH 刷新寄存器的刷新率是需要认真去计算的 */ .EQU REFEN, 0x1 .EQU TREFMD, 0x0 .EQU Trp, 0x0 .EQU Tsrc, 0x3 .EQU REF_CON, 0x510 /*BANKSIZE bk76map的值只要不小于当前sdram的大小即可 */ .EQU BURST_EN, 0x1 .EQU SCKE_EN, 0x1 .EQU SCLK_EN, 0x1 .EQU BK76MAP, 0x1 /*MRSRB6 模式设置寄存器,两个要一样配置,只需要配置cl即可 列地址扫描开关延迟? */ .EQU WBL, 0x0 .EQU TM, 0x0 .EQU CL, 0x3 .EQU BT, 0x0 .EQU BL, 0x0 /*MRSRB7 AS THE SAME AS BANK6*/ .EQU WBL, 0x0 .EQU TM, 0x0 .EQU CL, 0x3 .EQU BT, 0x0 .EQU BL, 0x0 @需要配置的13个寄存器的值放在这里 BANK_BWSCON: .long (B7_BWSCON<<28)+(B6_BWSCON<<24)+(B5_BWSCON<<20)+(B4_BWSCON<<16)+(B3_BWSCON<<12)+(B2_BWSCON<<8)+(B1_BWSCON<<4) .long (B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tcah<<4)+(B0_Tacp<<2)+(B0_PMC<<0) .long (B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tcah<<4)+(B1_Tacp<<2)+(B1_PMC<<0) .long (B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tcah<<4)+(B2_Tacp<<2)+(B2_PMC<<0) .long (B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tcah<<4)+(B3_Tacp<<2)+(B3_PMC<<0) .long (B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tcah<<4)+(B4_Tacp<<2)+(B4_PMC<<0) .long (B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tcah<<4)+(B5_Tacp<<2)+(B5_PMC<<0) .long (B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN) .long (B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN) .long (REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(REF_CON) .long (BURST_EN<<7)+(SCKE_EN<<5)+(SCLK_EN<<4)+(BK76MAP) .long (WBL<<9)+(TM<<7)+(CL<<4)+(BT<<3)+(BL) .long (WBL<<9)+(TM<<7)+(CL<<4)+(BT<<3)+(BL) /*COME ON BABY*/ .globl memsetup memsetup: @ ldr r0,=BANK_BWSCON @为什么不可以 我还不知道呢 adrl r0,BANK_BWSCON @将BANK_BWSCON地址装载进r0 ldmia r0,{r1-r13} /*13个寄存器来储存 连续的13个4字节值 前面解释过*/ ldr r0,=BWSCON @需要装载到的位置,因为这13个寄存器的地址是连续的,所以指定开始就好 stmia r0,{r1-r13} /*因为这13个要初始化的寄存器地址是连续的 所以可以这么做*/ mov pc,lr
c代码led.c
#include"led.h" void key_ctl(); void delay(int); void led_loop(); int led_test() { GPBCON =GPB05OUT | GPB06OUT | GPB07OUT | GPB08OUT ; //out led_loop(); key_ctl(); return 0; } //延时函数 void delay(int times) {//注意要带上volatile,以免此循环延迟被优化掉,我就吃过亏 volatile unsigned int i,j; for(i=0;i<times;i++) { for(j=0;j<(1<<17);j++); } } //用按键控制led灯,其con设置默认的就是输入状态00 void key_ctl() { unsigned char key; GPBDAT=0; delay(1); while(1){ key= GPFDAT&0x1f; if(key==0x1d) GPBDAT =~(1<<5); else if(key==0xf) GPBDAT =~(1<<6); else if(key==0x1b) GPBDAT =~(1<<7); else if(key==0x1e) GPBDAT =~(1<<8); else GPBDAT =0xffffffff; } } void led_loop() { unsigned int i; unsigned int ledtab[] = {0xEFF, 0xF7F, 0xFBF, 0xFDF}; while(1) { for(i=0;i<4;i++) { GPBDAT=ledtab[i]; delay(1); } } }
Makefile代码
CC=/usr/local/arm/3.3.2/bin/arm-linux-gcc LD=/usr/local/arm/3.3.2/bin/arm-linux-ld CP=/usr/local/arm/3.3.2/bin/arm-linux-objcopy DP=/usr/local/arm/3.3.2/bin/arm-linux-objdump #注意交叉编译器的版本不要太高,否则会报错,我犯过错,记下 sdram.bin : start.S led.c low_init.S $(CC) -c -o start.o start.S $(CC) -c -o led.o led.c $(CC) -c -o low_init.o low_init.S $(LD) -Ttext 0x30000000 start.o low_init.o led.o -o sdram_elf $(CP) -O binary -S sdram_elf sdram.bin $(DP) -D -m arm sdram_elf > sdram.dis clean: rm -f sdram.dis sdram.bin sdram_elf *.o
注意makefile的-Ttext 0x30000000 这个是链接编译地址,跟运行地址是不一样的哦 ,就是因为编译地址跟运行地址不一样
所以uboot的开始才离不开汇编的
附上其他头文件
//led fanction #define GPBCON (*(volatile unsigned long *)0x56000010) //先将地址值其转化为指针,GPBCON其实就变成了这个地址储存的值鸟 哈哈 #define GPBDAT (*(volatile unsigned long *)0x56000014) #define GPBUP (*(volatile unsigned long *)0x56000018) //key addr #define GPFCON (*(volatile unsigned long *)0x56000050) #define GPFDAT (*(volatile unsigned long *)0x56000054) #define GPFUP (*(volatile unsigned long *)0x56000058) #define GPB05OUT (1<<(5*2)) // datasheet info led1 out:01 #define GPB06OUT (1<<(6*2)) #define GPB07OUT (1<<(7*2)) #define GPB08OUT (1<<(8*2)) #define GPF00OUT (1<<(0*2)) #define GPF01OUT (1<<(1*2)) #define GPF02OUT (1<<(2*2)) #define GPF03OUT (1<<(3*2))
//memory register &bankx control register #define BWSCON 0x48000000 #define BANKCON0 0x48000004 #define BANKCON1 0x48000008 #define BANKCON2 0x4800000c #define BANKCON3 0x48000010 #define BANKCON4 0x48000014 #define BANKCON5 0x48000018 #define BANKCON6 0x4800001c #define BANKCON7 0x48000020 #define REFRESH 0x48000024 #define BANKSIZE 0x48000028 #define MRSRB6 0x4800002c #define MRSRB7 0x48000030
ok,经过几天的努力 终于是可以正常初始化sdram 并且搬移代码了
又艰难的向前迈了一步
Jay
2010.01.16 22:29:21