S3C6410裸奔——LED
扫描二维码
随时随地手机看文章
最近拿出了空闲已久的Tiny6410开发板来玩一下,一直对Linux有变态的崇拜,所以这次过度没有悬念的抛弃诸如ADS1.2或RVDS等IDE开发环境。完全的VIM + GCC搞定一切。
言简意赅,生成的BIN放入SD卡中启动,详细过程参见Tiny6410的帮助文档,配置文件附送光盘里都有。
这里仅主要介绍一下如何点亮核心板上的4个LED,当然在此之前arm-linux-gcc交叉编译环境要搭建起来,还要添入环境变量之中(在终端中输入arm-linux-gcc -v 看是否能正确的查询到当前交叉编译器的版本号以检查是否添加成功,出现如图所示说明添加成功)。
为了点亮LED,我们先看一下友善之臂Tiny6410开发板关于LED的原理图部分。
由图可见,我们要操作的LED分别由GPK[4-7]口控制。
然后就是看一下三星的datasheet了。
可见我们把输入方向配置为输出,并输出低电平LED才会亮。
首先先看汇编代码。
@********************************************@File:led_on.s@function:LED@author:pang123hui@********************************************.text@定义一个代码段.global_start@定义一个全局入口_start:@全局入口处LDRR0,=0x7F008800@设R0为GPKCON0寄存器MOVR1,#0x11112222@设置GPKC[4-7]为输出STRR1,[R0]LDRR0,=0x7F008808@R0设为GPKDAT寄存器MOVR1,#0x00000000@设置GPKDAT[4-7]为低电平STRR1,[R0]MAIN_LOOP:BMAIN_LOOP
汇编里的B指令为跳转指令,直接向PC寄存器赋值。B跳转是个相对跳转指令,其机器吗格式如下:
即B跳转指令依赖于当前PC寄存器的值,这个特点使得使用B指令的程序不依赖于代码存储的位置——即不管这条代码放在什么位置,B指令都可以跳到正确的位置。这类指令被称为位置无关码。
还有一条BL指令,除了条装之外,还将返回地址(BL的下一条指令的地址)保存在LR寄存器中,也是位置无关的指令。
B和BL指令可跳转的范围是当前指令的前后32MB.
相关Makefile文件。
CC=arm-linux-gccCFLAGS=-g-c-oled_on.bin:led_on.s$(CC)$(CFLAGS)led_on.oled_on.sarm-linux-ld-Ttext0x0000000-gled_on.o-oled_on_elfarm-linux-objcopy-Obinary-Sled_on_elfled_on.binclean:rm-fled_on.binled_on_elf*.o
简单介绍一下相关指令。
A.arm-linux-gcc
-c 对源文件进行预处理、编译、汇编,但不做链接,生成中间OBJ文件,通常以.o结尾。
-g添加调试信息
-o 指定输出文件。如果不指定-o filename选项,默认输出为a.out文件。
B. arm-linux-ld
-Ttext startaddr
-Tdada startaddr
-Tbss startaddr
其中-T选项用来指定代码段、数据段、BSS段的起始地址。如果不定义数据段和BBS段的起始地址,它们会被依次放在代码段的后面。
C. arm-linux-objcopy
用于将一个目标文件复制到另一个文件内,可以使用不同于源文件的格式输出到目的文件。常用于格式转化。
-O用于指定输出的文件格式。如二进制–O binary
-I 用于指定源文件的格式
-S 不从源文件中复制重定位信息和符号信息到目标文件
D. arm-linux-objdump用于显示二进制文件住处。常用于进行反汇编,方便调试。
-D 反汇编所有段
-m 指定反汇编目标文件所使用的架构,如–m arm指定为ARM体系架构。
-b指定输入文件的格式,这不是必须的,arm-linux-objdump能自动识别多种格式。
C语言代码。
#definerGPKCON0(*(volatileunsigned*)(0x7F008800))#definerGPKCON1(*(volatileunsigned*)(0x7F008804))#definerGPKDAT(*(volatileunsigned*)(0x7F008808))#definerGPKPUD(*(volatileunsigned*)(0x7F00880C))intmain(void){//设置GPKCON[4-7]为输出rGPKCON0=0x11112222;//设置GPKDAT[4-7]为低电平rGPKDAT=0xffffff0f;return0;}
有些学习过Bootloader和内核的朋友肯定会知道,在调用C语言函数之前肯定会有一段汇编代码在前面铺路,进行一些必要的初始化工作;而那些只学过单片机而没有学过ARM的朋友肯定会觉得很奇怪,在单片机中写C代码,前面完成可以不用任何汇编代码。这是为什么呢?
这主要是因为我们的开发环境(这里主要是指编译环境)的不同,在开发单片机程序的时候,开发环境(如KEIL)会在编译C代码的时候,给我添加启动代码(startup-51)或者在编译时已经由编译器在后台为我们初始化好了。而在开发ARM程序时,ARM处 理器支持多种模式,多种功能,而在不同的领域不同的项目里面,我们可以有选择的、适当的选择这些功能,这时,编译器就不知道我们需要什么功能,需要什么模 式,编译器也就无法给我们提供默认的“初始化”代码,所以,编译器干脆就“不管”这些了,把这些工作交由我们开发者来处理。
这里最简单的启动代码。
@****************************************@File:startup.s@function:startup@author:pang123hui@****************************************.text.global_start_start:LDRR0,=0x7E004000@WATCHDOG寄存器地址MOVR1,#0x0STRR1,[R0]@写入0,禁止WATCHDOG,否则CPU会不断重启LDRSP,=0x0c001000@设置堆栈,注意:这时我们是将程序直接烧录到SDRAM中,所以堆栈要设置在SDRAM中@如果将程序烧在NANDFLASH中,需将堆栈改为1024*4,因为NANDFLASH中的代码@在复位后会移到内部RAM中,此RAM只有4KBLmain@调用C程序中的main函数halt_loop:Bhalt_loop
这里要注意的一点是S3C6410中RAM的地址,见datasheet,如图。
最后是Makefile文件。
CC=arm-linux-gccCFLAGS=-g-c-oled_on.bin:startup.smain.c$(CC)$(CFLAGS)startup.ostartup.s$(CC)$(CFLAGS)main.omain.carm-linux-ld-Ttext0x0c000000-gstartup.omain.o-oled_on_elfarm-linux-objcopy-Obinary-Sled_on_elfled_on.binclean:rm-fled_on.binled_on_elf*.o
东西很简单没什么好说的,在此记录,以免忘记,如有疑问或发现本文有何错误,欢迎提出。