i2c接口常见于各种慢速ic,特别是传感器。本文以I2C的CO2 sensor为例,

如上可以看到该i2c设备的从机地址,最大通信速率以及通信时序。因只要读取co2值,因此只需关注读的时许即可。

i2c设备接到实际硬件上后可以通过i2ctool进行侦测硬件接线是否有误。


root@TinaLinux:/# i2cdetect -y -r 1       //查询接到i2c总线1的从设备,如下可以看到接了一个从机地址为0x41的设备,即准备驱动co2设备0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- 41 -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --root@TinaLinux:/# i2cdump -f -y 1 0x41   //把co2 设备的寄存器内容都dump出来0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 01 78 04 3f 10 ff 2f 3f 36 3f 01 3f 01 3f 00 3f    ?x???./?6?????.?
10: 00 3f 01 3f 00 3f 00 3f 00 3f 13 3f 00 3f 20 3f    .???.?.?.???.? ?
20: 78 3f 78 3f 78 3f 00 3f 3f 3f 10 3f 00 3f 00 3f    x?x?x?.?????.?.?
30: 7f 3f 7b 3f 04 3f 28 3f 28 3f 68 3f 68 3f 7b 3f    ??{???(?(?h?h?{?
40: 7b 3f 7f 3f 7c 3f 7b 3f 06 3f 00 3f 00 3f 00 3f    {???|?{???.?.?.?
50: 55 3f 01 3f 3f 3f 04 3f 3f 3f 00 3f 70 3f 3f 3f    U?????????.?p???
60: 00 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 00 3f    .?????????????.?
70: 3f 3f b2 3f 00 3f 03 3f 00 3f 00 3f 00 3f 7b 3f    ????.???.?.?.?{?
80: 7b 3f 04 3f 3f 3f 00 3f 00 3f 00 3f 3f 3f 3f 3f    {?????.?.?.?????
90: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
a0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
b0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
c0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
d0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
e0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
f0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
root@TinaLinux:/# i2cget -f -y 1 0x41 0x00   //读取寄存器00的值
0x01
root@TinaLinux:/# i2cget -f -y 1 0x41 0x02    //读取寄存器02的值
0x04
root@TinaLinux:/#

通过i2ctool确认可以识别到硬件上没问题后既可以开始进行驱动开发。

1、用户态驱动

即在用户层直接驱动iic从机,不需要涉及到编写内核驱动,好处是不用涉及到编译内核,只需要用户态驱动

//直接在用户态上通过read write 标准接口去读取
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <stdio.h>
#define CHIP "/dev/i2c-1"
#define CHIP_ADDR 0x41
int main()
{unsigned char rddata[4];unsigned char rdnofilterregaddr = 0x02;unsigned char rdfilterregaddr = 0x34;int co2ppm;printf("hello, this is i2c tester\n");int fd = open(CHIP, O_RDWR);if (fd < 0){printf("open "CHIP"failed\n");goto exit;}if (ioctl(fd, I2C_SLAVE_FORCE, CHIP_ADDR) < 0){   /* 璁剧疆鑺墖鍦板潃 */printf("oictl:set slave address failed\n");goto closelabel;}while(1){printf("write nofilteraddress return: %d\n",write(fd, &rdnofilterregaddr, 1)); if(read(fd, &rddata, 3)){printf("rawdata:%x %x %x\r\n",rddata[0],rddata[1],rddata[2]);co2ppm = rddata[0]*256 + rddata[1];printf("co2ppm:%d\n",co2ppm);}else{printf("noneread\n");}sleep(3);printf("write filteraddress return: %d\n",write(fd, &rdfilterregaddr, 1)); if(read(fd, &rddata, 2)){printf("rawdata:%x %x\r\n",rddata[0],rddata[1],rddata[2]);co2ppm = rddata[0]*256 + rddata[1];printf("co2ppmfilter:%d\n",co2ppm);}else{printf("noneread\n");}sleep(3);}closelabel:   close(fd);exit:return 0;
}
//编译用户态程序arm-openwrt-linux-gcc i2cuser.c//拷贝到板子上运行
root@TinaLinux:/# ./a.out
hello, this is i2c tester
write nofilteraddress return: 1
rawdata:3 a8 55
co2ppm:936
write filteraddress return: 1
rawdata:3 78
co2ppmfilter:888
write nofilteraddress return: 1
rawdata:3 9e 55
co2ppm:926
write filteraddress return: 1
rawdata:a 22
co2ppmfilter:2594
write nofilteraddress return: 1
rawdata:5 d1 55
co2ppm:1489
write filteraddress return: 1
rawdata:8 6
co2ppmfilter:2054

2、内核态驱动

编写设备树,依据平台设备驱动模型去编写sensor driver驱动。

设备树

&twi1 {clock-frequency = <100000>;//按co2 sensor支持的最大100khz填写pinctrl-0 = <&twi1_pins_a>;pinctrl-1 = <&twi1_pins_b>;pinctrl-names = "default", "sleep";status = "okay";co2lp3@41{   //co2子设备定义compatible = "co2lp3";//用于drive probereg = <0x41>;//设备地址};
};

驱动代码

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/mod_devicetable.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/property.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <linux/gpio/consumer.h>
#include <linux/uaccess.h>
#include <linux/fs.h>static int major = 0;
static struct class *lp3co2_class;
static struct i2c_client *lp3co2_client;static int lp3co2_read_regs( void *val, int len)
{int ret;struct i2c_msg msg;/* msg 为读取数据 */msg.addr = lp3co2_client->addr;msg.flags = I2C_M_RD;msg.buf = val;msg.len = len;ret = i2c_transfer(lp3co2_client->adapter, &msg, 1);if(ret == 1){ret = 0;}else{printk("i2c rd failed=%d len=%d \n",ret, len);ret = -EREMOTEIO;}return ret;
}static unsigned int lp3co2_write_regs( unsigned char reg, unsigned char*buf, unsigned char len)
{unsigned char *b;unsigned char i;struct i2c_msg msg;b = kzalloc(len+1,GFP_KERNEL);b[0] = reg;msg.addr = lp3co2_client->addr;//i;msg.flags = 0;//writemsg.buf = b;msg.len = len+1;return i2c_transfer(lp3co2_client->adapter, &msg, 1);
}static ssize_t lp3co2_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{int err;char kernel_buf[4];lp3co2_write_regs(0x02,NULL,0);lp3co2_read_regs(kernel_buf,2);lp3co2_write_regs(0x34,NULL,0);lp3co2_read_regs(&kernel_buf[2],2);err = copy_to_user(buf, kernel_buf, size);return size;
}static int lp3co2_open (struct inode *node, struct file *file)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}static struct file_operations lp3co2_ops = {.owner = THIS_MODULE,.open  = lp3co2_open,.read  = lp3co2_read,
};static const struct of_device_id of_match_ids_lp3co2[] = {{ .compatible = "co2lp3",       .data = NULL },{ /* END OF LIST */ },
};static const struct i2c_device_id lp3co2_ids[] = {{ "lp3co2",  (kernel_ulong_t)NULL },{ /* END OF LIST */ }
};static int lp3co2_probe(struct i2c_client *client, const struct i2c_device_id *id)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);lp3co2_client = client;/* register_chrdev */major = register_chrdev(0, "lp3co2", &lp3co2_ops);lp3co2_class = class_create(THIS_MODULE, "lp3co2_class");device_create(lp3co2_class, NULL, MKDEV(major, 0), NULL, "lp3co2"); /* /dev/lp3co2 */return 0;
}static int lp3co2_remove(struct i2c_client *client)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);device_destroy(lp3co2_class, MKDEV(major, 0));class_destroy(lp3co2_class);/* unregister_chrdev */unregister_chrdev(major, "lp3co2");return 0;
}static struct i2c_driver i2c_lp3co2_driver = {.driver = {.name = "co2lp3",.of_match_table = of_match_ids_lp3co2,},.probe = lp3co2_probe,.remove = lp3co2_remove,.id_table = lp3co2_ids,
};static int __init i2c_driver_lp3co2_init(void)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return i2c_add_driver(&i2c_lp3co2_driver);
}
module_init(i2c_driver_lp3co2_init);static void __exit i2c_driver_lp3co2_exit(void)
{i2c_del_driver(&i2c_lp3co2_driver);
}
module_exit(i2c_driver_lp3co2_exit);MODULE_AUTHOR("www.100ask.net");
MODULE_LICENSE("GPL");

应用层测试代码

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>int main(int argc, char **argv)
{int fd,ret;unsigned char databuf[4] = {0};int co2ppm;fd = open("/dev/lp3co2", O_RDWR);if (fd < 0){perror("open device lp3co2 error");}while (1){ret = read(fd, databuf, 4);printf("rawdata:%x %x %x %x\r\n",databuf[0],databuf[1],databuf[2],databuf[3]);co2ppm = databuf[0]*256 + databuf[1];printf("co2ppm:%d\n",co2ppm);co2ppm = databuf[2]*256 + databuf[3];printf("co2filterppm:%d\n",co2ppm);sleep(3);}return 0;
}

linux i2c既可以通过i2c硬件总线驱动,也可以通过模拟io驱动,模拟io驱动linux内核也有做好了对应的驱动,只要设备树按要求的定义后就可以直接使用。不需要自己像mcu级别额外去控制模拟scl和sda时序。

gpio模拟iic驱动需要内核开启相应配置

同时添加对应的设备树

 i2cgpio{compatible = "i2c-gpio";//必须为该名称才可以让内核的驱动识别到gpios = < &pio PB 6 0 /*sda*/&pio PB 7 0 /*scl*/>;i2c-gpio,delay-us = <30>;#address-cells = <1>;#size-cells = <0>;co2lp3@41{compatible = "co2lp3";reg = <0x41>;};};
root@TinaLinux:/# dmesg | grep i2c
[    2.361954] i2c /dev entries driver
[    3.059727] sunxi-i2c sunxi-i2c1: sunxi-i2c1 supply twi not found, using dummy regulator
[    3.069550] sunxi-i2c sunxi-i2c1: probe success
[    3.075112] sunxi-i2c sunxi-i2c2: sunxi-i2c2 supply twi not found, using dummy regulator
[    3.084907] sunxi-i2c sunxi-i2c2: probe success
[    3.091982] gpio-38 (i2cgpio): enforced open drain please flag it properly in DT/ACPI DSDT/board file
[    3.102457] gpio-39 (i2cgpio): enforced open drain please flag it properly in DT/ACPI DSDT/board file
[    3.113282] i2c-gpio i2cgpio: using lines 38 (SDA) and 39 (SCL)i2c-1   i2c             sunxi-i2c1                              I2C adapter
i2c-2   i2c             sunxi-i2c2                              I2C adapter
i2c-0   i2c             i2cgpio                                 I2C adapter//i2c-0即为模拟iic的adapterroot@TinaLinux:/# i2cdump -y -f 0
root@TinaLinux:/# i2cdetect -y -r 00  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- 41 -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
root@TinaLinux:/# i2cdump -y -f 0x41
root@TinaLinux:/# i2cdump -y -f 0 0x410  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 01 78 04 3f 10 ff 2f 3f 36 3f 01 3f 01 3f 00 3f    ?x???./?6?????.?
10: 00 3f 01 3f 00 3f 00 3f 00 3f 13 3f 00 3f 20 3f    .???.?.?.???.? ?
20: 78 3f 78 3f 78 3f 00 3f 3f 3f 10 3f 00 3f 00 3f    x?x?x?.?????.?.?
30: 7f 3f 7a 3f 05 3f 28 3f 28 3f 67 3f 67 3f 7a 3f    ??z???(?(?g?g?z?
40: 7a 3f 7f 3f 7b 3f 7a 3f 06 3f 00 3f 00 3f 00 3f    z???{?z???.?.?.?
50: 55 3f 01 3f 3f 3f 04 3f 3f 3f 00 3f 70 3f 3f 3f    U?????????.?p???
60: 00 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 00 3f    .?????????????.?
70: 3f 3f b2 3f 00 3f 03 3f 00 3f 00 3f 00 3f 7b 3f    ????.???.?.?.?{?
80: 7b 3f 05 3f 3f 3f 00 3f 00 3f 00 3f 3f 3f 3f 3f    {?????.?.?.?????
90: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
a0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
b0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
c0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
d0: 3f 3f 3f 3f 3f 3f 3f 3f XX 3f 3f 3f 3f 3f 3f 3f    ????????X???????
e0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
f0: 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f 3f    ????????????????
root@TinaLinux:/#

i2c更换成模拟io后内核会生成一个新的adapter,用户态驱动只需打开的设备文件名改为生成的i2c-0后就可以直接读取,

root@TinaLinux:/# ./a.out
hello, this is i2c tester
write nofilteraddress return: 1
rawdata:4 6a 55
co2ppm:1130
write filteraddress return: 1
rawdata:4 8e
co2ppmfilter:1166
write nofilteraddress return: 1
rawdata:4 62 55
co2ppm:1122

嵌入式Linux的两种I2C驱动方式相关推荐

  1. Linux上两种软件安装方式

    Day 8 安装包获取 安装包获取: 1.本地获取 2.网络获取 第一种安装方式 rpm 安装工具 (包名,软件名) .rpm 格式的安装包 eg:-r--r--r--r. 1996 root roo ...

  2. Android系统从驱动到上层服务再到应用的两种服务架构方式

    Android系统从驱动到上层服务再到应用的两种服务架构方式 1)使用类似sensor service的方式: 此方式用于,service的接口不想暴露给上层activity直接使用的情形 例如sen ...

  3. linux系统下编写I2C驱动

    I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL ,使用SCL,SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线. ...

  4. 南京邮电大学嵌入式系统开发实验5:嵌入式Linux下LED报警灯驱动设计及编程

    实验5  嵌入式Linux下LED报警灯驱动设计及编程 一.实验目的 理解驱动本质,掌握嵌入式Linux系统下驱动开发相关知识,包括端口寄存器访问.接口函数编写.和文件系统挂接.注册及相关应用编程等知 ...

  5. Pytorch两种模型保存方式

    以字典方式保存,更容易解析和可视化 Pytorch两种模型保存方式 大黑_7e1b关注 2019.02.12 17:49:35字数 13阅读 5,907 只保存模型参数 # 保存 torch.save ...

  6. 使用ubuntu16.04对NVIDIA Jetson Xavier NX使用刷机:两种刷机方式:SD卡镜像法 和 NVIDIA SDK Manager法

    文章目录: 1 NVIDIA Jetson Xavier NX的两种刷机方式 2 使用SD卡镜像法对Jetson Xavier NX刷机的具体步骤 3 使用NVIDIA SDK Manager法对Je ...

  7. 动态链接库dll的两种加载方式

    在第一篇技术博客"动态链接库简介"中说到了两种加载方式,当时没有详细说明,这里详细说明一下 可以通过两种方式 1.隐式链接(需要.dll,.lib,.h) 2.显式链接(需要.dl ...

  8. 启用物料账后,有两种物料价格确定方式

    启用ML后,有两种物料价格确定方式: 1.Cost Estimate 原材料和商品比较适合采用Cost Estimate,通过后台配置指定估价变式以确定未来标准价的获取 策略,如近期采购价,力求最接近 ...

  9. Spark _05Standalone模式两种提交任务方式

    Standalone模式两种提交任务方式 Standalone-client提交任务方式 提交命令 ./spark-submit --master spark://node1:7077 --class ...

最新文章

  1. (chap1 网络基础知识)网络的构成要素:(7)网关
  2. mediumtext和string转换_数据类型 - 字符串类型 - 《TiDB v3.0 用户文档》 - 书栈网 · BookStack...
  3. [C#]打包项目[转]
  4. P4719-[模板]动态DP【矩阵乘法,树链剖分,线段树】
  5. python内置函数返回序列中最大元素_Python之路(第八篇)Python内置函数、zip()、max()、min()...
  6. C#LeetCode刷题之#66-加一(Plus One)
  7. 百度、阿里等大厂面试技巧总结,Java工程师必看!
  8. 微软停止接受华为的新订单
  9. html资源文件放在哪里,09 Spring Boot开发web项目之静态资源放哪里?
  10. Maven系列--maven-compiler-plugin的使用、Maven之Surefire插件
  11. CMMI5 2.0版本是什么 做什么
  12. php 用户控件,一个使用用户控件(包括组件)的演示-.NET教程,组件控件开发
  13. cmd文件和bat文件的区别+一个的bat脚本+bat基础知识
  14. Ubuntu下通过命令打开图片
  15. tableau 集动作_举个栗子!Tableau技巧(59):学做两个集合的维恩图(文氏图)Venn diagram...
  16. 春节后第一周个人新闻两则
  17. DSPE-PEG4-Mal分子式:C56H103N2O15P的分子量介绍
  18. Android O 新特性和行为变更总结
  19. 千古以來:卍佛一心)悟道真机(转载)
  20. 外贸行业找客户的三种方式和五种工具

热门文章

  1. 算法 64式 7、搜索算法整理_第2部分_16到30题
  2. C++:实现量化GSR模型测试实例
  3. 金蝶KIS记账王增加3级明细科目的方法
  4. 过于执着其实没有什么好下场--《科学怪人之再生情缘》
  5. 人民日报强烈推荐的13本证书,含金量都很高!
  6. ffmpeg mp4转gif
  7. honeyselect身高补丁_honey select姿势mod最新补丁
  8. 让项目管理理论“落地”——读《IT项目经理成长手记》有感
  9. 多台路由器堆叠_关于多个无线网络叠加本人亲身经历!!最后成功了!!更新完毕!...
  10. opencv在电脑屏幕上画_opencv 用鼠标在窗口中画矩形