引言
嵌入式图像采集系统具有体积小、成本低、稳定性高等优点,在远程可视电话、计算机视觉、网络会议等领域应用广泛。然而,一些图像处理领域,如无人驾驶、模式识别,对运算速度、运算量要求较高,传统的基于ARM芯片的嵌入式图像采集系统往往无法满足这一要求。
TI公司的达芬奇技术集成了DSP内核和ARM内核,是典型的基于共享存储的嵌入式多处理器环境[1]。它既具有ARM对外设强大的管理能力,又拥有DSP对数据信号的高速处理能力,因而可以很好地满足图像处理对运算速度和运算量的要求。
Linux操作系统具有内核稳定、功能强大、支持多种硬件平台、源代码开放、可裁剪和低成本等众多优点,使其在嵌入式领域备受青睐。
本文在基于达芬奇技术的嵌入式linux平台上,利用OV511为控制芯片的网眼2000 USB摄像头为采集模块,使用Video4Linux内核API接口函数以及framebuffer编写相应的程序,实现了图像的采集与显示,为DSP内核后续的图像处理奠定了基础。
1 系统的硬件结构
本文使用的系统硬件平台采用TI公司的TMS320DM6446处理器(简称DM6446),它是一款双核嵌入式处理器,内部集成了ARM926EJS内核和C64x+DSP内核,DSP的数据处理能力达到4752 MIPS。该款芯片的ARM子系统是采用管道流水线的32位RISC处理器,工作频率高达297 MHz,带有独立的16 KB的指令Cache,8 KB的数据Cache,16 KB RAM,16 KB ROM[2]。其片上外设还包括USB接口、10M/100M以太网卡、UART接口、SPI接口。在处理器丰富资源的基础上,还进行了扩展,配置了128 MB 32位的SDRAM和128 MB的FLASH。另外,还配有分辨率为320×240的256色LCD。系统框图如图1所示。
图1 系统框图
2 Linux开发环境建立及内核定制
2.1 主机开发环境的建立
ARM的开发一般需要三个系统,即Windows系统、PCLinux系统、ARMLinux系统。其各自的功能如图2所示。
图2 三系统功能图
三系统的搭建有两种方法:一种是三台分立的单系统机器组合,一种是一台双系统PC机和一台单系统ARM开发板。本文采用后一种方式,一可以节约硬件资源,二可以使开发流程、开发环境的搭建更加简单。
本系统PC机采用WindowsXP+VMware虚拟机+Linux的开发环境。其中VMware采用的是6.0版本,Linux采用的是较为成熟的Redhat9,内核版本是2.4.20。
2.2 交叉编译环境的建立
在进入嵌入式开发之前,还需要建立一个交叉开发环境,这是一套编译器、连接器和libc库等组成的开发环境[3]。其开发模型如图3所示。
图3 交叉开发模式
图3中,TARGET是目标板,HOST是开发主机。在开发主机上,可以安装开发工具,编辑、编译目标板的Linux引导程序、内核和文件系统,然后在目标板上运行。这种在主机环境下开发,在目标板上运行的开发模式叫做交叉开发。
构建交叉开发环境,首先要安装交叉编译工具链。Linux使用GUN的工具,社区的开发者已经编译出了常用体系结构的工具链,从因特网上下载ARM体系结构的编译器,安装即可。安装后需要在环境变量PATH中添加路径,该路径必须是工具链的安装路径,这样就可以直接使用armlinuxgcc命令了。
2.3 内核定制
嵌入式系统的存储空间有限,要将Linux用于嵌入式系统就得对Linux操作系统进行定制(或叫裁剪),使整个Linux系统能够存放到容量较小的开发板FLASH中[4]。
由于本系统采用OV511芯片的USB摄像头进行图像采集,所以在定制内核时,一定要使内核支持USB总线和OV511摄像头。此外,视频采集设备的正常使用依赖于对 Video4Linux驱动程序的支持,所以在定制内核时也要添加这一项支持。
在定制内核时,应该选中:
[*]Video for Linux
[*]support for usb
[*]USB ov511 Camera Support
3 基于Video4Linux的图像采集
Video4Linux(简称V4L)是Linux中关于视频设备的内核驱动,它为针对视频设备的应用程序编程提供一系列接口函数,这些视频设备包括TV卡、视频捕捉卡和USB摄像头等。在Linux环境下,利用V4L应用程序接口获取视频图像,可以通过调用open()、ioctl()等函数,像操作普通文件一样,进行视频硬件初始化、硬件属性设置和硬件中断调用等操作。
视频采集程序的基本流程如图4所示。
图4 视频采集流程
V4L模块提供的主要API函数有:VIDIOCGCAP函数,以数据结构video_capability返回视频采集设备的基本信息,包括设备名称、设备类型、信道数、最大及最小像素高度和宽度等;VIDIOCSPICT函数,使用数据结构video_picture来获取和设置采集图像帧的属性,如亮度、色调、对比度、调色板等[5];VIDIOCGMBUG函数,使用数据结构video_mbuf获得摄像头设备图像存储的相关信息;VIDIOCMCAPTURE函数用于视频采集。以上函数都可以在videodev.h文件中查看定义。
首先必须声明两个头文件sys/types.h、linux/videodev.h,接着利用open函数打开视频设备,其中设备文件为/dev/video0。随后,调用ioctl(fd, VIDIOCGCAP, &capability)函数的VIDIOCGCAP宏命令,获取有关视频设备的基本信息。接着,调用ioctl(fd, VIDIOCGPICT, &picture)函数的VIDIOCGPICT宏命令,获取所采集图像的属性。至此,图像采集的前期准备工作已经完成。接着就是关键的图像采集部分。
图像采集有两种方法:一种是用内存映射方式读取图像,一种是直接读取视频设备。本文采用前者,获取图像的关键代码如下:
struct video_mmap mmap;
/*定义video_mmap型结构变量mmap*/
/*以下为设置图像缓冲区信息*/
mmap.frame=1;
/*采集帧数为2帧,交替出现,以完成显示图像的连续性*/
mmap.height=320;/*图像高度*/
mmap.width=480;/*图像宽度*/
mmap.format= picture.palette;/*图像的调色板格式*/
struct video_mbuf mbuf;
ioctl(fd, VIDIOCGMBUG ,& mbuf);/*获取存储图像的内存大小*/
unsigned char *map = mmap(0, mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)/*内存映像*/
ioctl(fd, VIDIOCMCAPTURE, & mmap)/*采集图像*/
截取图像后还要调用函数ioctl(fd, VIDIOCSYNC, &frame)进行同步操作,函数返回0表示图像已经获取完毕。图像存储在以map为起始地址,长度为mbuf.size的存储空间中。map +mbuf.offsets[frame_current]处。其中frame_current=0,即为第一帧的位置,frame_current=1,为第二帧的位置。由于DSP内核和ARM内核是共享DDR内存的,所以ARM可以直接传递该数据地址指针给DSP内核进行图像处理,无需大块的数据搬移。
4 基于FrameBuffer的图像显示
Framebuffer(帧缓冲),它作为基础图形设施,是出现在Linux2.2内核当中的一种驱动程序接口,是作为其他高级图形或者图形应用程序的基本函数库。这种接口将显示设备抽象为帧缓冲区。用户可以将它看成是显示内存的一个映像,而不必关心物理显存的位置、换页机制等等具体细节,这些都是由Framebuffer设备驱动来完成的。只要将其映射到进程地址空间之后,就可以直接进行读/写操作,而写操作可以立即反应在屏幕上。该设备使用特殊的设备节点,通常位于/dev目录,如/dev/fb*。用户若要使用它,需要在编译内核时选中FrameBuffer[6]。其简单的使用程序如下:
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
int fb = open("/dev/fb0", O_RDWR);
ioctl ( fb, FBIOGET_FSCREENINFO, &finfo) ;
/*获取与Framebuffer有关的固定的信息*/
ioctl( fb, FBIOGET_VSCREENINFO, &vinfo) ;
/*获取与Framebuffer有关的可变信息*/
从vinfo和finfo中取得显存起始地址、分辨率、色深等信息,然后根据这些计算出需映射的显存的大小。
screensize=vinfo.xres*vinfo.yres*vinfo.bits_per_pixel/8;
/*计算显存所需的字节数,其中xres,yres,bits_per_pixel分别为x、y轴分辨率和色深*/
char * fbp = mmap ( 0 , screensize ,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
/*通过调用mmap()用来实现内存映射IO*/
由此便可以直接操作大小为screensize,起始地址为fbp的内存空间,利用Video4Linux采集的图像数据映射到Framebuffer的内存区域中,便可以直接显示到LCD上了。
5 DSP核与ARM核之间的通信
如前所述,DaVinci是DSP和ARM双核架构的SOC芯片,ARM核负责芯片与外界的交互,DSP核处理相关算法,它们之间的通信和交互是通过引擎(Engine)和服务器(Server)来完成的[7],其框架如图5所示。
图5 Codec框架
Codec Engine是连接ARM和DSP的桥梁,是介于应用层(ARM端的应用程序)和信号处理层(DSP端的算法)之间的软件模块。ARM应用程序调用Codec Engine的VISA(Video, Image, Speech, Audio)API,以VIDENC_process(a、 b、 c)为例。首先,Codec Engine的stub(ARM端)会把参数a、b、c以及要调用DSP端process函数这个信息打包;随后,通过Engine SPI、OSAL和DSP Link传递给DSP;接着,Codec Engine的skeleton(DSP端)会解开这个包,把参数a、b、c转换成DSP端对应的参数x、y、z(比如ARM端传递的是虚拟地址,而DSP只能认物理地址);最后,DSP端的Codec server(优先级较低,负责和ARM通信的任务)会根据process这一信息创建一个DSP端的process(x, y, x)任务,最终实现VIDENC_process(a、b、c)的操作。
结语
Linux代码完全开源,系统具有良好的移植性,可方便地进行各种扩展,利用嵌入式Linux进行的图像采集和显示运行稳定,效果良好。本文利用达芬奇平台实现了图像采集和显示,采集到的图像可以给DSP内核进行高速处理,为后续的工作奠定了基础,可广泛应用于对运算量、运算速度要求较高的图像处理领域。