前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Linux驱动炼成记] 01-用户空间操作IIC

[Linux驱动炼成记] 01-用户空间操作IIC

作者头像
程序手艺人
发布2019-02-21 16:21:50
2K0
发布2019-02-21 16:21:50
举报
文章被收录于专栏:程序手艺人

工具准备

调试IIC过程中,需要准备示波器或逻辑分析仪,需要通过示波器查看波形确定硬件连接是否正确,不然出现问题,软件再怎么调试,都是枉然.

  • 普源示波器RIGOL(DS1102E)
  • 逻辑分析仪,淘宝上购买,USB 逻辑分析仪
    • 24M采样8通道
    • 自动分析UART,IIC,SPI等诸多标准协议

实际使用过程中,效果还不错,体积很小,USB接口, 自己解析IIC波形, 相比示波器,方便许多。

用户空间操作I2C

I2C设备驱动有两种模式:一种是用户层操作驱动设备,另一种是普通的设备驱动,应用层使用的时候像读写文件一样. 内核中驱动中/drivers/i2c/i2c-dev.c提供了I2C设备的驱动,实现了read().write().ioctl等函数,不过read()和write()函数每次只能读写一次数据,无法实现连续的数据读写,如下图:

这里写图片描述
这里写图片描述

注意:先write()地址之后总线上会有stop,之后read(),这种方式无法实现连续数据读取,使用ioctl函数来实现连续数据的读写,这样中间就没有stop.

示例代码

两个重要的数据结构

  • struct i2c_rdwr_ioctl_data结构体
  • /inclue/linux/i2c-dev.h
代码语言:javascript
复制
/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
	struct i2c_msg __user *msgs;	/* pointers to i2c_msgs */
	__u32 nmsgs;			/* number of i2c_msgs */
};
  • struct i2c_msg 结构体
  • include/linux/i2c.h
代码语言:javascript
复制
struct i2c_msg {
	__u16 addr;	/* slave address			*/
	__u16 flags;
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
	__u16 len;		/* msg length				*/
	__u8 *buf;		/* pointer to msg data			*/
};

注意: 一般buf[0]是写的地址,buf[1]之后都是写的数据; 如果读,第一遍写地址时buf[0]是地址,第二遍读数据时存放读的数据

  • Demo
代码语言:javascript
复制
int i2cWriteByte(int* i2c, int devAddr, int slaveAddr, int len, unsigned char data_buf[])
{
    int ret = 0;
    struct i2c_rdwr_ioctl_data ctl_data;
    struct i2c_msg msg;
    unsigned char msg_buf[50];
    memset((void *) msg_buf, 0, 50);
    msg_buf[0] = (unsigned char) (slaveAddr & 0x00ff); //第0位存放寄存器地址
    if (data_buf == NULL) {
        return -1;
    }

    if (len < 50) {
        memcpy((void *) &msg_buf[1], data_buf, len);  //第1位之后是数据
    } else {
        printf("i2c write error!\n");
        return -1;
    }
    msg.addr = devAddr;  //从设备地址
    msg.flags = I2C_M_WR;
    msg.len = 1 + len;
    msg.buf = msg_buf;
    ctl_data.nmsgs = 1;
    ctl_data.msgs = &msg;
    ret = ioctl(*i2c, I2C_RDWR, &ctl_data);
    usleep(5 * 1000);
    return ret;
}

调试工具

测试程序完成之后,需要进一步调试,通过示波器或逻辑分析仪查看I2c波形是否正确,调试过程中,抓取了一段波形:

这里写图片描述
这里写图片描述

发现第9位ACK信号为高电平(图中红色箭头),一番检查之后,最终发现硬件接线错误,修改之后,波形正常.

痛的领悟: 调试外设,软件写的再好,也是枉然.需要结合硬件,综合查看,才能快速定位问题

也可以结合芯片的DataSheet发现波形异常

这里写图片描述
这里写图片描述

参考

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年12月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 工具准备
  • 用户空间操作I2C
    • 示例代码
    • 调试工具
    • 参考
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档