不按datasheet介绍,从实战出发

上传人:鲁** 文档编号:476672877 上传时间:2023-06-26 格式:DOC 页数:31 大小:86.50KB
返回 下载 相关 举报
不按datasheet介绍,从实战出发_第1页
第1页 / 共31页
不按datasheet介绍,从实战出发_第2页
第2页 / 共31页
不按datasheet介绍,从实战出发_第3页
第3页 / 共31页
不按datasheet介绍,从实战出发_第4页
第4页 / 共31页
不按datasheet介绍,从实战出发_第5页
第5页 / 共31页
点击查看更多>>
资源描述

《不按datasheet介绍,从实战出发》由会员分享,可在线阅读,更多相关《不按datasheet介绍,从实战出发(31页珍藏版)》请在金锄头文库上搜索。

1、不按datasheet介绍,从实战出发思路: 不按datasheet介绍,从实战出发,以例子为基础讲解概念 第一章无论学习一门语言还是一个新的平台上开始开发,从最简单的例子入手总是最容易的,比如C语言学习中的HelloWorld程序,一个简单的例子,不但可以消除接触新语言新平台的恐惧感,而且可以用最小的代价,完成一个从源程序到最终运转的实际应用。和语言学习一样,在Arm平台上的嵌入式开发,我们也遵循这个步骤,从一个打印出的HelloWorld的应用开始,进入到嵌入式开发的世界。相比一门语言的HelloWorld,Arm平台的HelloWorld要略显复杂一些。以Linux平台的C语言Hello

2、World程序为例,我们只需要选用正确的编译工具,编译下面的程序,生成一个可执行文件,然后运行这个程序,就会在屏幕上打出“HelloWorld”。#include int main() printf(“HelloWorldn”); return 0;嵌入式平台的HelloWorld,不是在一个现成的操作系统上运行的单纯程序,因此不但要保成程序的正确性,能编译生成可执行文件,更重要的是在程序运行前,必须要做一系列的准备工作。反过来说,即使生成了可执行文件,如果没有和硬件的配置匹配的话,也是不可能在嵌入式平台上正确的运行的。这一章的目标就是从一个C语言的HelloWorld为基础,打造一个能在嵌入

3、式平台上运转的Helloworld开始,一步一步的扩展功能,最后目标是能将得到广泛应用的bootloader U-boot移植到我们的开发板上。第一节 嵌入平台的HelloWorld嵌入式应用程序简介由于我们是在一个没有操作系统的ARM嵌入式平台上开发,因此,和一般操作系统上的C语言程序不同,程序的执行并不是从main函数开始的。根据ARM CPU的式样,在CPU上电启动后的第一个动作就是硬件复位(Reset),当复位完成以后,CPU会发出一个复位异常(Reset Excepton),伴随着这个复位异常,CPU就会到0开始的地址去读取可执行代码。那么如果我们有办法把main函数放到0地址,是不

4、是就可以上电以后就直接执行C语言的main函数了呢?的确,是有办法把main函数放到0开始的地址上的。但是仅有这些是不够的,根据ARM CPU的式样,ARM系统具有8种异常,如表11所示,分别对应8种不同的异常原因,我们刚才提到的复位异常只是其中的一种,对应这些异常,一共有8个异常向量与之相对应,也就是说当某一种异常发生的时候,CPU会自动跳转到这个向量所对应的地址上去,执行预先放到这个地址里的代码。那么显而易见,这些异常响亮必须放到某个预先规定好的地方。对于ARM CPU来说,这个地址固定在从0开始的48=32字节的地址上。由于每个异常向量只能占有4个字节的位置,要想放下这个异常所对应处理的

5、全部代码是不可能的,实际上4个字节只够ARM CPU的一条机器指令,我们唯一的选择就是在这里放一条跳转指令,跳转的目的地才是真正的异常处理程序的地址。总结一下上面所提到的式样,我们发现ARM嵌入平台的入口代码必须满足下面这些要求:1. 从0开始的32个字节必须放置8种异常对应的异常处理代码2. 每个异常处理代码只有4个字节空间,因此必须放入跳转指令3. 0字节开始第一个指令对应系统的复位异常处理而C语言写出的程序,显然不可能精确到机器指令单位。对上述要求来说,唯一的选择就是用汇编语言来实现入口代码。除此之外,在调用C语言函数之前,必须设定好堆栈指针,这也必须用汇编语言来实现。对于一个只有C语言

6、编程经验的人来说,汇编语言似乎是繁琐,晦涩的代名词,其实不然,汇编语言指令虽然不如C语言那么容易读写,但是一旦掌握了常用指令的含义和用法,就会发现汇编语言其实并不难,而且重要的是,一旦我们掌握了汇编语言,就可以写出C等其他高级语言不可能实现或者实现起来很困难的功能,比如我们现在需要的的入口代码程序。本书没有用专门的篇幅来介绍汇编语言的语法,而是结合书中例子里,对涉及到的语法进行说明。读者也可以参考一本系统讲解ARM汇编语法的书,来理解本书中的实例。第一个HelloWorld既然C语言的函数,不能作为整个系统的入口函数,那么我们可以采用任何一个函数作为HelloWorld的C语言入口函数,在这里

7、,为了区别起见,我们把main改成arm_start,让它成为HelloWorld的C语言部分的入口函数。也就是上面汇编程序里调用的C语言入口函数。对于C语言程序来说,因该没有比打印一个”HelloWorld到屏幕上更简单的例子了,可是对嵌入式系统来说,却不是很容易的一件事情。我们知道,printf是C语言的系统函数,所谓系统函数,就是C语言的提供的一些现成的函数库,通常这些系统函数,完成了高级语言到实际硬件设备驱动之间的工作,这些工作是和硬件以及操作系统密切相关的。有了这些系统函数,我们只需要通过简单系统函数调用,比如printf,就可以把一个字符串打印到屏幕上,而不必关心printf的具体

8、实现里有关显示器硬件操作的细节。但是,就像前面提到的,我们的嵌入式平台现在并没有一个现成的操作系统,也就不存在一个现成的系统函数库,我们必须写出自己的printf来输出一个字符串来打印到显示器上。对于初学者来说,在现阶段,这几乎是一个不可完成的任务。幸运的是,我们可以找到一个替代方案,就是通过串口,输出字符串,这样我们就可以用term这种串口终端程序,看到我们想输出的字符串,实际上,通过串口输出,是嵌入式系统常见的字符串输出方法,广泛应用于系统的调试,而且相对来说,一个没有屏幕输出的嵌入式系统更为常见。可是即使是看似简单的串口输出,同样也涉及到CPU时钟的设定,串口频率的设定等等,为了让第一个

9、嵌入式程序尽量的简单化,我们选取一般嵌入式开发板都会带的LED发光二极管来作最简单的HelloWorld程序的输出。LED的驱动几乎是ARM嵌入式系统最为简单的一种驱动了,具体的来说,只需要在CPU的和LED相连的I/O 位写入0, LED就会发光,写入1,LED就会熄灭。好了, 现在我们就定下第一个HelloWorld需要达到的目标,我们希望打开电源开关之后,开发板上的LED能够固定时间间隔的一闪一灭。作为入门嵌入式编程的第一个elloWorld程序,我们希望程序本身越简单越好,尤其是对汇编语言还不熟练的时候,希望用到的汇编代码越少越好,越接近于语言越好。那么,下面我们就给出只用2行汇编语言

10、就能让开发板上的LED闪烁的HelloWorld程序。从理论上来说,这也可以说是史上最简单的嵌入式HelloWorld。首先列出汇编语言的源程序:start.S .global _start_start: mov sp, #4096 /* 设置堆栈指针 */ sub sp, sp, #4 /* 设置堆栈指针 */ b arm_start /* 调用C语言入口函数 */前面提到了,在0开始的位置,本来需要8个异常处理中断向量,除了复位异常以外的其他的异常在HelloWorld程序里都不会发生,因此可以忽略掉,只写出复位异常中断的处理,既然没有其他异常的处理,对于复位异常处理来说,就连跳转也可以省

11、略掉了,直接就可以开始为C语言调用准备堆栈的指针,因为S3C2440 CPU自带4K的内存,这里我们把堆栈指针SP设到CPU的自带的内存区域4K-4的位置上。这里之所以要减4,是因为内存的计算是从0开始的,4096的位置已经超过了4K的范围。内存的配置如下图所示:那么为何不能直接move sp, #4092呢?这是因为ARM汇编中的立即数的概念。ARM的机器语言中,不是任何一个数都符合立即数的要求,只有这样的立即数才是合法的:如果这个立即数可以由一个bit的数,循环右移位(这里的可以由一个bit数的倍来表示),那么这样的立即数就是合法的立即数。 根据立即数的规则,4096和4都是立即数,而40

12、92则不是。紧接着,就是跳转到C语言函数的入口。从这里开始,就是我们熟悉的C语言世界了。也就是说我们最少可以只用4行的汇编代码,就可以写出一个嵌入式的HelloWorld程序。HelloWorld.c#define GPBCON (*(volatile unsigned *)0x56000010) /* LED1/2 I/O 管脚配置寄存器地址 */#define GPBDAT (*(volatile unsigned *)0x56000014) /* LED1/2 I/O 数据寄存器地址 */#define GPBUP (*(volatile unsigned *)0x56000018) /

13、* LED1/2 I/O 端口上拉寄存器地址 */#define LED1_ON() (GPBDAT &= (0x1) /* LED1 I/O 数据位清0 */#define LED2_ON() (GPBDAT &= (0x2) /* LED2 I/O 数据位清0 */#define LED1_OFF() (GPBDAT |= (0x1) /* LED1 I/O 数据位置1 */#define LED2_OFF() (GPBDAT |= (0x2) /* LED2 I/O 数据位置1 */ void delay(int time) int i; for( i = 0; i time; i +)

14、; void arm_start() GPBCON = 0x5; /* LED12 I/O 位设为output 0101 = 0x5*/ GPBUP = 0xffff; /* 端口上拉寄存器 disable */ while(1) LED1_ON(); delay(0xffff); LED2_OFF(); delay(0xffff); LED1_OFF() ; delay(0xffff); LED2_ON(); delay(0xffff); MakefileCC=arm-softfloat-linux-gnu-gccAS=arm-softfloat-linux-gnu-gccOBJCOPY=arm-softfloat-linux-gnu-objcopyOBJDUMP=arm-softfloat-linux-gnu-objdumpCFLAGS= -mcpu=arm9tdmi -Wa -mlittle-endian -g -nostdlib -Ttext 0ASLAGS= $(CFLAGS)all: HelloWorld.binHelloWorld.bin: HelloWorld$(OBJCOPY) -O binary -S HelloWor

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 幼儿/小学教育 > 小学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号