分类:
2010-12-01 20:40:35
原文地址:(二)、 点亮LED 作者:machoe
嵌入式是一行涉及范围很广的行业,对于其硬件的体系结构、汇编与C编程语言、操作系统的使用和认识,一直到最后的Bootloader和内核移植、驱动、应用程序开发,每一个环节都涉及很多的知识,如果想把每一个环节吃透、消化掉,没有个3、5个月,恐怕也是不可能的。而初学者所容易走的也只是两条路:一条路就是拿来一本厚厚的书就从头到尾通读,读完一本又一本,结果没记住什么,拿来板子不会烧程序更不会编程序;另一条路就是买了开发板就从例程开始,拿来代码就编译下载,有了实验现象就乐不思蜀了,再回来看代码也不能好好斟酌,得过且过,这就导致了,只能看懂别人的代码,没有自己的东西。
鉴于以上两点,我在后面的学习心得中,我会结合知识和代码,只重点讲解和例程有关的知识点,后面会告诉大家去读哪些有用的文章和书籍,但这里,我建议读者重点看我讲的知识点,不要拿来一本书就一下子看完,把所有的东西全记住,“一口是吃不成胖子”的,随着本套博客系统的推出,当我们完成了本阶段的学习后,我想我们已经积累了很多的知识点,再回过头来看一些大作,如:《ARM体系结构与编程》也不会那么吃力了,我当时初学时,就通读了这篇大作,说实话,当时只理解了不到20%,现在再回头看看,感觉理解的要深得多了。
最后,由于我们是在LINUX环境下进行开发的,建议对不了解LINUX操作系统的朋友找一本书来看看,建议也不要通读,用一点,学一点,学一点,用一点,慢慢积累,这样等经过一段时间的学习,也就能慢慢掌握了。
提到“程序”,大家首先想到的是肯定是我们自己所书写的一行行代码,如C代码、汇编代码。然而,我们仅仅知道这些还是不够的。相信现在学习嵌入式的朋友们,肯定多多少少有一些计算机、单片机的基础知识,计算机(我们常说的INTEL和AMD的CPU)也好,单片机(如8051)也好,他们可不认识我们所写的“代码”,这就像我们和一个不懂“汉语”的外国人说中文一样,他根本不会理解你说的是什么。
CPU所能认识的只是二进制的机器码,通常以.bin结尾,而我们所书写的代码(以C语言为例)被我们称为源文件,通常以.c结尾。这时,就有一个问题摆在我们面前了。在现实生活中,如果遇到外国人,我们可以请一个翻译将我们讲的中文翻译成外语,这样就达到了沟通的目的,而在嵌入式这个特殊领域里,我们也可以找一个“翻译”,它就是----编译器。
编译器的工作就像翻译一样,将我们写的源文件:C代码和汇编代码翻译成CPU所认识的二进制文件,这样CPU就可以执行我们的指令了。注意:在我们现在所用到的编译器通常指预编译器、编译器、汇编器、链接器和反汇编器这些工具的总和,这些工具各自起到不同的作用,在后续的文章中,会一一讲解。这里读者需要理解可执行程序的形成过程:
上图是孙鑫老师的C++课程中课件截图,C++程序和我们现在学习的C程序编译的过程原理是一样的,请大家深入理解。
LINUX下的编程基础 、LINUX下的编译器相信从WINDOWS转向LINUX的程序员都会抱怨,WINDOWS中集成开发平台多的让人眼花,而LINUX至今大部分人还是使用命令行的方式去编辑,编译程序,麻烦得要命。其实LINUX中也有很好的集成开发平台,在我们装好的Fedora中系统自带的一个Eclipse就是一个很典型的开发平台,另外GNU还为我们提供了很多集成开发平台,如KDevelop,只不过目前,大部分LINUX程序员(至少从事嵌入式开发的)还是比较习惯使用古老和命令行开发模式。
这里,我也推荐大家使用命令行的开发模式,初学肯定会遇到困难,不过同样也会有好处的,这样更容易让初学者理解程序的运行机制。
在我们以后的学习中,我们使用的是交叉编译器,arm-linux- ,这里推荐使用天嵌已制作好的,当大家入门后,可以自己制作编译器。之所以称为交叉编译器,是因为,我们在PC机上编辑代码,编译、链接最后形成在ARM平台下执行的程序。(注:x86体系下的编译器为GCC,大家可自行参考GCC手册)
但这点要特别注意:大家一定要安装3.4.5版本,因为我们这里使用编译器主要编译裸奔程序,天嵌提供的另一版本4.3.3对裸奔程序支持不好。具体的安装方法详细天嵌的教程手册:
“TQ2440开发板使用手册V2.5_20100611.pdf”第85页。
A.这里只简单介绍该命令的使用方法,详细资料可详读参考资料中的《嵌入式LINUX应用开发完全手册》第3章。
-c 对源文件进行预处理、编译、汇编,但不做链接,生成中间OBJ文件,通常以.o结尾。
-g 添加调试信息
-o 指定输出文件。如果不指定-o filename 选项,默认输出为a.out文件。
arm-linux-ld-Ttext startaddr
-Tdada startaddr
-Tbss startaddr
其中-T选项用来指定代码段、数据段、BSS段的起始地址。此外,还可以用来指定的链接脚本。本章中不涉及链接脚本,后续会详述。
知识点: 可执行程序是由代码段、数据段、BSS段组成的。 数据段:存放的是初始化的全局变量和静态变量。 BSS段:存放的是未初始化的全局变量和静态变量。
用于将一个目标文件复制到另一个文件内,可以使用不同于源文件的格式输出到目的文件。常用于格式转化。
-O 用于指定输出的文件格式。如二进制 –O binary
-I 用于指定源文件的格式
-S 不从源文件中复制重定位信息和符号信息到目标文件
. arm-linux-objdump用于显示二进制文件住处。常用于进行反汇编,方便调试。
-D 反汇编所有段
-m 指定反汇编目标文件所使用的架构,如 –m arm 指定为ARM体系架构。
-b 指定输入文件的格式,这不是必须的,arm-linux-objdump能自动识别多种格式。
Makefile关于Makfile要介绍的实在是太多了,这里仅简单进行说明,请大家参考《GNU makefile 手册》。
目标(target)……. : 信赖(prerequiries)…
这里需要注意的是命令前面一定要使用TAB键,不能用空格。请参照后面的实例进行学习,看手册不要看得太多,要边学边用,这样才会达到最好的效果。
LED 硬件介绍TQ2440开发板使用的是S3C2440 CPU,请大家学习本章的同时,参看S3C2440手册。
S3C2440有130复用I/O口。从GPA~~GPJ,其中需要注意的是没有GPI端口。这些端口和单片机的P0~P3口十分相似,初学者可以完成“当成”是单片机的IO口来操作。
为了点亮我们开发板的LED,我们参考一下天嵌开板的原理图。
上述原理图分别取自于核心板原理图和扩展板原理图。上图表明,4个LED连接在CPU的GPB5、6、7、8端口,而且是共阳的连接方式,如果要使其点亮,我们应该在这些端口中输出“0”。
寄存器简介请大家参看手册。
GPIO引脚是通过寄存器来操纵的,由于GPIO引脚大部分都是复用功能,除了通用的I/O端口外,还有其它的功能,在上图中可以看出,GPB5还有一个名称叫“nXBACK”,因此,我们需要一个寄存器来选择它是通用的I/O功能还是额外的功能,这个寄存器就叫GPBCON。
除了GPBCON,GPB端口还有两个寄存器:GPBDAT,GPBUP。GPBDAT用于确定引脚的电平状态,当读操作时,读该寄存器就可以知道引脚是高电平或低电平;当写操作时,向寄存器中写0或1 ,就可以操纵引脚了。
三个寄存器的地址:
GPBCON 0x56000010
GPBDAT 0x56000014
GPBUP 0x56000018
实例分析下面列举出的是韦东山老师的代码:
@******************************************************************************
@ File:led_on.S
@ 功能:LED点灯程序,点亮LED1
@******************************************************************************
.text @定义一个代码段
.global _start @定义一个全局入口
_start: @全局入口处
LDR R0,=0x56000010 @ R0设为GPBCON寄存器。此寄存器
@ 用于选择端口B各引脚的功能:
@ 是输出、是输入、还是其他
MOV R1,#0x00000400
STR R1,[R0] @ 设置GPB5为输出口, 位[10:9]=0b01
LDR R0,=0x56000014 @ R0设为GPBDAT寄存器。此寄存器
@ 用于读/写端口B各引脚的数据
MOV R1,#0x00000000 @ 此值改为0x00000020,
@ 可让LED1熄灭
STR R1,[R0] @ GPB5输出0,LED1点亮
MAIN_LOOP:
B MAIN_LOOP
除了韦东山老师的注释,我又增加了一些,如果看这段程序还吃力的同学,请查阅《ARM体系结构与编程》中的相关章节,请注意,只要看懂上述代码即可,不求将所有的指令全掌握。
上述代码只是源文件,我们还需将其编译成可执行的.BIN文件,请看下面的Makefile文件。
led_on.bin : led_on.S #由led_on.S源文件生成led_on.bin文件
arm-linux-gcc -g -c -o led_on.o led_on.S #将源文件编译,但不链接,生成led_on.o中间文件
arm-linux-ld -Ttext 0x0000000 -g led_on.o -o led_on_elf #将中间文件链接成起始地址为0x0000000的.elf文件
arm-linux-objcopy -O binary -S led_on_elf led_on.bin #将.elf可执行文件的格式转化成.BIN格式
cp led_on.bin /opt/machoe/tftpboot –f #将生成的.BIN文件复制到TFTP目录下,见第一章。
clean:
rm -f led_on.bin led_on_elf *.o
在文章发表后,我会将源代码打包,放到网上,网址稍后会公布出来。
在该文件夹下,点击make,可以看到下图:
上图表明,我们已经成功编译,下面就烧录到开发板中,验证一下我们的实验结果。
具体的操纵方法如下(详见第一章):
1. 打开MINICOM。
2. 启动开发板,从NOR FLASH启动。
3. 按q退出BOOTLOADER。
4. 使用如下命令烧写并执行程序,见下图:
这时我们会在开发板中看到,第一个LED被点亮。
请大家熟悉操纵流程,并试着自己改一下代码,点亮两个LED。以上部分所涉及的知识点较多,希望大家不要满足,多参考其它资料以充实。
1.韦东山 《嵌入式LINUX应用开发完全手册》 第2、3、5章
2.杜春雷 《ARM体系结构与编程》 指令介绍章节
3.三星公司 《S3C2440手册》 指令介绍章节和第9章
4.《GNU GCC手册》
5.《GNU Makefile 手册》