0引言
嵌入式系统开发已经进入32位时代,在当前数字信息技术和网络技术高速发展的后PC时代,嵌入式系统已经广泛地渗透到科学研究、工程设计、军事技术等各个方面。
嵌入式系统通常由硬件和软件两个大部分组成。其硬件部分的核心部件就是各类嵌入式微处理器,并配置存储器、I/O设备、通信模块等必要的外设。目前市场上主流销售的32位嵌入式处理器有MOTOROLA、MIPS、ARM等系列,其中ARM以其体积小、成本低、功耗低、性能高等特点成为嵌入式系统设计的首选。
软件部分一般由嵌入式 *** 作系统和应用软件组成。嵌入式 *** 作系统是一种支持嵌入式应用的 *** 作系统软件,它负责全部软硬件资源的分配和调度、控制协调等活动。从20世纪80年代末开始,陆续出现了很多典型的嵌入式 *** 作系统,如Linux、μC/OS、WindowsCE等,其中使用最广泛、最受欢迎的是Linux,这是由于其源代码公开、可移植性好等优点。
1嵌入式视频处理平台和Linux系统移植
本文开发的嵌入式视频处理平台在达芬奇(Da-Vinci)数字媒体技术平台TMS320DM*6上进行的。此平台是以嵌入式处理器ARM为中心,由存储器、I/O设备、通信模块以及电源等必要的辅助接口组成。它的工作流程如图1所示。摄像头将视频信号传输进来后,再通过视频采集卡转换成数字信号然后送人TMS320DM*6,经过处理后通过视频输出接口在LCD(液晶显示器)上显示,在此过程中可以由USB口上所接的 *** 纵杆进行控制,以及与存储设备进行存取 *** 作。
此嵌入式视频处理平台主要应用于视频和图像的处理,如进行视频跟踪、图像的编解码等。
本文详细阐述如何在TMS320DM*6平台上进行Linux系统移植,形成了一个完整的Linux移植体系,为后续在此平台上的开发搭建了一个良好的平台,其移植流程如图2所示。
2交叉编译环境的建立
开发一个嵌入式Linux系统,首先要建立良好的交叉编译环境。所谓交叉编译环境,是由编译器、连接器和解释器组成的综合开发环境。交叉编译是嵌入式系统开发过程中的一项重要技术,它的主要特征是某机器中执行的程序代码不是在本机编译生成,而是由另一台机器编译生成。一般把前者称为目标机 (tar-get),后者称为宿主机(host)。在宿主机上编译好适合目标机运行的代码后,通过宿主机到目标机的调试通道将代码下载到目标机,然后由运行于宿主机的调试软件控制代码在目标机上运行调试,其交叉编译开发模型如图3所示。
建立ARM的交叉编译环境主要用到的开发工具有:binuTIls、gcc、glibc。其中binuTIls是二进制文件的处理工具,它主要包含了一些辅助开发工具,例如obj-dump显示反汇编码、nm列出符号表、readelf显示elf文件信息及段信息等。这些工具在嵌入式开发初期,尤其是移植调试 *** 作系统时非常有用;gcc是用来编译内核代码的工具,可以编译汇编语言和C语言的程序,生成ARM的代码;glibc是一个提供系统调用和基本函数的C语言库,所有动态链接的程序都要用到它。将这些开发工具包下载到宿主机上进行编译、安装,即可创建ARM的交叉编译环境。
3BootLoader的设计
BootLoader即引导加载程序,是在 *** 作系统内核运行之前运行的一段程序。它建立起 *** 作系统运行的环境,包括初始化硬件、建立存储空间映射和传递给 *** 作系统一些基本的配置参数等。因此,Bootloader是非常重要的组成部分,它独立于 *** 作系统,必须由用户自己设计,而且其实现高度依赖于硬件。在系统存储的空间分配结构中BootLoader、内核启动参数、内核映像和根文件系统映像的关系如图4所示。
BootLoader的作用是正确地调用内核来执行。系统开机后,执行的第1条指令是从Flash的0x00地址开始的,BootLoader 程序就是放在此。由于它是直接 *** 作硬件且依据硬件环境不同而代码不同,所以适合用汇编语言写,以达到短小精悍执行效率高的目的;内核从Flash复制到 SDRAM时,采用C语言实现,能实现较复杂的功能,因此BootLoader的设计分为两个阶段。用汇编语言实现的放在第1阶段,主要完成硬件初始化,设置SDRAM,然后把Boot-Loader从Flash复制到SDRAM的起始地址,即2M处,最后内存重映射,Flash地址从0x00- 0xlff映射成0x1000000-0x11fff,SDRAM地址0x200000-0xllfff映射成0x00-0xfff,至此控制权交给了用 C语言实现的loaderkernel()函数,就进入了第2阶段。第2阶段是用C语言实现的,它主要完成内核从Flash到SDRAM的复制,然后控制权交给Kernel,流程如图5所示。这样设计代码会具有很好的可读性和可移植性。
本系统BootLoader的第1阶段设计包括:
a)关闭看门狗程序,屏蔽所有中断;
b)设置处理器时钟和工作频率,TMS320-DM*6中ARM9的工作频率为300 MHz;
c)初始化外部寄存器;
d)初始化堆栈指针;
e)复制BootLoader的第2阶段到RAM空间中,使用一条跳转语句跳转到第2阶段的C程序如入口处。
第2阶段用C语言编写,具体步骤如下:
a)设置通用I/O口参数;
b)初始化内存映射和内存管理单元;
c)初始化mtd设备;
d)复制Flash中的Kernel映像和根文件系统映像到RAM空间中;
e)跳转到内核的第1条指令处,跳转时需要满足这些条件:R0=0,R1=机器类型ID,R2=启动参数,同时禁止中断(IRQ和FIQ),CPU设置为保护模式,关闭MMU和数据Cache。
这样,本系统的BootLoader就设计完成了,下面就可以进行Linux内核移植。
4 Linux内核移植
Linux内核主要由5个子系统构成:
a)进程调度(Process Scheduler):负责控制进程对CPU的使用。
b)内存管理(Memory Manager):标准Linux的内存管理支持虚拟内存,进程代码、数据和堆栈的总量可以超过实际内存的大小。
c)虚拟文件系统(Virtual File System):隐藏了不同硬件的具体细节,为所有设备提供统一的接口。
d)网络接口(Network Interface):负责支持标准的网络通信协议和各种网络硬件设备。
e)进程间通信(Inter-Process Communica-TIon):支持进程间各种通信机制。
根据嵌入式系统的特点,要使嵌入式Linux系统具备一定的功能且保持小型化,应包括启动加载程序、内核、初始化进程,以及硬件驱动程序、文件系统、必要的应用程序等。
不管是哪一款嵌入式处理器,完成移植工作就要修改所有与体系结构有关的代码,主要指内核人口、处理器初始化、I/O口映射等。具体 *** 作如下:
(1)修改配置文件
a)打开根目录下的Makefile文件,指定目标平台ARCH=arm;指定交叉编译器CROSS_COMPILE=arm-linux-gcc;
b)打开/arch/arm目录下的Makefile文件,添加内核起始运行地址,即image.ram应下载的位置,该位置一般在RAM区起始地址偏移0x8000处;
c)打开/arch/arm/boot目录下的Makefile文件,指定Bootloader的压缩内核解压后数据的输出地址。
(2)编译Linux内核
在完成上述工作后,开始编译Linux内核,生成目标代码。在内核源代码目录下依次键入以下命令:
a)make clean:清除以前构造内核时生成的所有目标文件、模块和临时文件;
b)make dep:搜索Linux输出与源代码之间的依赖关系,并以此生成依赖文件;
c)make menuconfig:调用菜单式的配置内核界面,内核配置的选项非常多,根据自己系统的具体情况选择合理的配置,在内核配置时选上相应型号的硬件;
d)make zImage:编译内核,生成压缩的Linux内核目标代码zImage文件;
e)make modules:编译块模块驱动程序,凡是在menuconfig中被选为的都会在这条命令运行时被编译。
至此,已编译好能在本系统上运行的Linux内核。
(3)创建JFFS2文件系统
文件系统是Linux系统的重要组成部分。本系统使用mkfs.jffs2工具创建JFFS2文件系统。首先建立/bin、/sbin等目录,然后复制命令工具到/bin文件夹,复制系统控制程序到/sbin目录下,复制应用程序运行时所需的库到/lib,库文件可从PC机的交叉编译工具安装目录下复制。最后键人命令:mkfs.jffs2-o jffs2root.jffs2,生成JFFS2根文件系统。
上述工作完成后,将BootLoader、Linux内核、文件系统烧写到TMS320DM*6的Flash中,这样就能运行Linux系统了。
5设备驱动程序开发
5.1 Linux设备驱动程序开发步骤
Linux系统设备分为字符设备、块设备和网络设备3种。其设备驱动的开发主要包括:
a)在驱动程序源文件中定义file_opera-TIons结构,并编写出设备需要的各个 *** 作函数,对于设备不需要的 *** 作函数用NULL初始化,这些 *** 作函数将被注册到内核中。
b)定义一个初始化函数,在Linux初始化时会调用此函数。此函数包含:初始化驱动程序要用到的硬件寄存器;初始化与设备相关的参数;注册设备;注册设备使用的中断和函数;其他一些初始化工作。
c)对于驱动程序的使用,可以进行静态编译,也可以进行动态编译。静态编译是指将设备驱动程序添加到内核中,动态编译是指将设备驱动程序编译成驱动模块。
本嵌入式系统主要用于视频处理,涉及到的外设主要是显示设备和输入设备。这里采用的显示设备是LCD,而输入设备是通过USB接口与系统相连的。
5.2 LCD显示驱动程序开发
LCD的设备驱动程序属于字符设备的驱动,应按照字符设备的规则编写。在Linux下进行LCD显示用Framebuffer技术,这是提取图形的设备,是用户进入图形界面很好的接口。Linux内核根据硬件描述抽象出Framebuffer设备,供用户态的进程直接进行写屏。可以将 Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写 *** 作,写 *** 作立即反应在屏幕上。 Framebuffer的设备文件一般存放在/dev这个目录下,对此设备文件进行 *** 作即可实现图像的显示。
LCD显示驱动程序主要包括:
a)LCD驱动的文件结构:包括打开设备文件、设备文件其它 *** 作、关闭设备文件等;
b)LCD的打开:LCD设备以读写的方式打开;
c)LCD设备的硬件初始化:包括注册LCD设备、卸载LCD设备等;
d)LCD相关结构的设置:以获取显存起始地址、分别率、色深等;
e)映射内存区的 *** 作:包括初始化显存清零等,将摄像头采集到的图像数据读至显存处,以显示图像;
f)LCD控制输出:包括得到命令、画水平线、画垂直线、画圆等;
g)LCD的关闭。
将上面的内容用程序实现,进行动态编译。通过后,将LCD驱动模块进行移植加载,一个完整的LCD驱动就开发完毕了。
5.3 USB驱动程序开发
与LCD设备不同,USB既不属于字符设备,也不属于块设备,而是一个新的设备类别,设计框架和流程如下:首先,提供一个“.o”的驱动模块文件,且在一开始就加载运行。USB驱动就会根据其类型向系统注册。注册成功后,系统会反馈一个主设备号,这个主设备号就是其唯一标识。USB驱动就是根据主设备号创建一个放置在/dev目录下的设备文件。要访问此硬件,可用open、read和write等命令访问相应的设备文件,驱动就会接收到相应的 read或write函数,根据模块中相对应的函数进行 *** 作。驱动流程见图6。
USB驱动的具体设计过程如下:
a)USB驱动的注册。USB驱动程序在注册时会发送一个命令给函数register_chrdev,通常在驱动程序的初始化函数中。当USB 设备插入时,为了使linux-hotplug(Linux中USB等设备热插拔支持)系统自动装载驱动程序,需创建 MODULE_DEVICE_TABLE,在此过程中需将USB的主设备号传递给相应的函数。
b)USB设备的打开。打开设备是通过调用file_operations结构中的函数open()来完成的。其主要完成的任务是:检查设备相关错误,如果是第一次打开,则初始化硬件设备;识别次设备号;使用计数增1。
c)USB设备的释放。释放设备是通过调用file_operations结构中的函数release()来完成的。它的作用正好与open()相反,通常要完成这样的工作:使用计数减1,如果使用计算为0,则关闭设备。
d)USB设备的控制信息与数据读写。USB设备驱动程序可以通过文件 *** 作结构中的函数向应用程序提供对硬件进行控制的接口,同时读写 *** 作也要通过此函数来完成。
e)USB驱动的注销。当从系统卸载驱动程序时,需要注销USB设备,这样必须编写一个注销函数unregister_chrdev。
6结束语
本文基于TMS320DM*6平台实现了Linux移植,包括创建交叉编译环境、BootLoader的设计、Linux内核移植以及LCD、 USB设备驱动程序开发,为实时视频处理应用开发创建了一个良好的嵌入式平台,在此平台上可进一步进行应用程序、GUI及视频处理算法开发与测试。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)