因为要移植一个微内核到6410的体系上,我手里正好有一块友坚恒天的UT6410BV04的开发板,在这个板子上有D4、D5、D7、D8四个LED灯,经过查看原理图,知道它们分别对应GPM0~GPM3,查看Datasheet,知道GPMCON的物理地址是0x7F008820,GPMDAT的地址是0x7F008824,下面编写程序控制LED灯亮灭,程序有两种写法,一是汇编实现,一是C实现:
一、汇编实现:
# touch led_on.S
# gedit led_on.S
.text
.global _start
_start:
ldr r0, =0x7f008820
mov r1, #0x00000001
str r1, [r0]
ldr r0, =0x7f008824
mov r1, #0x00000000
str r1, [r0]
main_loop:
b main_loop
Makefile的内容:
CROSS_COMPILE := /usr/local/arm/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
led_on.bin : led_on.S
$(CC) -g -c -o led_on.o led_on.S
$(LD) -Ttext 0x0000000 -g led_on.o -o led_on_elf
$(OBJCOPY) -O binary -S led_on_elf led_on.bin
clean:
rm -f led_on.bin led_on_elf *.o
二、C实现
ARM Linux C环境需要crt0.S构建运行环境,诸如SP之类的,因此先建立crt0.S,下面是crt0.S的内容:
.text
.global _start
_start:
ldr r0, =0x53000000
mov r1, #0x0
str r1, [r0]
ldr sp, =1024*4
bl main
halt_loop:
b halt_loop
然后建立C文件:led_on_c.c,其内容为:
#define GPMCON (*(volatile unsigned long *)0x7F008820)
#define GPMDAT (*(volatile unsigned long *)0x7F008824)
int main()
{
GPMCON = 0x00000101;
GPMDAT = 0x00000000;
return 0;
}
下面是Makefile:
CROSS_COMPILE := /usr/local/arm/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
led_on_c.bin : crt0.S led_on_c.c
$(CC) -g -c -o crt0.o crt0.S
$(CC) -g -c -o led_on_c.o led_on_c.c
$(LD) -Ttext 0x0000000 -g crt0.o led_on_c.o -o led_on_c_elf
$(OBJCOPY) -O binary -S led_on_c_elf led_on_c.bin
$(OBJDUMP) -D -m arm led_on_c_elf > led_on_c.dis
clean:
rm -f led_on_c.dis led_on_c.bin led_on_c_elf *.o
然后编译之后,使用dnw,开发板加电,在uboot下使用usb OTG下载程序到开发板内存0xc0008000,然后:
go 0xc0008000启动程序运行,可以看到LED灯根据控制变亮或者灭掉。
问题1 GPIO( 在上一篇文章说过啦)
问题2 值的确定
/ uboot/include/s3c6410.h
/*
* GPIO
*/
#define ELFIN_GPIO_BASE 0x7f008000
#define GPACON_OFFSET 0x00
#define GPADAT_OFFSET 0x04
#define GPAPUD_OFFSET 0x08
#define GPACONSLP_OFFSET 0x0C
#define GPAPUDSLP_OFFSET 0x10
#define GPBCON_OFFSET 0x20
#define GPBDAT_OFFSET 0x04
#define GPBPUD_OFFSET 0x08
#define GPBCONSLP_OFFSET 0x0C
#define GPBPUDSLP_OFFSET 0x30
*****
****
*******
#define GPLPUD_OFFSET 0x81C
#define GPMCON_OFFSET 0x820
#define GPMDAT_OFFSET 0x824
#define GPMPUD_OFFSET 0x828
#define GPNCON_OFFSET 0x830
#define GPNDAT_OFFSET 0x834
#define GPNPUD_OFFSET 0x838
#define GPOCON_OFFSET 0x140
#define GPODAT_OFFSET 0x144
#define GPOPUD_OFFSET 0x148
在核心板图中能找到子上有D4、D5、D7、D8四个LED灯,经过查看原理图,知道它们分别对应GPM0~GPM3
知道GPMCON的物理地址是0x7F008820,GPMDAT的地址是0x7F008824, 上面的头文件给出。
********************************************************************************************************
作者Makefile写的不错:嘿嘿,分析:
objcopy
GNU objcopy 程序拷贝目标文件的内容到另一个文件。objcopy使用GNU BFD 库读写目标文件. 它可以把源目标文件的内容用不同的格式写入另一个目标文件。命令行选项决定objcopy确切的行为。 注意objcopy应该可以在两种格式之间拷贝经过充分连接的文件。 然而,在两种格式之间拷贝可重定位 的目标文件可能不象预期一样工作。objcopy 产生一些临时文件去做转换工作,这些文件过后被删除掉。 objcopy使用BFD库 来做所有的转换工作。它可以访问BFD描述的所有格式,因而能够识别大部分的格式,即便 没有显式地被告知。
objcopy 可以被使用来产生S记录。(.e.g use -O srec) objcopy 可以被用来产生纯二进制文件。 (.e.g use -O binary) 当 objcopy产生纯二进制 文件时,本质上它会产生输入目标文件的一个内存映像。 所有的符号及重定位信息将被丢弃掉。当产生一个S记录或纯二进制文件时,用-S 选项去掉包含调试信息的段是比较有帮助的。在 某些情况下 用-R 选项去掉二进制文件中的不需要的段是有帮助的。
objdump
objdump:用来显示目标文件的信息. 可以通过选项控制显示那些特定信息. objdump一个最大的用处恐怕
# 就是将C代 码反汇编了. 在嵌入式软件开发过程中, 也可以用它查看执行文件或库文件的信息.
问题3
我们先来分析文件 crt0.s
@ 文件 crt0.s
@ 作用:设置堆栈指针
.text
.global _start
_start:
ldr sp, =1024*4
bl main
halt_loop:
b halt_loop
你可能会有疑问,这个汇编文件有什么用?呵呵,这是因为我们的串口通信代码要用 C
编写(用汇编可读性太差了)。可这又和这个 crt0.s 有什么关系呢?这得从 C 语言程序的
编译说起。C 语言程序执行的第一条指令并不在 main 函数里。当生成一个 C 语言程序时
编译器总是在我们的代码前加一段固定的代码--crt0.o,它是编译器自带的一个文件,用来
设置 C 程序的堆栈等,然后调用 main 函数。可惜在我们的裸板上它自带的 crt0.o 的代
码是不能运行的,我们得自己动手写,这就是为什么要有 crt0.s 这个文件。稍后你将看到,
这个 crt0.s 被编译成我们自己的 crt0.o 文件。
问题4 0x53000000