1.1.8 内存驱动实验
设置该工程加载时运行时地址为0x30000000,如图2-55所示:
图2-55设置加载时运行时地址
init.s:本程序文件主要实现了,关闭看门狗,初始化内存,拷贝ROM数据到内存中,然后跳往内存中执行xmain函数,从xmain函数返回之后,将全部led点亮,进入死循环。
;
; 内存初始化实验
;
AREA Init, CODE, READONLY
ENTRY
start
; close watchdog
ldr r0, = 0x53000000 ; 将看门狗控制寄存器地址放入r0
mov r1, #0
str r1, [r0] ; 设置看门狗控制寄存器的值为0
bl initmem ; 跳转到initmem代码段,初始化内存
bl copyall ; 跳转到数据拷贝代码段,将ROM中数据拷贝到内存中
IMPORT xmain ; 引入main.c中的xmain函数
ldr sp, =0x34000000 ; 调用C程序之前先初始化栈指针
ldr lr, =endxmain ; 设置xmain函数的返回地址
ldr pc, =xmain ; 跳转到C程序中的xmain函数的入口处执行
endxmain
ldr r0, =0x56000010 ; LED的GPIO接口配置寄存器
ldr r1, =0x00015400 ; GPIO配置数据
str r1, [r0] ; 设置GPIO
ldr r0, =0x56000014 ; LED控制寄存器地址
ldr r1, =0x0 ; 全部LED亮
str r1,[r0]
loop
b loop ; 死循环
copyall
IMPORT |Image$$RO$$Base| ; 引入编译器Image$$RO$$Base符号变量
IMPORT |Image$$RW$$Limit| ; 引入编译器Image$$RW$$Limit符号变量
ldr r0, = |Image$$RO$Base| ; 取得Image$$RO$Base域基址的值
ldr r1, = |Image$$RW$$Limit| ; 取得Image$$RW$Base域结束地址的值
ldr r2, =0x0 ; 数据拷贝源地址
copyallloop
teq r0,r1 ; 测试是否拷贝完成
beq quitcopyallloop ; 拷贝完成,跳往quitcopyallloop退出
ldr r3, [r2], #4 ; 四字节加载
str r3, [r0], #4 ; 四字节存储
b copyallloop ; 返回继续执行
quitcopyallloop
mov pc, lr ; 调用返回
initmem ; 内存初始化
ldr r0, =0x48000000 ; 加载内存相关寄存器首地址r0
ldr r1, =0x48000034 ; 加载内存相关寄存器尾地址到r1
adr r2, memdata ; 将寄存器配置数据地址段首地址加载到r2
initmemloop
ldr r3, [r2], #4 ; 循环设置存寄存器
str r3, [r0], #4
teq r0, r1
bne initmemloop ; 循环到最后一个寄存器时退出函数
mov pc,lr
memdata
DCD 0x22000000 ;BWSCON
DCD 0x00000700 ;BANKCON0
DCD 0x00000700 ;BANKCON1
DCD 0x00000700 ;BANKCON2
DCD 0x00000700 ;BANKCON3
DCD 0x00000700 ;BANKCON4
DCD 0x00000700 ;BANKCON5
DCD 0x00018005 ;BANKCON6
DCD 0x00018005 ;BANKCON7
DCD 0x008e07a3 ;REFRESH
DCD 0x000000b1 ;BANKSIZE
DCD 0x00000030 ;MRSRB6
DCD 0x00000030 ;MRSRB7
END
main.c:本程序文件主要实现led灯的初始化,然后四个led灯循环滚动亮5遍,xmain函数返回。
/* C语言函数 */
/* 端口F寄存器预定义 */
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
#define LEDS (1<<5|1<<6|1<<7|1<<8)
#define DELAYVAL (0x1ffff)
extern int delay(int time); /* 声明外部声明汇编函数 */
int i = 5;
int xmain()
{
GPBCON = 0x00015400; //GPF4--GPF7设置为output
while(i > 0) {
//第一个LED灯亮
GPBDAT=(GPBDAT&(~LEDS)) | (1<<6|1<<7|1<<8);
delay(DELAYVAL); //调用汇编语言编写的延时程序
//第二个LED灯亮
GPBDAT=(GPBDAT&(~LEDS)) | (1<<5|1<<7|1<<8);
delay(DELAYVAL); //调用汇编语言编写的延时程序
//第三个LED灯亮
GPBDAT=(GPBDAT&(~LEDS)) | (1<<5|1<<6|1<<8);
delay(DELAYVAL); //调用汇编语言编写的延时程序
//第四个LED灯亮
GPBDAT=(GPBDAT&(~LEDS)) | (1<<5|1<<6|1<<7);
delay(DELAYVAL); //调用汇编语言编写的延时程序
i--;
}
return 0;
}
delay.s:本程序文件主要通常汇编来实现延时功能。
;汇编指令延时程序
EXPORT delay
AREA DELAY,CODE,READONLY ;该伪指令定义了一个代码段,段名为Init,属性只读
;下面是延迟子程序
delay
sub r0,r0,#1 ;r0=r0-1
cmp r0,#0x0 ;将r0的值与0相比较
bne delay ;比较的结果不为0(r0不为0),继续调用delay,否则执行下一条语句
mov pc,lr ;返回
END ;程序结束符
内存的初始化也可以用下面的C程序实现:
C语言版本:
#define MEM_CTL_BASE 0x48000000
#define MEM_CTL_END 0x48000034
/* SDRAM 13个寄存器的值 */
unsigned long const mem_cfg_val[]={ // 声明数组存放内存控制器设置数据
0x22000000, //BWSCON
0x00000700, //BANKCON0
0x00000700, //BANKCON1
0x00000700, //BANKCON2
0x00000700, //BANKCON3
0x00000700, //BANKCON4
0x00000700, //BANKCON5
0x00018005, //BANKCON6
0x00018005, //BANKCON7
0x008e07a3, //REFRESH(HCLK = 12MHz,该值为0x008e07a3
//HCLK = 100MHz 0x008e04f5)
0x000000b1, //BANKSIZE
0x00000030, //MRSRB6
0x00000030, //MRSRB7
};
void mem_init(void)
{
int i = 0;
unsigned long *p = (unsigned long *)MEM_CTL_BASE;
for(; i < (MEM_CTL_END - MEM_CTL_BASE)/4; i++)
p[i] = mem_cfg_val[i];
}
