exynos4412之I2C client---sht3x-div

linux kernel version:4.4.38

hardware version:exynos4412-tiny4412 1312B, Sht3x sensor

最近在学习IIC UART SPI,就捡了一个软的IIC先捏了~

在TB买了sht3x sensor,店家有提供datasheet和PCB

I2C client还是比较简单的,我所使用的kernel已经支持了I2C adapter, 只要硬件管脚接对,将I2C client的DTS放置到对应的adapter下,就ok了~

下面记录一下我调试过程中遇到的坑~

首先,我看tiny4412的PCB,发现CON15上有I2C channel 5引出,那我就简单点,直接拿来用,发现sensor不能运行,一度怀疑,店家的东西是坏的,为了验证自己的判断,还特意去公司其他部门借了一台示波器抓波形(这个也是临时学的,之前只会使用傻瓜按键autoset)

 

 

抓不到波形,因为是临时学的使用示波器,不自信又怀疑操作不对,但是幸运的是,tiny4412上带了一块好的mma7660,于是抓mma7660的波形,发现抓的波形ok~

继续找问题,去看exynos4412的datasheet, PCB和linux kernel的DTS

1.PCB显示I2C channel 5的SCL和SDA是接在GPB_6和GPB_7

2.但是datasheet显示GPB_6和GPB_7并没有I2C的选项

3.原理图和datasheet对不上???

4.决定放弃I2C channel 5

5.既然I2C的channel 3是ok的,那我看下有没有开发板是否有引出

6.很幸运,有引出在con3,于是使用四根杜邦线连接好。进行下一步测试~

 

 7.以为后面会一切顺利,结果发现NO,使用i2cdetect等i2c-tools调试工具进行调试,甚至还抓波形,发现没有ACK信号,说明IIC adapter是ok的,再度怀疑商家产品是坏的???

8.这可咋办呀!!!接下来就进入了盲猜阶段

9.去量了一下MMA7660的电源电压,发现是3.3V,但是我的sht3x供电是接到CON3上的5V的

10.来一波盲猜换供电引脚(Wide supply voltage range, from 2.4 V to 5.5 V)虽然sht3x说明供电在2.4V~~~5.5V,但是我也不知道咋想的就瞎换。

11.哎,好了,i2cdetect -r -y 3可以发现了

 

 12.此时算是完成了一半了,只需要写程序和DTS就好了

上代码~~~

 1 &i2c_3 {
 2     samsung,i2c-sda-delay = <100>;
 3     samsung,i2c-max-bus-freq = <200000>;
 4     status = "okay";
 5 
 6     mma7660: mma7660@4c {
 7         compatible = "fsl,mma7660";
 8         reg = <0x4c>;
 9         interrupt-parent = <&gpx3>;
10         interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
11         poll_interval = <100>;
12         input_fuzz = <4>;
13         input_flat = <4>;
14         status = "disabled";
15     };
16 
17     sht3xdis: sht3xdis@44 {
18         compatible = "ethan,sht3xdis";
19         reg = <0x44>;
20         poll_interval = <100>;
21         input_fuzz = <4>;
22         input_flat = <4>;
23         status = "okay";
24     };
25 };

首先是DTS的部分,在i2c_3的node下,直接将mma7660的dts复制一份,按照格式修改

其中compatible是需要和驱动程序匹配的,reg即为client address

sht3x还有终端引脚,目前还没实现,后续补上~

  1 #include <linux/kernel.h>
  2 #include <linux/module.h>
  3 #include <linux/slab.h>
  4 #include <linux/interrupt.h>
  5 #include <linux/irq.h>
  6 #include <linux/delay.h>
  7 #include <linux/i2c.h>
  8 #include <linux/input-polldev.h>
  9 #include <linux/hwmon.h>
 10 #include <linux/hwmon-sysfs.h>
 11 #include <linux/of.h>
 12 #include <linux/of_device.h>
 13 
 14 #define DEBUG 1
 15 
 16 #define sht3x_NAME        "sht3x"
 17 static struct i2c_client    *sht3x_client;
 18 
 19 
 20 #ifdef CONFIG_OF
 21 static const struct of_device_id sht3x_dt_ids[] = {
 22     { .compatible = "ethan,sht3xdis", },
 23     { /* sentinel */ }
 24 };
 25 MODULE_DEVICE_TABLE(of, sht3x_dt_ids);
 26 #endif
 27 
 28 static int sht3x_soft_reset(struct i2c_client *client)
 29 {
 30     int ret = -1;
 31     char data[2] = {0x30, 0xa2};
 32     ret = i2c_master_send(client, data, sizeof(data));
 33     if(ret != 2)
 34         printk(KERN_INFO "sht3x_soft_reset fail.\n");
 35     return ret;
 36 }
 37 
 38 static int sht3x_read_temperature_and_humidity(struct i2c_client *client, unsigned short *temperature, unsigned short *humidity)
 39 {
 40     int ret = -1;
 41     char value[6];
 42     char data[2] = {0x2c, 0x06};
 43 
 44 
 45     ret = i2c_master_send(client, data, sizeof(data));
 46     if(ret == sizeof(data)){
 47         memset(value, 0, sizeof(value));
 48         ret = i2c_master_recv(client, value, sizeof(value));
 49         if(ret <= 0){
 50             return -1;
 51         }
 52         else{
 53             #if 0
 54             for(i = 0; i < sizeof(value); i++){
 55                 printk(KERN_INFO "value[%d] = 0x%x\n", i, value[i]);
 56             }
 57             #endif
 58         }
 59 
 60 
 61     }
 62 
 63     if(temperature != NULL){
 64         *temperature = (value[0]<<8)|value[1];
 65         
 66     }
 67 
 68     if(humidity != NULL){
 69         *humidity = (value[3]<<8)|value[4];
 70     }
 71 
 72     return ret;
 73     
 74 }
 75 
 76 static ssize_t sht3x_show_temperature(struct device *dev,
 77         struct device_attribute *attr, char *buf)
 78 {
 79     unsigned short val = 0;
 80     sht3x_read_temperature_and_humidity(sht3x_client, &val, NULL);
 81     return sprintf(buf, "%d\n", val);
 82 }
 83 
 84 static ssize_t sht3x_show_humidity(struct device *dev,
 85         struct device_attribute *attr, char *buf)
 86 {
 87     unsigned short val = 0;
 88     sht3x_read_temperature_and_humidity(sht3x_client, NULL,  &val);
 89     return sprintf(buf, "%d\n", val);
 90 }
 91 
 92 static SENSOR_DEVICE_ATTR(temperature, S_IRUGO, sht3x_show_temperature, NULL, 0);
 93 static SENSOR_DEVICE_ATTR(humidity, S_IRUGO, sht3x_show_humidity, NULL, 0);
 94 static struct attribute* sht3x_attrs[] = {
 95     &sensor_dev_attr_temperature.dev_attr.attr,
 96     &sensor_dev_attr_humidity.dev_attr.attr,
 97     NULL
 98 };
 99 
100 static const struct attribute_group sht3x_group = {
101     .attrs        = sht3x_attrs,
102 };
103 
104 static int sht3x_probe(struct i2c_client *client,
105         const struct i2c_device_id *id)
106 {
107     int ret;
108 
109     sht3x_client = client;
110     sht3x_soft_reset(client);
111     ret = sysfs_create_group(&client->dev.kobj, &sht3x_group);
112     if (ret) {
113         dev_err(&client->dev, "create sysfs group failed!\n");
114     }
115     printk(KERN_INFO "sht3x_probe success.\n");
116     return 0;
117 }
118 static int sht3x_remove(struct i2c_client *client)
119 {
120     sysfs_remove_group(&client->dev.kobj, &sht3x_group);
121     printk(KERN_INFO "sht3x_remove success.\n");
122     return 0;
123 }
124 
125 static const struct i2c_device_id sht3x_ids[] = {
126     { "sht3x", 0 },
127     { },
128 };
129 MODULE_DEVICE_TABLE(i2c, sht3x_ids);
130 
131 static struct i2c_driver i2c_sht3x_driver = {
132     .driver        = {
133         .name    = sht3x_NAME,
134 #ifdef CONFIG_OF
135         .of_match_table = sht3x_dt_ids,
136 #endif
137     },
138 
139     .probe        = sht3x_probe,
140     .remove        = sht3x_remove,
141     .id_table    = sht3x_ids,
142 };
143 
144 static int __init init_sht3x(void)
145 {
146     int ret;
147     ret = i2c_add_driver(&i2c_sht3x_driver);
148     printk(KERN_INFO "sht3x sensor driver registered.\n");
149     return ret;
150 }
151 
152 static void __exit exit_sht3x(void)
153 {
154     i2c_del_driver(&i2c_sht3x_driver);
155     printk(KERN_INFO "sht3x sensor driver removed.\n");
156 }
157 
158 module_init(init_sht3x);
159 module_exit(exit_sht3x);
160 
161 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
162 MODULE_DESCRIPTION("sht3x sensor driver");
163 MODULE_LICENSE("GPL");

主要实现了温度和湿度的获取,在sysfs注册了两个文件,temperature和humidity,但是exynos4412不支持浮点运算,所以只能先获取原始数据在应用层在计算转换成温湿度~

 

驱动程序主要实现了两个函数,reset和read,驱动初始化的时候reset sensor,每次打开temperature和humidity文件时执行read函数,0x2c06表示高重复度一次性读取数据~

应用层程序读取temperature文件,然后按照公式计算温湿度就ok了~

 

 第一次是正常测试,后面一次对着sensor哈一口气测试,数值有变化~

 

posted @ 2021-07-12 13:43  王东力  阅读(424)  评论(0)    收藏  举报