天天看点

SDRAM初始化+存储设备初始化 代码

       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

继续阅读