APP下载

Linux下基于I2C协议的RTC驱动开发

2010-05-13孟令公,朱宏,杨忠孝,杨裕辉

现代电子技术 2009年20期
关键词:嵌入式系统驱动程序

孟令公,朱 宏,杨忠孝,杨裕辉

摘 要:在嵌入式中,Linux渐渐成为一种流行操作系统,Linux驱动开发也成为嵌入式开发中的必备环节。介绍Linux环境下基于I2C协议的RTC驱动程序开发与实现。首先研究了Linux环境下字符设备驱动程序框架,然后介绍I2C协议,在此基础上开发基于I2C协议的RTC字符设备驱动程序。对于驱动程序,这里详细介绍其整体架构和各模块实现细节。最终成功实现了基于I2C协议的RTC驱动程序,并移植到Linux操作系统中。

关键词:嵌入式系统;Linux;驱动程序;I2C

中图分类号:TP316.81文献标识码:B

文章编号:1004-373X(2009)20-032-04

Development of RTC Driver Based on I2C under Linux

MENG Linggong,ZHU Hong,YANG Zhongxiao,YANG Yuhui

(University of Electronic Science and Technology of China,Chengdu,610054,China)

Abstract:In embedded field,Linux OS has been more and more popular,the development of Linux driver is becoming a constituent job.Reaserch and development of RTC driver based on I2C under Linux OS are introduced.First,research on the character device driver framework is given.Then,I2C protocol is introduced,RTC driver based on I2C under Linux OS is developed,the scheme and realization are proposed.Finally,RTC driver based on I2C is realized and transplanted into Linux.

Keywords:embedded system;Linux;driver;I2C

0 引 言

近年来嵌入式系统的研究与开发渐渐成为热点,在嵌入式系统中,Linux操作系统以其开源、稳定、可移植等种种优点,渐渐成为一种流行的操作系统。Linux下各种驱动程序的开发经常是软件开发中必不可缺的环节,Linux对其驱动程序提供了很好的支持框架。I2C总线是一种由Philips公司开发的两线式串行总线,用于连接微控制器及其外围设备。I2C总线产生于在20世纪80年代,最主要的优点是其简单性和有效性。这里介绍Linux字符设备驱动以及I2C总线协议,并在此基础上开发基于I2C总线的RTC驱动程序。

1 Linux字符设备驱动框架

在Linux内核中每个字符驱动程序都是基于以下框架进行设计的[1,2]:

struct file_operations {

ssize_t (*read) (struct file *,char __user *,size_t,loff_t *);

ssize_t (*write) (struct file *,const char __user *,size_t,loff_t *);

int (*ioctl) (struct inode *,struct file *,unsigned int,unsigned long);

int (*open) (struct inode *,struct file *);

int (*release) (struct inode *,struct file *);

… };

其中每个驱动程序必须实现的函数主要有:

(1) open()

在Linux或应用程序使用设备前都会调用驱动程序的这个方法。在驱动程序中open()方法一般用于对驱动程序支持的设备进行初始化。

(2) release()

当Linux或应用程序不再使用设备时会调用驱动程序的这个方法。release()方法主要用于在使用完毕支持驱动程序的设备后,对设备进行关闭操作。

(3) read()

read()方法主要用于供应用程序或Linux从字符设备中读取数据。read()方法读取的数据会从内核态拷贝到用户态,供应用程序使用[3]。

(4) write()

Linux或应用程序会调用write()方法写多个字节数据到字符设备中。应用程序的数据会首先从用户态拷贝到内核态,然后再传给write()方法。

(5) ioctl()

ioctl()方法向应用程序提供了一些独特的操作,这些操作不易通过read()方法或write()方法来实现[4,5]。

2 I2C协议以及RTC芯片介绍

2.1 I2C协议

I2C总线是一种由Philips公司开发的两线式串行总线标准,用于链接微控制器及其外围设备。I2C由数据线(SDA)和时钟线(SCL)构成的同步串行总线,可发送和接收数据。在处理器与被控制芯片之间,芯片与芯片之间进行双向传送[6]。

I2C总线在传送数据过程中共有三种类型信号, 它们分别是开始信号、结束信号和应答信号[3]。

开始信号 SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。

结束信号 SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。

应答信号 接收数据的设备在接收到8位数据后,向发送数据的设备发出特定的低电平脉冲,表示已收到数据。

(1) 控制字节。

在起始条件之后,必须是器件控制字节,其中高4位为器件类型识别符(不同芯片类型有不同定义),接着3位为地址片选,最后1位为读写位,当为1时读操作,为0时写操作。

(2) 写操作。

在写入时,I2C主控设备先发起起始位(S),抢占总线;然后,发送7位设备地址和1位0,表示对设备的写入;接着就是向设备传送数据。

(3) 读操作。

在读取时,要改变总线数据的传输方向,其流程如下:I2C主控设备发起起始位(S),抢占总线;发送7位设备地址和1位0,表示对设备写入;发送要写入的寄存器地址;再次发起起始位(S);发送7位的设备地址和1位1,表示对设备读取;从设备读取数据[7]。

2.2 RTC时钟芯片介绍

在此,采用精密时钟ISL1208向系统提供实时时间。ISL1208是Intersil公司的一款低功耗实时时钟集成电路。ISL1208寄存器可由后备电池供电。在从地址“1101111x”之后,可以访问,可以读或写到地址[00h~13h],可以通过对任意寄存器地址直接以字节写或页面写操作来修改寄存器的内容。

寄存器分成4段,它们是:实时时钟(7 B):地址为00h~06h;控制与状态(5 B):地址为07h~0Bh;报警(6 B):地址为0ch~11h;用户SRAM(2 B):地址为12h~13h。

由于只使用了其中的实时时钟寄存器,所以只对其中用到的寄存器进行描述。实时时钟寄存器主要包括SC(秒)、MN(分)、HR(时)、DT(日期)、MO(月)、YR(年)、DW(星期)。

2.3 IXP425网络处理器对I2C协议的支持

IXP425本身没有基于I2C协议的端口,但是ixp425有16个GPIO(GPIO0~GPIO15),即通用输入输出端口。这些GPIO可以由软件控制输出0或1,并且也可由软件去读取GPIO上的状态[8]。虽然Ixp425没有基于I2C协议的接口,但是可以采用它的GPIO来实现I2C信号发送与接受。具体采用:

GPIO7SDA数据信号发送与接受

GPIO6SCK时钟信号发送

3 基于I2C协议的RTC驱动程序设计

3.1 驱动程序总体框架

整个驱动程序可以分成两个模块,第一个模块是I2C协议实现部分,称之为I2C协议模块。第二个模块负责与Linux内核及应用程序交互,称之为RTC驱动模块[9],如图1所示。

图1 模块图

3.2 I2C协议实现模块

该模块中用到的宏与函数:

#define I2C_SDA_BIT 7

//gpio7配置为数据信号口SDA

#define I2C_SCK_BIT6

//gpio6配置为时钟信号口SCL

GPIO_DATA_BIT_WRITE_HIGH();

//设置GPIO状态为高

GPIO_DATA_BIT_WRITE_LOW();

//设置GPIO状态为底

(1) void GpioI2CStart(void)

功能:产生一次I2C开始信号。

实现:在SCL为高的情况下,SDA由高电平向低电平跳变。

函数流程图如图2所示。

(2) void GpioI2CStop(void)

功能:产生一次I2C传送结束信号。

实现:在SCL为高的情况下,SDA由低电平向高电平跳变。

函数流程图如图3所示。

图2 函数流程图(一)

图3 函数流程图(二)

(3) void GpioI2CSendByte(BYTE ucData)

功能:在I2C总线上发送一个字节(8位数据)。

参数:BYTE ucData 要发送的字节(8位数据)

实现:现在总线上写一个8位数据,然后等待ACK。函数流程如图4所示。

图4 函数流程图(三)

(4) UINT8 GpioI2CReceiveByte(void)

功能:在I2C总线上读取一个字节(8位数据)。

返回值:在I2C总线上读取到的数据。

实现:在总线上等待数据的读取。

函数流程如图5所示。

3.3 RTC驱动实现模块

RTC驱动模块主要实现struct file_operations结构框架。这里主要实现了该框架的read,write,ioctl,release几个函数成员。其中主要功能在ioctl中实现。

图5 函数流程图(四)

该结构的定义如下[10]:

struct file_operations I2C_rtc_fops =

{

.open = I2CRtcDrvOpen,

.release = I2CRtcDrvClose,

.read= I2CRtcDrvRead,

.write= I2CRtcDrvWrite,

.ioctl = I2CRtcDrvIoctl,

};

由于所有功能都在ioctl函数成员中实现,所以以下将主要介绍ioctl函数成员。

(1) ioctl函数用到的数据结构与调用的函数

typedef struct

{

unsigned char second;//秒

unsigned char minute;//分钟

unsigned char hour;//小时

unsigned char date;//日

unsigned char month;//月

unsigned char year;//年

}I2C_RTC_DATA_T;

该结构表示系统时间。在I2C驱动中,主要用来存储从I2C总线上读取的RTC时间。I2C协议模块把从RTC时钟中读取的时间转化为该类型,然后传给RTC驱动模块。RTC驱动模块再把该类型的系统时间传给用户态。

INT32 GpioI2CRead(UINT8 * address,UINT16 rom_address,UINT16 count);

INT32 GpioI2CWrite(UINT8 * address,UINT16 rom_address,UINT16 count);

这两个函数用于读和写RTC时钟上的寄存器,其中address参数为内存区缓冲地址,rom_address为RTC上寄存器地址,count为要读取的字节数。它们是基于I2C协议的调用来实现的。在以下函数中将会用到。

(2) int I2CRtcDrvIoctl(struct inode *inode,struct file *file,UINT32 cmd,unsigned long arg)

功能:这个是I2C驱动模块中的ioctl函数成员。

参数描述如表1所示。

表1 函数的参数描述

参数名类型说明

cmdUINT32用户态向内核态传入的命令

argunsigned long用户态向内核态传入的参数

cmd中传入的命令:

RTC_RD_TIME 读取RTC时钟时间

RTC_SET_TIME 设置RTC时钟时间

arg参数为一个指向I2C_RTC_DATA_T类型的指针,用于存取时间。

函数流程如图6所示,图中I2C_RTC_DATA_T gI2cRtcData;全局数据,表示时间。

图6 函数流程图(五)

该函数读取用户传入的命令(cmd),如果用户要获取时间,则调用底层函数读RTC寄存器,获取时间。如果用户要设置时间,则调用底层函数写RTC寄存器,设置时间。

4 结 语

这里介绍了Linux操作系统下基于I2C协议的RTC驱动程序的开发,主要介绍了I2C协议以及Linux字符设备驱动程序框架,并在此基础上给出了基于IXP425处理器、I2C协议的RTC字符设备驱动程序。该设备驱动程序包括最底层的协议开发,以及上层的驱动程序框架,具有很强的移植性。最终成功开发并实现了该驱动程序。

参考文献

[1]刘名博,邓中亮.基于ARM的嵌入式Linux操作系统移植的研究[J].计算机系统应用,2006,44(11):87-88.

[2]刘军芳,胡和智.基于ARM的嵌入式 Linux操作系统移植研究[J].科技信息:学术版,2006,22(5):29-31.

[3]王淑贞.U-Boot在S3C2410上的移植[J].微计算机应用,2008,29(4):95-97.

[4]刘广路.基于ARM的μCLinux片级移植[J].现代计算机,2008,33(1):131-133.

[5]孙纪坤,张小全.嵌入式Linux系统技术开发详解——基于ARM[M].北京:人民邮电出版社,2006.

[6]周立功,陈明计,陈渝.ARM嵌入式Linux系统构建与驱动开发范例[M].北京:北京航空航天大学出版社,2006.

[7]许振山,刘峥嵘.嵌入式Linux系统应用开发详解[M].北京:电力工业出版社,2007.

[8]李驹光,郑秋,江泽明.嵌入式Linux系统技术开发详解基于EP93XX系列ARM[M].北京:清华大学出版社,2006.

[9]Daniel P Bovet,Marco Cesa.深入理解Linux内核[M].2版.陈莉君,冯锐,牛欣源,译.北京:中国电子出版社,2004.

[10]陈渝,李明,杨晔.源码开放的嵌入式系统软件分析与实践[M].北京:北京航空航天大学出版社,2004.

猜你喜欢

嵌入式系统驱动程序
计算机硬件设备驱动程序分析
基于物联网项目驱动的嵌入式系统教学改革的研究与实践
嵌入式系统课程“中断、异常与事件”教学实践及启示
面向实践创新人才培养的嵌入式系统教学研究
基于MPC8280的CPU单元与内部总线驱动程序设计
妙用鼠标驱动
驱动程序更新与推荐