一个简单的arm 裸机程序
是参照网上的一些例子
start.S
.globl _start /*汇编的入口, 生成bin文件的开始处的标识, 把程序加载到某个地址, 用go 命令 go addr, 执行的就是下面的一条指令 */
_start:
/* peri port setup = Peripheral port setup */
ldr r0,=0x70000000
orr r0, r0, #0x13
mcr p15, 0, r0, c15, c2, 4 /*写处理器的操作 mcr move to coprocessor from register */
/*
当时很疑惑,不知道这段代码有什么用,经过一番查找,原来和ARM的协处理器有关,如下所示:
c15, Peripheral Port Memory Remap Register。
/* close watch dog 0x7e004000文档上有, 是在上一步的基础上的 */
ldr r0,=0x7e004000
mov r1, #0
str r1, [r0]
/* setup sp */
ldr sp,=0x50000000 + 8*1024 /* 不知道 与0x50000000 + 4*1024的区别, 是sd or nand 方式 设置栈指针 */
/* go to setup clock 调用c函数 bl = branch with link */
bl clock_init
halt:
b halt
end of start.S
main.c
#define GPKCON0 (*((volatile unsigned long *)0x7f008800))
#define GPKDAT (*((volatile unsigned long *)0x7f008808))
/* Bit Operate */
#define SET_BIT(x,y) (x|=(1<<y)) // 设置 x的ybit为 1
#define CLR_BIT(x,y) (x&=~(1<<y)) // 设置x的ybit为0
#define CPL_BIT(x,y) (x^=(1<<y)) // 设置x的ybit为原来的反 1-》0 0-》1
#define GET_BIT(x,y) (x&(1<<y)) // 获取x的ybit的值 如x=0x09123456 GET_BIT(x,24) 返回 0x01000000
void delay()
{
volatile unsigned long i=0x100000;
while(i--)
;
}
void clock_init()
{
int i=0;
GPKCON0=0x11110000; // gpk的控制寄存器 表示控制 led1 -led4
GPKDAT=0XF0; // gpk的数据寄存器 数据为0 表示低电平 来点亮led
for(i=0;i<100;i++)
{
if(i%2==0)
CLR_BIT(GPKDAT,4);
else
SET_BIT(GPKDAT,4);
if(i%2==0)
SET_BIT(GPKDAT,6);
else
CLR_BIT(GPKDAT,6);
delay(); //延时函数
}
}
makefile
led.bin: start.o main.o
arm-linux-ld -Ttext 0x50000000 -o led.elf $^ #生成elf文件 text的第一条指令定位到0x50000000 (我们之后要加载的地方一致)
arm-linux-objcopy -O binary led.elf led.bin #去掉elf文件的其他信息数据, 使text的第一条指令位于文件的开始
arm-linux-objdump -D led.elf > led.dis #led.elf的相关符号信息
%.o : %.S
arm-linux-gcc -o $@ $< -c
%.o : %.c
arm-linux-gcc -o $@ $< -c
clean:
rm *.o led.bin led.dis
end of makefile
进入到uboot命令行发
tftp 0x50000000(与编译一致) led.bin # 把led.bin 从tftp服务器加载到内存的0x50000000处
go 0x50000000 # 可以看到效果了