APP下载

高速公路视频监控下RX-8025实时时钟系统研究与设计

2015-01-28廖建尚曹成涛杨志伟

电子设计工程 2015年19期
关键词:驱动程序调用时钟

廖建尚,曹成涛,杨志伟

(广东交通职业技术学院 计算机工程学院,广东 广州 510650)

随着社会的发展,汽车不断增多,高速公路上违章的车辆也逐渐增多,为了构建一个平安交通和智能交通,视频监控系统在交通行业的应用也越来越多,为了能对高速公路进行监控,高清视频监控也应用越来越广泛[1]。

文中将研究详细分析RX8025和I2C的工作原理和通信协议和Linux的I2C总线驱动程序,设计一个应用在高速公路视频监控的基于I2C的RX-8025实时时钟控制系统,为高速公路的高清视频监控提供一个设计方案。

1 高速公路视频监控系统以及实时时钟系统设计

本研究课题的高速公路高清视频监控系统采用TI公司的TMS320DM368,DM368是一款面向多媒体技术应用的高性能芯片,功能强大,集成了ARM9、硬件编码协处理引擎(HDVICP)、图像处理子系统(VPSS)。DM368最高可以支持H.264编码 1080P格式 30帧/s的速度。该处理器有I2C总线等外围接口等,其中ARM9运行性能稳定的Linux嵌入式操作系统[2]。

视频监控系统中实时时钟控制的设计采用DM368的I2C总线接口,设计基于ARM9的I2C云台电机,完成驱动程序设计和应用程序设计,以及应用程序控制RX-8025实时时钟,应用于视频监控系统中,达到全方位的高速公路视频监控。

2 RX-8025实时时钟硬件构成和通信协议

2.1 RX-8025简介

RX-8025是一种具有高精度,包括32.768 kHz晶振时钟I2C总线接口的实时时钟芯片,该芯片提供的功能有6个中断,2个系统闹钟功能、电源电压监测和数字时钟精度调节功能来满足不同精度要求,其中计时功能可以进行至阳历二位数和年、月、日、时、分、秒为止的数据设定,包括计时和读取,当阳历的下二位数为4的倍数时,可自动识别至2099年。因此RX-8025适用于高清视频监控的嵌入式系统,用于计时同步[5]。

2.2 RX-8025管脚功能

SCL:I2C通信用的串行时钟输入,与时钟信号同步,SDA SDA:与I2C通信串行时钟同步,进行地址、数据、应答等的输入输出。

图1 RX-8025内部时钟信号图Fig.1 Internal clock signal of RX-8025

FOUT:由FOE控制的32.768 kHZ时钟输出端;

FOE:控制FOUT输出时钟信号的输入脚内置,当它接高电平时,FOUT脚输出时钟信号;

RX-8025使用I2C和外围芯片进行数据通信,因此,本系统中ARM9和RX-8025通信需要通过I2C总线,因此需要完成Linux在ARM9的I2C驱动。

2.3 I2C硬件构成和通信协议

I2C总线是由双向数据线和时钟线构成的二线制串行总线,总线采用主从双向通信,即总线上在某一时刻只有一个主设备总线上的其他设备都作为从设备,任何能够进行发送和接收的设备都可以成为主设备,但是在同一时间内只能有一个设备作为主设备,通常为处理器,其他器件作为从设备与主设备进行通信,采用唯一的I2C地址识别[5]。

图2 I2c工作时序Fig.2 Working sequence of I2c

如图2所示I2C的工作时序图所示,I2C总线在传送数据过程中使用了3种信号。1)开始信号:SCL为高电平时,SDA由高电平向低电平跳变,表示将要开始传送数据;2)应答信号:从设备在接收到1个字节数据后向主设备发出一个低电平脉冲应答信号,表示已收到数据,主设备根据从设备的应答信号做出是否继续传输数据的操作;3)结束信号:为低电平时由低电平向高电平跳变,表示数据传送结束[4-5]。

总线具体的通信工作原理:主设备首先发出开始信号,接着发送的1个字节的数据,其由高7位地址码和最低1位方向位组成。系统中所有从设备将自己的地址与主设备发送到总线上的地址进行比较,如果从设备地址与总线上的地址相同,该设备就是与主设备进行数据传输的设备。接着进行数据传输,根据方向位,主设备接收从设备数据或发送数据到从设备。当数据传送完成后,主设备发出一个停止信号,释放I2C总线,然后所有从设备等待下一个开始信号的到来[4-5]。

3 I2C的Linux和ARM驱动设计

3.1 Linux2.6.32的I2C驱动分析

I2C由主设备和从设备构成,通信上通过识别I2C地址进行通信,即可以存在多个i2c adapter适配器和多个外设i2c device,Linux的I2C驱动采用分层设计实现的思想,层与层之间不存在耦合,增加adapter和增加device不会影响其他驱动,具体分层如下。

第一层:提供i2c adapter的硬件驱动,探测、初始化i2c adapter(如申请I2C地址和中断号),驱动处理器控制的i2c adapter在硬件上产生信号(开始、停止、应答)以及处理i2c中断,涉及图2中的硬件实现层;

第二层:提供i2c adapter的algorithm,用具体适配器的函数来填充i2c_algorithm的master_xfer函数指针,并把赋值后的i2c_algorithm,再赋值给i2c_adapter的成员指针,主要涉及图2中访问抽象层、i2c核心层;

第三层:实现i2c设备驱动中的i2c_driver接口,用具体的 i2c device 设备的 i2c_add_driver()、i2c_del_driver()方法赋值给i2c_driver的成员函数指针,采用Probe探寻方式实现设备device与总线的挂接,涉及图2中的driver驱动层,此层是本文实现的驱动部分;

第四层:实现i2c设备所对应的具体device的驱动,i2c_driver只是实现设备与总线的挂接,挂接在总线上的设备千差万别的,所以要实现具体设备device的write()、read()、ioctl()等方法,赋值给file_operations,然后注册字符设备,涉及图2中的driver驱动层,此层是本文实现的驱动部分。

第一层和第二层又叫i2c总线驱动(bus driver),第三层和第四层属于i2c设备驱动(device driver)。在Linux驱动架构中,不需要再开发总线驱动,因为Linux内核几乎集成所有总线驱动,驱动设计主要是实现第三层和第四层的设备驱动。

图3 I2c驱动架构图Fig.3 Driven architecture of I2c

3.2 Linux系统中i2c驱动中结构体分析

Linux中的I2C驱动分层设计涉及了多个数据结构,数据结构的设计在I2C分层设计中起了非常重要的作用,数据结构有i2c_driver、i2c_client、i2c_adapter,下面具体分析这三个数据结构之间的关系。

1)i2c_driver与i2c_client

i2c_driver对应Linux的一种驱动方法,它不对应于任何的物理实体。

i2c_client对应于真实的物理设备,每个I2C设备都需要一个 i2c_client来描述,i2c_client代表一个挂载到I2C总线上的I2C从设备,该设备所需要的数据结构,包括该I2C从设备所依附的I2C主设备i2c_adapter,I2C从设备的驱动程序i2c_driver,作为i2c从设备所通用的成员变量;

struct i2c_client{

unsigned shortaddr; /* chip address -NOTE:7bit */

struct i2c_adapter*adapter;/*该i2c从设备所依附的i2c主设备*/

struct i2c_driver*driver;/*该i2c从设备的驱动程序*/

intusage_count; /*目前挂接I2C从设备的数量 */

struct device dev; /*该i2c从设备驱动所特有的数据*/

struct list_head list;/*链表*/

char name[I2C_NAME_SIZE];/**/

}

i2c_driver与 i2c_client发生关联的时刻在 i2c_driver的attach_adapter()函数被运行时,attach_adapter()会探测物理设备,当确定一个I2C从设备存在时,把该 client使用的i2c_client数据结构的 adapter指针指向对应的i2c_adapter。

2)i2c_adpater与i2c_client

i2c_adpater与 i2c_client的关系与 I2C硬件体系中适配器和设备的关系一致,即 i2c_client依附于 i2c_adpater,一个i2c_adpater上可以连接多个 I2C设备,i2c_adpater中包括依附于它的i2c_client的链表。

3)结构体i2c_msg解析

i2c_msg用于I2C驱动第三层和第二层的数据交换,i2c_transfer通过调用master_xfer函数传递i2c_msg结构体,结构体包括成员变量有设备地址addr,消息长度len和消息数据buf以及读写标志的宏定义,具体如下:

struct i2c_msg{

__u16 addr;/*设备地址*/

__u16 flags;/*标志 */

__u16 len;?/*消息长度*/

__u8*buf;?/*消息数据*/

#define I2C_M_TEN 0x10 /*we have Aten bit chip address */

#define I2C_M_RD 0x01

#define I2C_M_NOSTART 0x4000

#define I2C_M_REV_DIR_ADDR 0x2000

#define I2C_M_IGNORE_NAK 0x1000

#define I2C_M_NO_RD_ACK 0x0800};

3.3 RX8025实时时钟的I2C驱动设计

根据Linux2.6.32的驱动分层设计[3,5,7],驱动的第一层和第二层在Linux-2.6.32中以及集成了成熟驱动,文中重点讲述第三层和第四层驱动程序的设计。

驱动设计采用字符设备方式来实现,RX8025_I2C_Init()和RX8025_I2C_Exit()实现驱动的初始化以及退出,初始化最后调用cdev_add()实现字符设备的添加,添加过程中通过完善file_operations的结构体,填充了以下4个结构体变量。

Struct file_operations i2c_dev_ops={

.open=RX8025_Open,

.close=RX8025_Close,

.read=RX8025_Read,

.write=RX8025_Write

};

这4个用户空间接口驱动函数,完成注册后,用户空间可以采用文件读写的方式来操作I2C设备了,RX8025_Open函数实现打开实时时钟字符设备,RX8025_Close函数实现关闭实时时钟字符设备,数据交换通过接口RX8025_Read和RX8025_Write来实现,主要实现设备的数据读取和数据写入,从而完成用户空间和驱动程序以及硬件设备的数据交换,i2c_board_info结构体中,“RX8025-i2c” 定义为 RX8025的I2C名字,0x32为RX8025的地址,该数据结构的填充在Board-dm368-evm.c文件,Board-dm368-evm.c文件包含了大部分驱动的数据信息,系统启动会自动加载相关驱动信息。一个i2c_client就代表着一个位于adapter适配器上,地址为client->addr,使用设备驱动的一个i2c设备。

static struct i2c_board_info i2c_info[]={

{I2C_BOARD_INFO("RX8025-i2c",0x32),

},};

本设计主要完整时钟数据的读取,用于同步到系统中,因此重点实现RX8025_Read接口函数,RX8025_Read利用i2c_transfer函数调用master_xfer实现时钟数据的读取,具体实现过程如图4所示,其中i2c_probe和RX8025_Read实现部分代码如下:

struct i2c_client*rx8025_client=NULL;

static int i2c_probe(struct i2c_client*client, const struct i2c_device_id*id){……

rx8025_client=client;……}

int I2C_read (struct file*file,unsigned char*buffer,unsigned char count){

client=( struct i2c_client*)file->private_data;for(i=0;i

msg->addr=((client->addr)>>1);

msg->flags=0;

msg->len =1;

msg->buf=data;

data[0] =reg[i];

err=i2c_transfer(client->adapter,msg,1);}//end of for

}

图4 RX8025_Read驱动的实现过程Fig.4 Driven implementation process of RX8025_read

4 RX8025实时时钟I2C应用程序设计

根据I2C驱动程序设计[7],要正确调用驱动程序,需要实现驱动的用户空间调用函数,主要是实现open、read和write等函数,因此在应用层的接口函数中也需要实现此函数。

i2c_Init()函数实现open函数,调用驱动函数打开该设备驱动,定义一个数据结构体为:

int Rx_8025(){

fd_rx8025=open(I2C_RX8025_NAME,O_RDWR);if(fd_rx8025<0) {

printf("open/dev/rx8025_i2c error!");

return-1;

}

return 0;

}

设备通过open函数正确打开后,就能通过读写函数进行数据交换了,该结构体主要用来实现用户空间和内核空间的调用的数据交换,下面通过read数据读取函数说明具体的实现过程,其中buf用于保存读取数据,count用于读取数据的字节数。

int RX8025_read(uint8_t*buf,uint8_t count){

unsigned char ret

ret=read(fd_rx8025,buf,count);if(status<0)

printf("RX8025 read error! ");

return reg;}

如图5所示,可以通过人机交互设置实时时钟或读取实时时钟、同步系统时钟,调用setTime()和synTime()接口函数来调用write()和read()文件IO读写文件,最终调用write()和read()的字符驱动函数实现对I2C驱动的调用。

图5 云台电机控制应用程序设计图Fig.5 Application design of PTZmotor control

5 RX8025实时时钟应用程序设计

实时时钟在本系统中有两个功能,一是通过QT图形界面软件输入时间信息来设置实时时钟的时间,可以在界面年月日时分秒信息,通过调用应用程序函数达到时间设置的目的,二是从而带动视频监控的摄像头朝不同方位转动以及定位,如图所示。根据协议,应用程序设计主要实现以下操作:

1)设置当前的时钟信息,函数接口为setTime();

2)同步实时时钟的时钟信息到系统,函数接口为synTime();

下面通过时钟同步函数的接口函数synTime(),详细RX8025实时时钟应用程序接口函数的实现过程,通过调用用户空间和内核空间的read()函数实现对驱动的调用,最终通过I2C总线设置时钟和读取时钟数据。

通过实现人机交互操作程序,实现设置当前的时钟信息和同步实时时钟的时钟信息到系统,通过调用相应的接口函数,实现对I2C应用程序的调用,最后通过read、write函数实现对RX-8025的控制,具体实现如图5所示。

6 结束语

本系统设计实现了一款基于TMS320DM368的高清视频监控系统中的实时时钟系统控制设计,完成了实时时钟RX8025的I2C驱动程序的分析以及设计,并且完成了i2c应用程序的设计和实时时钟RX8025控制应用程序设计,达到了应用目的。

[1]张志.高速公路高清视频监控系统的构建[J].中国交通信息化,2011(4):99-102.ZHANG Zhi.Construction of the highway high-definition video surveillance system[J].China ITSJoural,2011(4):99-102.

[2]Texas Instruments Incorporated.TMS320DM368 digitalmedia sys-tem-on-Chip(DMSoC).[EB/OL](2014-03)http://www.ti.com/lit/ds/sym link/tms320dm368.pdf.

[3]TMS320DM36x Digital Media System-on-Chip(DMSoC)Inter-Integrated Circuit(I2C)Module User's Guide[EB/OL].[2014-03].http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/dvsdk/DVSDK_4_00/latest/index_FDS.html.

[4]高非非.ARM-Linux中I2C总线驱动开发[J].微型机与应用,2012(5):57-58.GAO Fei-fei.Design of I2C bus driver based on ARM-Linux[J].Network and Comunication,2012(5):57-58.

[5]Philips Corp.The I2C-BUSSpecification Version 2.1[Z],2000.

[6]Real time clock module RX-8025SA/NB applicationmannual[M].EPSON Toyocom,2002.

[7]Jonahan Corbet.Linux device drivers[M].北京:中国电力出版社,2006.

猜你喜欢

驱动程序调用时钟
别样的“时钟”
古代的时钟
核电项目物项调用管理的应用研究
LabWindows/CVI下基于ActiveX技术的Excel调用
计算机硬件设备驱动程序分析
有趣的时钟
基于系统调用的恶意软件检测技术研究
时钟会开“花”
基于MPC8280的CPU单元与内部总线驱动程序设计
利用RFC技术实现SAP系统接口通信