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