上一篇文章使用crosstool-NG创建了新的linux-gnueabi工具链。本文使用新的工具链创建第一个运行在s3c2440上的程序。
首先创建toolchains.sh,并将该脚本source到当前shell,这样就可以直接使用了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/bin/sh#TOOLCHAIN_DIR=/work/toolchain/gcc-3.4.5-glibc-2.3.6#TOOLCHAIN_PREFIX=arm-linuxTOOLCHAIN_DIR=/work/toolchain/arm-unknown-linux-gnueabiTOOLCHAIN_PREFIX=arm-unknown-linux-gnueabiTOOLCHAIN_BIN_PREFIX=${TOOLCHAIN_DIR}/bin/${TOOLCHAIN_PREFIX}CC=${TOOLCHAIN_BIN_PREFIX}-gccAS=${TOOLCHAIN_BIN_PREFIX}-asCPP=${TOOLCHAIN_BIN_PREFIX}-cppLD=${TOOLCHAIN_BIN_PREFIX}-ldSTRIP=${TOOLCHAIN_BIN_PREFIX}-stripOBJDUMP=${TOOLCHAIN_BIN_PREFIX}-objdumpOBJCOPY=${TOOLCHAIN_BIN_PREFIX}-objcopyREADELF=${TOOLCHAIN_BIN_PREFIX}-readelfRANLIB=${TOOLCHAIN_BIN_PREFIX}-ranlibSIZE=${TOOLCHAIN_BIN_PREFIX}-sizeSTIRNGS=${TOOLCHAIN_BIN_PREFIX}-stringAR=${TOOLCHAIN_BIN_PREFIX}-arNM=${TOOLCHAIN_BIN_PREFIX}-nmADDR2LINE=${TOOLCHAIN_BIN_PREFIX}-addr2lineexport CC AS CPP LD STRIP OBJDUMP OBJCOPY READELF RANLIB SIZE STRINGS AR NM ADDR2LINE |
需要具备汇编相关的知识,可参考我之前的文章。start.S准备入口,提供_start符号。
1 2 3 4 5 6 7 8 9 10 | .text .global _start_start: ldr r0, =0x53000000 mov r1, #0 str r1, [r0] @ disable watchdog ldr sp, =1024*4 bl mainloop: b loop |
这个汇编文件干2件事情:关看门狗;设置栈,跳转到main执行。编译方法:
1 | $(AS) -o start.o start.S |
main函数,进行跑马灯操作,就是循环设置LED的GPIO寄存器,这里用c实现最简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /* * my s3c2440 develop board has 4 led * led1 ==> GPF4 * led2 ==> GPF5 * led4 ==> GPF6 * led8 ==> GPF7 */#define GPFCON (*(volatile unsigned long *)0x56000050)#define GPFDAT (*(volatile unsigned long *)0x56000054)#define GPF4_out (1<<(4*2))#define GPF5_out (1<<(5*2))#define GPF6_out (1<<(6*2))void main(){ int i = 0, j = 4; // configure gpio as output mode GPFCON = GPF4_out | GPF5_out | GPF6_out; while (1) { i++; if (i == 30000) { GPFDAT = ~(1 << j); j++; if (j == 7) j = 4; i = 0; } }} |
编译:
1 | $(CC) -c -o led.o led.c |
使用自定义的简单链接脚本,需要具备ld相关的知识,可参考本站ld分类中的文章。
1 2 3 4 5 6 | SECTIONS{ . = 0; .text : { *(.text) } .data : { *(.data) }} |
定义链接地址从0开始,因为编译出的binary放在NAND的首4K处,被拷贝到内部SRAM,从地址0开始执行。此处链接器会将_start入口放在.text段的最前面。
链接:
1 | $(LD) T bare.lds -o led_elf start.o led.o |
链接生成的led_elf是ELF格式文件,包括ELF头等信息,需要有辅助程序(loader)才能运行,所以需要使用objcopy工具生成二进制文件。objcopy的工作是把.text和.data段抽出,这样CPU就可从.text最开始处开始执行,不需要别人的帮助。
1 | $(OBJCOPY) -O binary -S led_elf led_bin |
将led_bin烧录到s3c2440的nand,重启切换到nand启动,可以看到3个LED开始轮流亮。