赞
踩
I2C (interintegrated Circuit)是一种简单的串行协议,它以主从关系连接多个设备。多个主设备可以共享一个总线。在不同的事务中,同一设备可以同时充当主从设备。I2C规范定义了这些传输速度范围:
I2C框架由以下部分组成:
hardware/i2c/* 硬件接口
lib/i2c 资源管理器层
<hw/i2c.h> 定义硬件和应用程序接口的公共头文件
I2C总线最常见的应用是对从设备寄存器的低带宽、低速率访问,例如:编写音频编解码器、编程一个RTC程序、读取温度传感器数据等等。 通常,总线上只交换几个字节。可以将I2C主机实现为单线程资源管理器或专用应用程序。资源管理器接口的主要优点是:
1、它为应用程序开发人员提供了一个清晰、易于理解的思路。
2、它作为一个中介,在多个应用程序对一个或多个从设备之间进行访问,强制不同I2C接口之间的一致性。
3、对于专用的i2c总线应用程序,硬件访问库更有效;硬件接口定义了这个库的接口,有助于维护和代码可移植性。
typedef struct {
size_t size; /* size of this structure */
int (*version_info)(i2c_libversion_t *version);
void *(*init)(int argc, char *argv[]);
void (*fini)(void *hdl);
i2c_status_t (*send)(void *hdl, void *buf, unsigned int len,
unsigned int stop);
i2c_status_t (*recv)(void *hdl, void *buf, unsigned int len,
unsigned int stop);
int (*abort)(void *hdl, int rcvid);
int (*set_slave_addr)(void *hdl, unsigned int addr, i2c_addrfmt_t fmt);
int (*set_bus_speed)(void *hdl, unsigned int speed, unsigned int *ospeed);
int (*driver_info)(void *hdl, i2c_driver_info_t *info);
int (*ctl)(void *hdl, int cmd, void *msg, int msglen,
int *nbytes, int *info);
} i2c_master_funcs_t;
这是整个硬件接口函数,提供了10个接口函数,分别对10个接口函数进行介绍:
1、version_info函数来获取关于库版本的信息。这个函数的原型是:
int version_info( i2c_libversion_t *version );
version参数是指向这个函数必须填充的i2c_libversion_t结构的指针。该结构定义如下:
typedef struct {
unsigned char major;
unsigned char minor;
unsigned char revision;
} i2c_libversion_t;
这个函数应该设置这个结构的成员如下:
version->major = I2CLIB_VERSION_MAJOR;
version->minor = I2CLIB_VERSION_MINOR;
version->revision = I2CLIB_REVISION;
2、init函数初始化主接口。该函数的原型是:
void *init( int argc, char *argv[]);
参数是在命令行上传递的。函数返回传递给所有其他函数的句柄,如果发生错误则返回NULL。这个函数主要根据命令行解析来进行I2C初始化。
3、fini函数清理驱动程序并释放与给定句柄关联的所有内存。该函数的原型是:
void fini(void *hdl);
hdl init函数返回的句柄。
4、发送函数启动主发送。通信完成时将发送一个可选事件(可以释放数据缓冲区)。如果此函数失败,则未启动任何通信。
i2c_status_t send(
void *hdl,
void *buf,
unsigned int len,
unsigned int stop );
hdl :init函数返回的句柄;
buf:指向要发送的数据缓冲区的指针;
len:要发送的数据的长度(以字节为单位);
stop:如果这是非零的,函数将在发送完成时设置停止条件;
返回状态为:
I2C_STATUS_DONE:传输完成,并且没有错误。
I2C_STATUS_ERROR:传输错误
I2C_STATUS_NACK:没有ACK
I2C_STATUS_ARBL:失去了仲裁。
I2C_STATUS_BUSY:传输超时
I2C_STATUS_ABORT:传输终止
5、recv函数启动主接收。传输完成时将发送一个可选事件(可以使用数据缓冲区)。如果此函数失败,则未启动任何传输。
该函数的原型是:
i2c_status_t recv(
void *hdl,
void *buf,
unsigned int len,
unsigned int stop );
hdl :init函数返回的句柄;
buf:指向要接收的数据缓冲区的指针;
len:要接收的数据的长度(以字节为单位);
stop:如果这是非零的,函数将在发送完成时设置停止条件;
返回状态为:
I2C_STATUS_DONE:传输完成,并且没有错误。
I2C_STATUS_ERROR:传输错误
I2C_STATUS_NACK:没有ACK
I2C_STATUS_ARBL:失去了仲裁。
I2C_STATUS_BUSY:传输超时
I2C_STATUS_ABORT:传输终止
6、中止功能迫使主程序释放总线。当停止条件被发送时,它返回。该函数的原型是:
int abort(
void *hdl,
int rcvid );
hdl: init函数返回的句柄。
rcvid:客户端的接收ID。
7、set_slave_addr函数指定目标从地址。该函数的原型是:
int set_slave_addr(
void *hdl,
unsigned int addr,
i2c_addrfmt_t fmt );
hdl: init函数返回的句柄。
addr: 目标从地址。
fmt:地址的格式; I2C_ADDRFMT_7BIT 和I2C_ADDRFMT_10BIT
8、set_bus_speed函数指定总线速度。如果请求的总线速度无效,该函数将返回一个失败,并保持总线速度不变。该函数的原型是:
int set_bus_speed(
void *hdl,
unsigned int speed,
unsigned int *ospeed );
hdl
init函数返回的句柄。
speed
总线的速度。
ospeed
NULL或指向函数应该存储实际总线速度的位置的指针。
9、driver_info函数返回有关驱动程序的信息。该函数的原型是:
int driver_info(
void *hdl,
i2c_driver_info_t *info );
hdl
init函数返回的句柄
info
一个指向i2c_driver_info_t结构的指针,函数应该在该结构中存储信息:
typedef struct {
uint32_t speed_mode;
uint32_t addr_mode;
uint32_t reserved[2];
} i2c_driver_info_t;
10.ctl函数处理一个驱动程序特定的devctl()命令。该函数的原型是:
int ctl(
void *hdl,
int cmd,
void *msg,
int msglen,
int *nbytes,
int *info );
hdl:init函数返回的句柄;
cmd:设备命令;
msg:一个指向消息缓冲区的指针。该函数可以更改缓冲区的内容;
msglen:消息缓冲区的长度,以字节为单位;
nbytes:返回的字节数。这个不能大于msglen;
Info:指向函数可以存储devctl()返回状态信息的位置指针;
资源管理器接口使用此函数访问特定于硬件的函数。它必须得到执行;
int i2c_master_getfuncs(i2c_master_funcs_t *funcs, int tabsize);
硬件访问接口流程如下:
#include <hw/i2c.h>
i2c_master_funcs_t masterf;
i2c_libversion_t version;
i2c_status_t status;
void *hdl;
i2c_master_getfuncs(&masterf, sizeof(masterf));//初始化硬件接口
masterf.version_info(&version);
if ((version.major != I2CLIB_VERSION_MAJOR) ||
(version.minor > I2CLIB_VERSION_MINOR))
{
/* error */
...
}
hdl = masterf.init(...); //调用初始化函数
masterf.set_bus_speed(hdl, ...); //设置总线速度
masterf.set_slave_addr(hdl, ...); //设置从地址
status = masterf.send(hdl, ...);//发送数据
if (status != I2C_STATUS_DONE) {
/* error */
if (!(status & I2C_STATUS_DONE))
masterf.abort(hdl);
}
status = masterf.recv(hdl, ...);//接收数据
if (status != I2C_STATUS_DONE) {
/* error */
...
}
masterf.fini(hdl);//完成I2C传输后,清理驱动程序并释放与给定句柄关联的所有内存
当I2C主设备专用于单个应用程序使用时,可以将硬件接口代码编译为库并将其链接到应用程序。
为了提高代码的可移植性,应用程序应该调用i2c_master_getfuncs()来访问特定于硬件的函数。通过功能表访问硬件库,应用程序更容易加载和管理多个硬件库。
资源管理器接口以类似的方式使用硬件库。
资源管理器层实现为静态链接到硬件库的库,提供了一个单线程管理器,libi2c-master。
在启动时,resmgr层执行以下操作:
i2c_master_getfuncs(&masterf)
masterf.init()
masterf.set_bus_speed()
然后,资源管理器让自己在后台运行,下面是资源管理器处理这些devctl()命令:
资源管理器线程一直占用,直到传输完成并回复客户端,可以通过向资源管理器发送SIGTERM来终止它。
1、首先在startup 对I2C进行硬件初始化,包括基地址、中断向量、时钟等等,这部分和硬件相关。
2、首先驱动从build 文件里进行加载,在dev生成设备节点,/dev/i2c1 等等
3、编写I2C驱动,其中init.c解析build加载参数,如I2C基地址地址、 中断号等等,并在lib.c 对所有的I2C驱动进行封装,调用i2c_master_getfuncs函数实现。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。