在编译内核的时,建议在Linux平台下进行。 7.3.4 内核的加载运行
当内核的编译工作完成之后,会在/ uClinux-Samsung/images目录下看到两个内核文件:image.ram和image.rom,其中,可将image.rom烧写入ROM/SRAM/FLASH Bank0对应的Flash存储器中,当系统复位或上电时,内核自解压到SDRAM,并开始运行。
image.ram可直接在系统的SDRAM中运行,使用ADS(或SDT)集成开发环境将系统的SDRAM映射到起始地址为0x0处,并将image.ram载入从0x8000开始的SDRAM中,加载完毕后,修改PC指针寄存器的值为0x8000并执行。 注意该内核默认串行口COM1为输入输出控制台,波特率为19200,8个数据位,1个停止位,无校验。
7.4 在uClinux下开发应用程序
当完成了上述所有工作后,一个嵌入式应用开发平台就已经搭建好了,在这个平台之上,就可以根据不同需要开发嵌入式应用了。图7.8所示为一个基于uClinux 的嵌入式系统典型框架结构,下面将向读者介绍如何将自己开发的应用程序添加到目标板上运行。
图7.8 基于uClinux嵌入式系统框图
基于uClinux系统的应用程序的开发通常是在标准Linux平台上(本书已经介绍了适用于Windows环境的交叉编译器,所以也可以在Windows平台)用交叉编译工具来完成。由于uClinux是为没有内存管理单元(MMU)的处理器和控制器而设计的,并做了较大幅度的精简,所以可能出现这样的情况:在标准Linux下可以使用的某些函数在uClinux下却用不了,这个时候,就需要用户编写相应的库函数了。当然绝大多数的函数它们都还是通用的。除
此以外,在x86版本的gcc编译器下编译通过的软件,通常不需要做太大的改动就可以用刚才我们建立的交叉编译工具编译成可以在uClinux上运行的文件格式。因此开发在uClinux 下运行的程序,基本上就和开发在Linux下运行的程序是一样的,关于Linux下的编程,读者可以参考其他更详细的资料,以下就一个简单的例子,描述其基本开发过程。
考虑一个定时中断的例子,文件名为lednxy.c,其源代码如下:
/******************************************************* * Institute of Automation, Chinese Academy of Sciences * File Name: lednxy.c
* Description: timing interrupt * Author: * Date:
Xueyuan Nie
*******************************************************/ #include
#define IOPMOD (*(volatile unsigned *)0x3ff5000) #define IOPDATA (*(volatile unsigned *)0x3ff5008) int i=0;
static void sig_alarm(int signumber) {
if(i==3) i=0; IOPDATA=i++; alarm(2); }
int main(void) {
IOPMOD=0xff;
if(signal(SIGALRM,sig_alarm)==SIG_ERR) {
printf(“some error occurs\\n”);
return 1; }
} alarm(2); while(1); return 0;
在代码中,SIGALRM为系统定义的信号的名字,在头文件里被定义为一个正整数,用户自定义函数sig_alarm()为信号处理函数, 系统函数
alarm()用来设定一个2秒的定时器,当定时器时间片终止的时候,进程将会产生SIGALRM信号,在程序中用函数signal()实现了信号SIGALRM和信号处理函数sig_alarm()的连接,这样,当用alarm()函数设置时钟的时间段终止时,就会有SIGALRM信号产生,程序就会转而执行函数sig_alarm(),从而实现每隔2秒钟,I/O口数据寄存器的值发生一次变化,达到控制LED等的目的。有关signal()函数和alarm()函数的使用,读者可以查阅有关在Linux上的C编程方面的内容,本书在此不作详述。
该程序达到的效果就是,让目标硬件上的P0和P1口的两个LED显示器按照P0亮,P1亮,P0、P1全亮的顺序,每隔2秒实现其中的一种状态。 在装有标准Linux的宿主机(或装有Cygwin的windows的PC机)上,用前面已经建立好的交叉编译工具编译源文件,在该程序所在的目录下键入如下命令:
arm-elf-gcc –Wall –O2 –Wl,-elf2flt –o lednxy lednxy.c 仍然在该目录下,键入命令:
ls
可以查看到在该目录下生成了文件名为lednxy的文件。
在键入的编译命令中,选项 : -Wall 指定产生全部的警告信息;
-O2 是一个二级优化选项,它表示告诉编译器产生尽可能小和尽可能快的代码;
-Wl 的一般用法是’’-Wl,option’’ 就是把它后面的选项传递给链接器,在本命令中就是把’’- elf2flt ‘’传给链接器;
-elf2flt 指定自动调用elf转换flat格式的工具;之所以要使用该选项是因为,由于GNU工具本身并不支持flat格式的二进制文件,然而,uClinux目前只支持flat格式的可执行文件,因此必须使用相应的二进制工具进行格式转换。flat格式是对elf格式的很大的文件头和一些段信息做了简化的文件格式。
编译成功后得到的lednxy就可以在uClinux环境上运行了。关于如何将生成的可执行代码加入到uClinux,将在后面的章节讲述。 除了以命令行的形式进行代码编译外,我们还可以利用前面提到的makefile的知识,用makefile文件实现代码编译的功能。
下面给出本例相应的makefile文件(该文件名为makefile)。
CFLAGS = -Wall –Os –Dlinux –D__linux__ -Dunix –D__uClinux__ -DEMBED LDFLAGS = -Wl,-elf2flt CC = arm-elf-gcc LD = arm-elf-gcc TARGT = lednxy OBJ = $(TARGT).o SRC = $(TARGT).c all: $(TARGT) %.o : %.c
$(CC) $(CFLAGS) –c $< -o $@ $(TARGT): $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) –o $@ $(OBJ)
整个编译过程如下:
[nie@uClinux usr]$ make
arm-elf-gcc –Wall –Os –Dlinux –D__linux__ -Dunix –D__uClinux__ -DEMBED -c lednxy.c –o lednxy.o arm-elf-gcc –Wall –Os –Dlinux –D__linux__ -Dunix –D__uClinux__ -DEMBED -Wl,-elf2flt –o lednxy lednxy.o
可以用工具arm-elf-flthdr查看生成的lednxy的格式,它是一个能够操作和显示flat格式文件的头信息的可执行程序。在生成lednxy的当前路径下键入命令:
arm-elf-flthdr lednxy
后,可以看到以下对该文件头描述的信息,
lednxy
Magic: bFLT Rev: 4
Build Date: Thu Jun 19 10:31:14 2003 Entry: 0x50 Data Start: 0x1c80 Data End: 0x2010 BSS End: 0x22a0 Stack Size: 0x1000 Reloc Start: 0x2010 Reloc Count: 0x4f