基于ARM的嵌入式设备中uCLinux系统开发
控制工程

1 引言

  uCLinux支持多任务,支持多种文件系统,提供了对网络的强大支持,具有完整的TCP/IP协议栈,以及标准丰富的API。由于它的很多核心代码都为没有被MMU的处理器重新编写过,对标准Linux庞大的应用程序库和驱动程序库作了删改,所以它的内核要比常规的Linux 内核小很多;uCLinux包含Linux常用的API和小于512k的内核及相关的工具,总代码只有900k左右,但同时保留了常规Linux 操作系统绝大多数的优点。
2 基于ARM的硬件平台
    嵌入式领域32位处理器以ARM公司的ARM核最为流行,本文以Samsung公司的ARM7TDMI芯片S3C4510为处理器开发板为硬件平台,开发板上与S3C4510相关的部分主要集成了如下器件:
(2M+512k)B 的Flash,其中AT29C010A为512B作为BootLoader,一片SST49VF160为1M×16bitFlash;
16MB 的DRAM,由两片4M×16bits的HY57V641620提供 ;
16MB 的SRAM,由M-systems的新一代闪存盘DOC2000构成;
Ethernet接口;
ARM JTAG 接口。
  开发板上与S3C4510相关部分功能框图如图1 所示。
 

 IO      

UART                         

S3C4510

JTAG            

Ethernet

 FLASH             

F
 
DOC2000
 
232串口
 
JTAG接口
 
LED
 
以太网接口
 
用户自定义逻辑
 
DRAM
 
3 uCLinux内核移植
    嵌入式 Linux 开发大致涉及三个层次:引导装载程序、Linux 内核和驱动及应用程序。我们将讨论涉及这三层的一些基本概念;深入了解引导装载程序、内核和文件系统是如何交互的。
    引导程序BootLoader的主要作用包括初始化处理器;初始化必备的设备;下载系统映象;初始化操作系统系统并准备执行。
    引导装载程序有两种方法:专用软件和微小的引导代码。专用软件可以直接与远程系统上的闪存设备进行交互并将引导装载程序安装在闪存的给定位置中。而某些种类的嵌入式设备具有微小的引导代码:根据几个字节的指令,它将初始化一些 DRAM 设置并启用目标上的一个串行(或者 USB,或者以太网)端口与主机程序通信;然后,主机程序或装入程序可以使用这个连接将引导装载程序传送到目标上,并将它写入闪存。
    嵌入式设备上一些流行的并可免费使用的 Linux 引导装载程序有 Blob、Redboot 和 Bootldr。所有这些引导装载程序都用于基于 ARM 设备上的 Linux,并需要Jflash-linux 工具用于安装。一旦将引导装载程序安装到目标的闪存中,它就会执行我们上面提到的所有初始化工作。然后,它准备接收来自主机的内核和文件系统。一旦装入了内核,引导装载程序就将控制转给内核。
    Linux内核移植首先需要配置内核,可以用make menuconfig进行,根据板卡选择必要的选项。主要包括系统类型选定(ARM system type),配置SDRAM/Flash地址;对块设备、字符设备进行选择和配置;配置文件系统;是否配置图形用户界面(GUI)。修改内核,我们选用www.lomx.net上的uClinux-2.4.26-uc0.diff,已经为S3C4510移植好的内核,需要修改的地方很少。编译内核,首先要在宿主机(安装有Linux)上建立交*编译环境,下载arm-elf-tools安装在Linux 宿主机上的/usr/local/bin 目录下。现在的BLOB 和将来的uClinux 都要在这个环境下编译。
开始编译uClinux
编译内核:执行命令:
make menuconfig 在出现的对话框选Samsung/4510B 和 uC-libc,然后退出。如果选择uC-libc编译出错,可以改选uClibc!
   make dep
   make lib_only  
   make user_only
   make romfs
   make image 产生 romfs.o,这一步将会出现一些错误报告,可忽略继续下面的命令
   make
如果make无错误,在images的目录下你会看到有 image.ram 和 image.rom 两个二进制的内核文件。即image.ram和image.rom。 image.ram可以通过Bootloader下载到SDRAM中运行。image.rom可以写入到Flash SST39VF160中直接运行。
down image.ram看看能不能运行    最后一步,uClinux调试完毕,通过jflashp将其写入到Flash中:开发板断电,把JTAG仿真器接到计算机的并口和板子的14Pin JTAG插座上;接通5V电源;执行 FlashP w -f image.rom,大约30分钟以后烧写完毕。撤掉JTAG仿真器以后再上电就应该运行uClinux了。如果想把BootLoader写回Flash,执行FlashP w -f bios.img即可。
4 uCLinux驱动程序开发
    嵌入式系统通常有许多设备用于与用户交互,象触摸屏、小键盘、滚动轮、传感器、RS232 接口、LCD 等等。除了这些设备外,还有许多其它专用设备,包括闪存、USB、GSM、GPS 等。内核通过所有这些设备各自的设备驱动程序来控制它们,包括 GUI 用户应用程序也通过访问这些驱动程序来访问设备。uClinux 的驱动程序库不可能包括实际项目系统中所有外围硬件的驱动,所以在应用开发中,编写驱动程序是一个重要步骤,驱动程序设计的好坏直接影响系统运行的稳定性和运行效率。


    在uClinux 内核编写驱动程序并不像其他操作系统那么复杂,实际上,所要做的只是为相应的设备编写几个基本函数并向VFS(virtual file system) 注册即可。当上层应用要使用该设备时,VFS 就会调用相应的设备函数。设备驱动程序通常可归为以下3 类:
a) 块设备(block) ,以块为单位,允许随机访问,多用缓存技术;
b) 字符设备(char) ,以字节为单位,只能按顺序访问,不用缓存;
c) 网络接口(net) 。
    在本系统中,DOC作为块设备可被模拟为IDE设备进行识别,系统用主设备号(MAJOR)和次设备号(MINOR)来唯一标识一般设备;相同主设备号表示同一类设备,次设备号表示同类设备的个数。所有设备在适当的目录(通常是/dev目录)下必须有相应的文件,这样字符设备和块设备都可以通过文件操作的系统调用完成。不同的是,块设备操作经常和缓冲区联系在一起。
    字符设备的驱动程序通过在device_struct数据结构的chrdevs向量中增加一项的方法来向内核注册自己。然后对这个设备的所有调用都用这个设备号来实现;
    块设备和字符设备都需要定义功能函数:对于每一个驱动函数来说,都有一些和此设备密切相关的功能函数,就最常用的字符设备来说,都存在着诸如open()、read()、write()、ioctrol( ) 这一类的操作。当系统调用这些操作时,将自动的使用file-operations 结构中对应的函数来实现具体的操作;块设备由于使用高速缓存,其驱动程序不需要保护自己的read()、write()和fsync()函数,但必须使用自己的open()、release()和ioctl()函数,函数原型为:
static int my_open(struct inode *inode,struct file *file);
static int my_release(struct inode *inode,struct file *file);
static int my_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long age);
    块设备驱动程序的请求处理函数一般通过中断实现。驱动程序被调用时CPU由内核程序控制,故不可抢占,驱动程序必须调用sleep_on()函数释放对CPU的占用,在中断服务子程序将数据复制到内核内核后,再发出wake_up()调用。
    字符设备如LCD、USB应用广泛,下面以此为例详细说明添加设备驱动的过程。设备名称为scre,设备号为254。块设备与网络设备可以比照处理。
    在目录/linux_2.4/drives/char编写源程序scre.c,编写字符设备的处理函数。
1.设备驱动原文件必须包括这样的一个函数:
    void scre_init(void){register(254, ’scre’, &scre_fops)} 这个函数完成注册.在linux-2.4.x/driver/mem.c 将会调用它。
2.修改 linux-2.4.x/driver/char/Makefile 在适当位置添加一行:obj_$(CONFIG_SCRE) += scre.o
3.修改linux-2.4.x/driver/char/Config.in, 添加一行:
   bool   ’scre device’ CONFIG_SCRE,便于在 make menuconfig 时选择
4.修改linux-2.4.x/driver/char/mem.c ,在适当位置(你去找就会发现,在文件头部)添加:
#ifdef CONFIG_SCRE
       extern void scre_init(void);
      #endif
     在chr_dev_init()函数添加:
      #ifdef CONFIG_SCRE
         scre_init();
      #endif  
5. 修改vendor/Samsung/4510b/Makefile ,建立设备节点;在12---35行间,DEVICE 部分添加如下内容 :scre,c,254,0 。
6.make menuconfig 选中scre device,编译,下载;启动后你会看到 /proc/devices 中字符设备多了一项 scre 254 。
    uClinux的Web技术,主要有三个Web服务器:httpd,thttpd和boa。Httpd简单,但只能Web浏览,不支持认证、CGI,thttpd和boa Web服务器功能较全;而boa Web代码简单、速度快,适合嵌入式应用。Boa作为一个简单的http服务器,与传统服务器的主要区别是它是单进程的。boa在uClinux下的实现需要对boa.conf和mime.types作一些配置和修改,并且需在命令行指定配置文件所在目录。配置完成后需要重新编译内核,并选中boa选项,将编译好的内核下载到开发板,启动uClinux,完成IP设置,启动boa Web后便可通过IE访问网页了。
5 结语
    uClinux在嵌入式领域凭借其稳定、良好的移植性,优秀的网络功能,灵活完备的文件系统以及众多的技术支持等优点得到广泛应用,并将有更广阔的应用前景。本文针对uClinux的开发应用步骤作了大致的阐述,对ARM应用平台上的系统移植和应用开发作了分析,具有一定的指导意义。
参考文献
[1].刘安昱 温晓辉 刘志红,基于S3C44B0X的uClinux的移植,《单片机与嵌入式系统应用》[J]2003.12.
[2].徐雪松等,基于嵌入式Linux的DiskOnChip设备的驱动开发实现,《电子设计应用》[J]2003.12
[3].Linux on module project-Lom ARM7 ,www.lomx.net.
[4].朱珂等译,《Linux编程白皮书》[M],机械工业出版社,2000.
[5].赵炯,《Linux内核完全注释(内核版本0.11)》[M],2003