百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

基于FIMC接口的CMOS摄像头驱动分析与设计

cac55 2025-03-20 12:38 9 浏览 0 评论

摘 要: 目前的嵌入式系统中,USB摄像头使用比较普遍,但其应用会受到传输速度的限制。本文采用一款高速CMOS摄像头,其驱动利用S3C6410内置的FIMC接口技术,采用DMA和ping-pong缓冲池机制,结合内存共享策略,有效提高了传输速率并充分利用了有限的内存资源。深入分析了该驱动的原理和实现细节,并提出了改进设计,最终应用在嵌入式图像采集系统中,能够为应用程序提供高清、高速图像。

0 引言

嵌入式系统具有体积小、功耗低和成本低等天然性的优势,因而得到广泛应用,甚至在许多场合得以取代传统工控机,比如视频监控系统和安防系统。目前嵌入式系统中最常用、嵌入式Linux内核支持最广泛的是USB摄像头。然而受到嵌入式处理器性能的限制,USB摄像头接口的传输速率限制为12 Mb/s,对于常用的640×480分辨率的YUV图像,其最高帧率为3.75帧/s,无法满足实时性要求。因此,基于CMOS图像传感器的高速摄像头正在被推广应用。CMOS高速摄像头可以为嵌入式系统实时地提供高分辨率图像[1],很适合进行识别、跟踪等实时图像处理作业。采集640×480的VGA图像,CMOS摄像头最高帧率可以达到30帧/s。基于OV系列的CMOS摄像头应用很多,比如监控[2]和人数检测[3]都使用了OmniVision公司的OV9650摄像头。参考文献[4]介绍了基于S3C6410和OV9650的V4L2图像采集系统的设计,参考文献[5]和[6]介绍了基于S3C2440中相机接口(Camera Interface,CAMIF)的OV9650摄像头驱动设计。

本文涉及的S3C6410[7]的完全交互式移动相机(Fully Integrated Mobile Camera,FIMC)接口是由S3C2440的CAMIF发展而来,但是目前关于FIMC驱动的原理分析和设计实现的文献仍然很少。本文对OV9650及FIMC接口驱动的原理和实现细节作了深入分析,并对原有驱动进行了改进,使之适用于视线检测系统。

本文首先分析摄像头驱动所依赖的硬件接口,然后重点分析其驱动软件设计原理和实现细节,并给出改进设计,最后对下一步的改进工作提出展望。

1 摄像头驱动系统的硬件接口

本文所涉及的驱动系统基于OK6410嵌入式开发板,采用S3C6410作为中央处理器。S3C6410内置的FIMC接口为开发板与CMOS摄像头的连接提供了可靠便利的接口。该驱动系统的硬件结构如图1所示。

如图1,摄像头为130万像素、20引脚的OV9650,通过FIMC接口接入S3C6410。OV9650与FIMC对应管脚连接如图2所示。其中,CAMYDATA7~CAMYDATA0负责图像数据传输,CAMRSTN为复位信号,CAMSYNC为同步信号。OV9650的配置接口为SCCB接口。由于S3C6410没有专用的SCCB接口,因此使用GPB6、GPB5分别模拟SIO_D、SIO_C,即数据和时钟信号。SCCB协议与I2C协议的区别仅在于设备地址不同,因此,驱动中直接用I2C代替。

2 摄像头驱动系统软件

2.1 Linux驱动模型

在Linux操作系统中,设备驱动为应用程序提供访问接口,屏蔽了底层硬件细节。从Linux2.6内核开始,设备被驱动和内核映射为文件,应用程序可以像访问普通文件一样访问这些挂载在/dev目录下的设备,访问接口被定义在驱动中file_operations结构体对象内。每一个接口函数其实都是一个系统调用,其具体实现由驱动程序完成。Linux内核中驱动模型包括总线(Bus)、设备(Device)和驱动(Driver)三个要素,即设备和驱动作为对象挂载在相同的总线上,由总线对设备和驱动进行一一匹配。

Linux驱动模型将所有外设分为字符设备、块设备和网络设备三种。摄像头属于字符设备,其驱动遵循着字符设备驱动的框架,包括设备号、设备注册和最重要的文件操作函数的实现。特别地,针对摄像头设备,V4L2[8]接口为驱动程序提供了一套完备的文件操作标准接口和缓冲池管理策略,目前大多数的摄像头驱动都遵循V4L2接口标准。

2.2 V4L2驱动

V4L2是Video For Linux 2的简称,是Linux内核中关于视频设备的虚拟驱动,它不涉及硬件,仅仅为应用程序提供一套完备的操作接口,这些接口的具体实现都由遵守V4L2协议的驱动程序来完成,比如常用的ioctl接口。V4L2的存在极大地方便了应用程序的编写,使得同一套应用程序可以应用于多种摄像头。V4L2层次示意图如图3。

基于V4L2的基本图像采集流程如下:

(1)打开视频设备文件(一般为dev/video0),初始化采集格式等参数;

(2)在内核空间申请若干视频采集的帧缓冲区;

(3)地址映射,使得用户空间的应用程序对帧缓冲区有读写权限;

(4)帧缓冲区在视频采集输入队列排队,并启动视频采集;

(5)从缓冲队列取出帧缓冲区,获得数据进行处理;

(6)处理完,将帧缓冲区重新放入视频采集输入队列,循环往复采集连续视频数据。

V4L2为图像采集程序维持一个环形缓冲队列,如图4。该缓冲区队列为ping-pong操作模式,应用程序需要使用的图像数据会通过ioctl接口使对应的缓冲区出队,缓冲队列的其余缓冲区继续接收图像数据,并在一个循环之后覆盖掉原有的缓冲区数据,以保证缓冲区队列中图像数据的实时性。

2.3 关键模块驱动的设计与实现

OV9650通过FIMC接口与S3C6410连接,FIMC为输入图像进行格式转换、剪裁等预处理,最后传输到内核中开辟的图像缓冲区,供应用程序读取。摄像头驱动分为两个部分:OV9650驱动和FIMC驱动。

2.3.1 OV9650驱动

OV9650驱动的主要作用是挂载驱动和配置寄存器,其中.h文件定义了寄存器配置数据,并由.c文件调用。由于FIMC接口的存在,应用程序不需要直接操作OV9650摄像头,因此OV9650驱动不需要为应用程序提供访问接口,不需要定义file_operations结构体。

从Mach-smdk6410.c文件中可以知道,内核在启动时,将OV9650作为一个I2C设备挂载到内核树的I2C总线上。之后内核找到OV9650驱动,执行其入口函数——ov965x_init,将OV9650.c文件中定义的i2c_driver驱动对象也添加到内核树中,最后由总线根据其name将设备和驱动进行匹配。在匹配工作完成之后,内核会调用其探测函数ov965x_probe,将OV9650的配置数据传递给FIMC驱动中的一个全局参数s3c_fimc,用于配置FIMC寄存器,然后,初始化OV9650寄存器。

2.3.2 FIMC驱动

FIMC是s3c6410芯片为摄像头设备提供的一个接口,用来对所采集的图像进行裁剪、放缩等预处理。FIMC为输出图像提供两个DMA通道:preivew通道和codec通道,并为每个通道分配四个ping-pong缓冲区,以提高图像传输速度和内存使用效率。如图5所示。

FIMC接收OV9650图像数据,并向上传递。因此,FIMC驱动最重要的作用就是向应用层提供标准的操作接口,供应用程序使用。

FIMC驱动主要包括三个部分:(1)platform驱动注册;(2)file_operations接口定义;(3)V4L2接口实现。

2.3.2.1 platform驱动注册

platform是Linux 2.6内核所引进的一种新型驱动管理和注册机制。目前Linux内核中大部分的设备驱动都采用platform架构。在platform架构中,设备用platform_device表示,驱动用platform_driver表示。Linux platform driver机制与传统的device driver机制(通过drivce_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序使用这些资源时通过platform device提供的标准接口进行申请并使用,提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。

FIMC驱动入口函数是s3c_fimc_core.c中的s3c_fimc_register,该函数将platform_driver类型的s3c_fimc_driver挂载到platform虚拟总线。由mach-smdk6410.c文件可知,内核启动时将所有platform_device(包括s3c_device_fimc0)挂载到platform总线。platform总线的match函数将device和driver匹配之后,会自动调用s3c_fimc_driver中指定的probe函数探测设备、申请内存资源、申请中断等,并将最终形成的platform_device类型数据保存到内核中,供后续使用。最后,调用video_register_device函数将对应的video_device注册到内核。

video_device结构体包括fops、ioctl_ops、release、name、vf_type几个成员变量,其中,最重要的是file_operations类型的fops和v4l2_ioctl_ops类型的ioctl_ops,分别实现文件操作接口和V4L2接口。

2.3.2.2 file_operations接口

FIMC驱动遵循V4L2接口标准,其file_operations接口定义如下:

static const struct v4l2_file_operations s3c_fimc_fops=

{

.owner=THIS_MODULE,

.open=s3c_fimc_open,

.release=s3c_fimc_release,

.unlocked_ioctl=video_ioctl2,

.read=s3c_fimc_read,

.write=s3c_fimc_write,

.mmap=s3c_fimc_mmap,

.poll=s3c_fimc_poll,

};

当应用程序通过系统调用open打开摄像头设备时,内核会最终找到s3c_fimc_open函数来打开摄像头。

应用程序通过read获取图像数据,该函数通过copy_to_user将内核空间所申请缓冲区中图像数据拷贝到用户空间中开辟的图像数据区。该函数没有充分利用FIMC接口提供的ping-pong缓冲区,按字进行拷贝(memcpy),十分耗时。

mmap函数将内核空间中申请到的图像缓冲区映射到应用程序所在的用户空间,这样,应用程序申请到的buffer将指向内核空间的图像缓冲区,应用程序可以(不拷贝)直接对图像进行操作。该函数配合V4L2标准中的环形缓冲区队列,节省了应用程序读取图像数据所消耗的时间。

2.3.2.3 V4L2接口

V4L2接口功能强大,为应用程序提供了完备的操作接口,包括设置格式、帧率、白平衡、曝光模式、申请缓冲区、取数据、剪裁图像等。此处仅列举几个重要接口。

const struct v4l2_ioctl_ops s3c_fimc_v4l2_ops=

{

.vidioc_s_fmt_vid_cap=

s3c_fimc_v4l2_s_fmt_vid_cap,

.vidioc_s_ctrl=s3c_fimc_v4l2_s_ctrl,

.vidioc_streamon=s3c_fimc_v4l2_streamon,

.vidioc_streamoff=s3c_fimc_v4l2_streamoff,

.vidioc_reqbufs=s3c_fimc_v4l2_reqbufs,

.vidioc_querybuf=s3c_fimc_v4l2_querybuf,

.vidioc_qbuf=s3c_fimc_v4l2_qbuf,

.vidioc_dqbuf=s3c_fimc_v4l2_dqbuf,

.vidioc_s_parm=s3c_fimc_v4l2_s_parm,

};

应用程序通过ioctl接口使用这些函数,比如ioctl(fd,VIDIOC_S_FMT,&fmt)用来设置图像格式,此时V4L2会将VIDIOC_S_FMT命令映射为
s3c_fimc_v4l2_s_fmt_vid_cap函数,并将fmt指定的格式告知FIMC接口,FIMC会将OV9650传递过来的原始图像数据经过类型转换传递回应用程序。

s3c_fimc_v4l2_reqbufs用于申请图像缓冲区,该函数为应用程序在内核空间开辟ping-pong缓冲区。s3c_fimc_v4l2_qbuf函数将缓冲区组成环形缓冲队列,当应用程序需要调用图像数据时,使用s3c_fimc_v4l2_dqbuf使指定的缓冲区出队,缓冲区在出队期间,不会被新来的图像数据覆盖,新到的图像数据会被传送到环形队列中指定缓冲区的下一个缓冲区。由于FIMC控制器为P通道和C通道分别开辟了4个缓冲区,在内核初始化时已经申请到,因此FIMC驱动中并不需要再重新申请。

2.4 驱动错误分析与改进设计

在驱动主体框架正确的情况下,开发板(OK6410A)自带的驱动并不能直接使用。同一套V4L2图像采集程序可以应用在USB摄像头上,应用在OV9650上却无法获得图像,并且先后报出两个错误:

(1)tx or ty is lower than zero and this is a invalid target size

(2)VIDIOC_QUERYBUF error

上述错误出现之后,LCD屏幕没有图像,紧接着串口会显示display 0,表示程序无法读出图像数据,导致程序终止。下面分别对两个错误进行分析并改进。

2.4.1 错误1的分析与改进

由于ov9650驱动仅仅将ov9650设备注册进入系统,并没有其他处理,因此ov965x.h和ov965x.c两个文件不用修改和调试。

FIMC采用DMA通道向内核缓冲区传送数据,需要专门的函数打开DMA输出通道。通过函数跟踪得知,原有
s3c_fimc_v4l2_s_fmt_vid_cap函数并没有打开输出DMA通道,因此CMOS摄像头的数据并没有传送到内核开辟的缓冲区中,导致V4L2也无法获取这些图像数据。而且由于没有打开输出DMA通道,out_frame参数也没有设置,导致其对应的尺寸参数也为0,所以报出第一个错误。


s3c_fimc_v4l2_s_fmt_vid_cap中通过调用s3c_fimc_ set_output_frame函数,打开输出DMA通道,解决了该问题。

2.4.2 错误2的分析与改进

该错误由s3c_fimc_v4l2_querybuf函数报出,报错条件是:

if(b->type!=V4L2_BUF_TYPE_VIDEO_OVERLAY&&b

->type!=V4L2_BUF_TYPE_VIDEO_CAPTURE)

该函数用于配置所申请图像缓冲区的长度、偏移量等属性,从而使所申请的环形队列缓冲区生效。由于本系统中摄像头仅用于图像捕获,因此在该函数开头可以将b->type进行强制设定,即:b->type=V4L2_BUF_ TYPE_VIDEO_CAPTURE,从而解决图像缓冲区申请的问题,该错误不再出现。

至此,修正后的FIMC驱动程序可以正常工作,图像数据得以传输到内核中为FIMC驱动开辟的图像缓冲区,应用程序可以通过read系统调用或者ioctl的VIDIOC_DQBUF命令获取图像数据。

图像捕获效果如图6所示。

3 结论

本文深入分析了CMOS摄像头驱动的原理和实现细节。FIMC驱动向内核申请四个ping-pong缓冲区,通过DMA方式传入图像数据,提高了图像数据传输速率。内存共享策略使得应用程序在访问图像缓冲区时免去了内存拷贝的步骤,大大缩减了图像获取的时间。但是目前的FIMC驱动在缓冲区出队和入队时的保护机制仍不够完善,需要在今后的工作当中对这一部分不断进行优化。

参考文献

[1] OminiVision Technologies Inc. OV9650 color CMOS SXGA (1.3MegaPixel)camerachipTM implementation guide[EB/OL].(2004-12-07)[2015-01-31]. http://www.ovt.com.

[2] 胡哲光.基于S3C2440与OV9650的嵌入式监控设计[J].轻工机械,2012,30(2):50-53.

[3] 官志平.基于ARM9的Linux系统移植以及在电梯轿厢内人数检测的应用[D].厦门:厦门大学,2014.

[4] Lu Yinli, Yu Hongli, Zhang Pengpeng. The implementation of embedded image acquisition based on V4L2[C]. Proceedings of the 2011 International Conference on Electronics, Communications and Control (ICECC), 2011:549-552.

[5] Zhang Min, Sun Jinguang, Wang Shi. Research and implementation of the CMOS camera device driver based on S3C2440[C]. Proceedings of the 2010 International Conference on Intelligent Computation Technology and Automation (ICICTA),2010:1039-1042.

[6] Kuang Shunming, He Xiaojian. Included in your digital subscription design and application of CMOS device driver based on S3C2440[C]. Proceedings of the 2011 10th International Conference on Electronic Measurement & Instruments (ICEMI),2011:342-343.

[7] Samsung. S3C6410x RISC microprocessor user′s manual (revision 1.2)[EB/OL].(2009-02-13)[2015-01-31]. http://www.samsung.com.

[8] DIRKS B. Video for Linux two API specification (revision 3.9)[EB/OL].(2012-12-03)[2015-01-31]. http://www.linuxtv.org/downloads/v4l-dvb-apis/v4l2spec.html.

相关推荐

用闲置电脑当软路由安装OpenWRT(小白教程)

话说软路由系统OpenWRT用起来真是香,里面的好多功能都是普通路由无法实现的,由于众所周知的原因,在这里就不细说,等安装完自己体验吧。今天就介绍用一台闲置的电脑(自带两个网口)充当软路由,安装Ope...

一招把废旧路由器改成交换机(用旧路由器做交换机)

家里面的路由器用个几年,就会WIFI变卡,新路由器买回来,旧路由器就没什么用了?我在这里教大家把老路由器变成交换机。近两年新出的路由器,基本都是2个LAN口,接网络设备还需要买交换机,淘汰下来的路由器...

如何将PC电脑变成web服务器:将内网主机映射到外网实现远程访问

我是艾西,今天跟大家分享内容还是比较多人问的一个问题:如何将PC电脑变成web服务器。内网主机作为web服务器,内容包括本地内网映射、多层内网映射解决方案、绕过电信80端口封锁、DDNS功能的实现(非...

电脑怎么改Wi-Fi密码(电脑怎么改wifi密码视频教程)

一.电脑打开“任意浏览器ie/google浏览器等”——>地址栏里输入管理ip地址然后按“回车键”打开该地址,如下图所示。二.输入正确的管理员密码——>点击“登录”即可(下图是PC版本的路...

旧路由器不要扔,可当电脑无线网卡使用,你还不知道吧!

家里有旧路由器,卖二手又不值钱,扔了又可惜。想不到路由器还有以下这些功能:扩大Wifi覆盖范围;充当电脑无线网卡;把这个技巧学起来,提升网络冲浪的幸福感!导航栏路由器恢复出厂设置(通用教程)有线桥接无...

硬件大师AIDA64 5.60.3716更新下载:“认准”Win10

著名硬件测试工具AIDA64更新至5.60.3716Beta版,本次更新修复了Win10Build版本号检测错误问题,识别更准确。另外还添加了对ITEIT8738F传感器、ASRock主板、NVI...

互联网病毒木马与盗版软件流量产业链(一)

A.相关地下产业链整体深度分析可能很多用户都有这样的经历,就是不管打开什么网站,甚至根本就没有打开浏览器,都会跳出来一堆的弹窗广告。那么,这个用户要么是中的病毒木马,或者是使用了盗版软件。不管是...

穿越火线tenparty.dat文件损坏怎么办?

很多玩家在玩火线的时候经常会因弹出错误代码,而被退出游戏。下面就教大家一些常见错误代码的解决方案。方法/步骤1SX提示码提示说明:您的电脑出现1,xxx,0(xxx代表任意数字)提示码,存在游...

办公小技巧015:如何关闭Windows Defender安全中心

WindowsDefenderWindowsDefender是Widows中自带杀毒软件,可以检测及清除潜藏在操作系统里的间谍软件及广告软件。为电脑提供最高强度的安全防护,也被誉为Windows的...

Win7/8.1/10团灭:微软发现严重漏洞

据外媒报道称,微软已经停止为Windows7发布新的安全更新了,理由是IE存在严重漏洞。存在严重漏洞的IE按照微软的说法,这个远程代码执行漏洞存在于IE浏览器处理脚本引擎对象的内存中。该漏洞可能以一...

WinCC flexible 2008 SP4 的安装步骤及系统要求

1、软件安装过程安装注意事项(必须严格遵守):软件仅支持以下操作系统(必须是微软原版的操作系统,Ghost版系统不支持,如番茄花园、雨林木风、电脑城装机版等):WinCCflexible2008...

Windows三方杀毒防护软件可能问题以及使用建议

在处理ECSWindows相关案例中,我们遇到很多奇怪的操作系统问题,例如软件安装失败,无法激活操作系统,无法访问本地磁盘,网络访问受到影响,系统蓝屏,系统Hang等,排查发现这与客户安装的各类杀...

杀毒软件被指泄露个人隐私(杀毒软件查出来一定是毒吗)

最近的多篇报道显示,你使用的杀毒软件在监视着你,而不仅仅是你计算机上的文件。2014年的一项研究使用虚拟机监视了杀毒软件产品向企业发送了什么信息。他们发现,所有测试的杀毒软件都给电脑分配了一个唯一的识...

开源杀毒软件ClamAV在推出约20年后终于到达1.0版本

ClamAV是一个开源的反病毒引擎,用于检测木马、病毒、恶意软件和其他恶意威胁。与商业Windows反恶意软件程序相比,它的检测水平相当低,但开发工作已经持续了几十年。该工具可用于所有平台,尽管它主要...

【Excel函数使用】时分秒时间怎么转换成秒?(二)

本节主要分享的函数是IFERROR和NUMBERVALUE上回我们用MID和FIND函数已经将数值提取出来,但是一些错误的返回值显示“#VALUE!”,此时我们需要检验错误返回值,并将错误值返回指定值...

取消回复欢迎 发表评论: