i2c通道在开发过程中使用是非常的方便的,主要是由于其简单的结构,i2c主要有SCL,SDA两条通道,一个时钟线,一个数据线,这也是i2c之所以应用如此普遍的原因。i2c的时序如下:

实现上述时序,便可以轻松通过i2c读写寄存器了,接下来看看i2c下在Linux应用层中实现读写,主要是通过O_RDWR IOTCL读写i2c设备,写函数如下:

static int iic_write(int i2c_fd, unsigned int reg_address ,unsigned int reg_val)
{
struct i2c_rdwr_ioctl_data work_queue;
int ret;

work_queue.nmsgs = 2;
work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs * sizeof(struct i2c_msg));
if(!work_queue.msgs)
{
printf("msgs memery alloc error\n");
close(i2c_fd);
return 0;
}
if ((work_queue.msgs[0].buf = (unsigned char *)malloc(2 * sizeof(unsigned char))) == NULL)
{
printf("buf memery alloc error...\n");
close(i2c_fd);
return 0;
}

(work_queue.msgs[0]).len = 2;
(work_queue.msgs[0]).flags = 0;
(work_queue.msgs[0]).addr = slave_address;
(work_queue.msgs[0]).buf[0] = reg_address;
(work_queue.msgs[0]).buf[1] = reg_val;

work_queue.nmsgs = 1;

ioctl(i2c_fd, I2C_RDWR, (unsigned long) &work_queue);
if(ret < 0)
{
printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
return 0;
}
free(work_queue.msgs[0].buf);
free(work_queue.msgs);

}

上述贴出的代码分析 :

i2c_rdwr_ioctl_data结构体的源码如下

struct i2c_rdwr_ioctl_data {   
 /* pointers to i2c_msgs                 */ 
   struct i2c_msg __user *msgs;   
 /* number of i2c_msgs                   */
    __u32 nmsgs;
};
这个结构中nmsgs是指要发送的消息的数量,其次是i2c_msg,这个才是i2c设备的核心结构体,在内核中源码如下
struct i2c_msg
{
unsigned short addr;   //slave IIC device addr 
unsigned short flags; //write read flags 
#define I2C_M_TEN0x0010/* this is a ten bit chip address */
#define I2C_M_RD0x0001/* read data, from slave to master */
#define I2C_M_NOSTART0x4000/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR0x2000/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK0x1000/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK0x0800/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN0x0400/* length will be first received byte */

unsigned short len;    //写入或者读出数据的个数(字节)
unsigned char *buf;    //写入或者读出数据的地址 buf[0] 
};

在这个结构体中可以清楚的看到i2c的各个参数带表的意思,根据下面的程序可以更好的理解。
我在上述的代码中发送了2条消息,但是细心的朋友应该会注意到代码的work_queue.nmsgs = 1;这条信息,这是因为实际上我在写函数中只写了一条消息,实际我只需要给一个寄存器只写一条信息即可,已经可以实现我的寄存器写入功能,之所以写着是因为当时在调试过程中我首先是去读寄存器的,读一个寄存器之少需要两条消息,从datasheet可知,i2c读信号如下图所示

i2c的实际地址是0x1c,通过 (0x1c<<1) | 0 得到i2c写地址, (0x1c<<1) | 1 得到i2c读地址。在读i2c主设备模式下ST是指开始位,Device Address是指传感器设备地址及0x1c,w写标志位,后面紧跟着寄存器地址,SR是指重写启动i2c地址,所以读i2c至少要两条消息,我在写消息的时候为了保持读写消息的一致,也将写函数中写了两条消息,在运行过程中导致系统内核崩溃。为了解决这个问题,只要在i2c下发消息前,重新给发送的消息赋值即可。接下来实现i2c的读函数,在调试过程中一旦实现了i2c的驱动,首先应该实现的是读函数。

i2c的读函数如下:

static int iic_read(int i2c_fd, unsigned int reg_address)
{
struct i2c_rdwr_ioctl_data work_queue;
unsigned char val;
int ret;

work_queue.nmsgs = 2;
work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs *sizeof(struct i2c_msg));

if(!work_queue.msgs)
{
printf("Memery alloc error\n");
close(i2c_fd);
return 0;
}

val =(unsigned char)reg_address;

(work_queue.msgs[0]).len = 1;
(work_queue.msgs[0]).flags = 0;
(work_queue.msgs[0]).addr = slave_address;
(work_queue.msgs[0]).buf = &val;

(work_queue.msgs[1]).len = 1;
(work_queue.msgs[1]).flags = 1;
(work_queue.msgs[1]).addr = slave_address;
(work_queue.msgs[1]).buf = &val;

ret = ioctl(i2c_fd, I2C_RDWR, (unsigned long) &work_queue);
if(ret < 0)
{
printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
return 0;
}

free(work_queue.msgs);

return val;
}

这样就可以直接调用i2c读写函数实现对传感器寄存器的操作了。最后在说明一点,千万不要忘记给i2c_rdwr_ioctl_data结构体中的最重要最重要最重要的结构i2c_msg中的buf分配内存。

Linux应用层的i2c读写相关推荐

  1. Linux系统 通过i2c读写铁电存储器 ram

    imx6ul上要加入铁电存储器,型号fm24cl64b,存储器焊接在i2c 1上,期间选择位都为0,使用open打开/dev/i2c-0,配置地址时舍弃最后一位读写位,系统会自动提供,(如:铁电存储器 ...

  2. S3C2440 Linux下的I2C驱动以及I2C体系下对EEPROM进行读写操作。

    这篇文档算上期末复习这段时间其实拖了有好久了,因为从一开始接触linux的i2c驱动体系我就各种凌乱,因为起初脑海中既没有整体框架也不熟悉相关体系下的结构,所以四处乱看,经常性的在看内核代码时看着看着 ...

  3. linux i2c 读写函数,Linux下读写芯片的I2C寄存器

    要想在Linux下读写芯片的I2C寄存器,一般需要在Linux编写一份该芯片的I2C驱动,关于Linux下如何编写I2C驱动,前一篇文章<手把手教你写Linux I2C设备驱动>已经做了初 ...

  4. linux i2c 读写函数,Linux内核调用I2C驱动_实现MPU6050的数据读取

    0. 导语 最近一段时间都在恶补数据结构和C++,加上导师的事情比较多,Linux内核驱动的学习进程总是被阻碍.不过,十一假期终于没有人打扰,有这个奢侈的大块时间,可以一个人安安静静的在教研室看看Li ...

  5. linux kernel 2.6 i2c设备驱动程序框架介绍,linux设备驱动程序-i2c(2)-adapter和设备树的解析...

    linux设备驱动程序-i2c(2)-adapter和设备树的解析 (注: 基于beagle bone green开发板,linux4.14内核版本) 而在linux设备驱动程序--串行通信驱动框架分 ...

  6. 嵌入式Linux应用层开发教程(一)基本概念

    1 应用层与驱动层 要想学习嵌入式Linux应用层的开发,首先要区分好应用层和驱动层之间的关系.我们在本科阶段学习51等较简单的单片机时,都是把应用层和驱动层混在一个文件里写的.比如拿下面的I2C程序 ...

  7. Linux驱动分析——I2C子系统

    stm32mp157  盘古开发板  Linux内核版本4.19 目录 1.朱有鹏老师视频笔记 2.I2C子系统的4个关键结构体 3.关键文件 4.i2c-core.c初步分析 ​4.1.smbus代 ...

  8. linux驱动之i2c学习

    最近在研究linux的i2c驱动,从最底层i2c控制器初始化到应用层与i2c设备交互基本打通了. 一.linux的i2c架构可以用下图表示: IIC适配器对应一条i2c总线,linux里面用i2c_a ...

  9. linux i2c子系统看不懂啊,Linux 下的I2C子系统

    Linux 下的I2C子系统 2013.7.16 本文分为两部分,一.设备模型 二.平台相关 . ================================================ 第一 ...

最新文章

  1. 附庸风雅(2006-10-20 13:39:32)(新浪)
  2. Android 让你的SeekBar 也支持长按事件
  3. 并发编程—Volatile关键字
  4. Android之SharedPreferences 存储复杂对象
  5. JavaScript日期格式化处理
  6. 【转】js日期时间函数
  7. Windows环境下配置thrift编译器(VS2015)
  8. ArcGIS API for Silverlight开发入门准备
  9. pku 1094(拓扑排序,多次拓扑)
  10. cas内外网同时访问_科普:CAS 和 ABA
  11. 多线程实战(二)线程同步
  12. Asp.net中Bind()和Eval()的区别
  13. 如何写一份优秀的java程序员简历
  14. jeecms系统使用介绍——通过二次开发实现对word、pdf、txt等上传附件的全文检索
  15. 如何将本地图片转换成链接
  16. jQuery第二章选择器
  17. Vue install 失败的一些解决办法
  18. 区块链+大数据:万物互联时代的“CP组合”
  19. Error:Skipped due to earlier error
  20. 揭开影响RS485通讯因素的面纱

热门文章

  1. 智慧矿山综合管控平台,实现井上井下一体化管理
  2. JS 三元运算符嵌套使用
  3. Maven - 编译报错Execution repackage of goal spring-boot-maven-plugin;Unable to find main class
  4. QT无人机地面站设计与制作随笔总结
  5. 线上线下融合 国美新零售全面升级用户消费体验
  6. 澳洲最大的华资快递公司ACE 签约动软微信商城系统!
  7. 【裂缝识别】无人机图像处理公路裂缝检测研究与实现【含Matlab源码 1730期】
  8. DIY你的QQ登陆器
  9. LeetCode-算法-岛屿的最大面积
  10. 佳能G3800彩色喷墨打印机报代码5B00维修