“扩展板空气温湿度传感器驱动移植”的版本间的差异

来自华清远见研发中心
跳转至: 导航搜索
实验原理
实验步骤
 
(未显示同一用户的2个中间版本)
第30行: 第30行:
  
 
==实验平台==
 
==实验平台==
 +
华清远见开发环境,FS-MP1A平台
 +
 
==实验步骤==
 
==实验步骤==
 +
<ol>
 +
<li>导入交叉编译工具链</li>
 +
linux@ubuntu:$ source /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
 +
 +
<li>内核配置</li>
 +
内核中没有SI7006的驱动,但是可以找到SI7020和SI7005的驱动,通过查阅资料及芯片手册对比,可以发现SI7020和SI7006兼容,所以使用SI7020的驱动即可。
 +
drivers/iio/humidity/si7020.c
 +
执行make menuconfig配置内核对应选项
 +
 +
<pre>
 +
linux@ubuntu:$ make menuconfig
 +
Device Drivers  --->
 +
<*> Industrial I/O support  --->
 +
Humidity sensors  --->
 +
<*> Si7013/20/21 Relative Humidity and Temperature Sensors
 +
</pre>
 +
<li>修改设备树</li>
 +
参考linux内核文档:
 +
Documentation/devicetree/bindings/i2c/i2c-stm32.txt
 +
修改设备树文件:
 +
arch/arm/boot/dts/stm32mp157a-fsmp1a-extended.dts
 +
由于i2c1在stm32mp151.dtsi中已完成定义,这里需要在原有基础添加与硬件对应的相关信息,在文件stm32mp157a-fsmp1a-extended.dts末尾集成并添加i2c1相关内容:
 +
 +
<pre>
 +
&i2c1 {
 +
pinctrl-names = "default", "sleep";
 +
pinctrl-0 = <&i2c1_pins_b>;
 +
pinctrl-1 = <&i2c1_pins_sleep_b>;
 +
i2c-scl-rising-time-ns = <100>;
 +
i2c-scl-falling-time-ns = <7>;
 +
status = "okay";
 +
/delete-property/dmas;
 +
/delete-property/dma-names;
 +
 +
si7020: si7020@40 {
 +
compatible = "silabs,si7020";
 +
reg = <0x40>;
 +
};
 +
};
 +
</pre>
 +
仿照设备树对于i2c管脚的配置添加i2c1管脚配置:
 +
 +
<pre>
 +
&pinctrl {
 +
i2c1_pins_b: i2c1-0 {
 +
pins {
 +
pinmux = <STM32_PINMUX('F', 14, AF5)>, /* I2C1_SCL */
 +
  <STM32_PINMUX('F', 15, AF5)>; /* I2C1_SDA */
 +
bias-disable;
 +
drive-open-drain;
 +
slew-rate = <0>;
 +
};
 +
};
 +
 +
i2c1_pins_sleep_b: i2c1-1 {
 +
pins {
 +
pinmux = <STM32_PINMUX('F', 14, ANALOG)>, /* I2C1_SCL */
 +
  <STM32_PINMUX('F', 15, ANALOG)>; /* I2C1_SDA */
 +
};
 +
};
 +
};
 +
 +
</pre>
 +
<li>重新编译内核和设备树文件</li>
 +
linux@ubuntu:$ make -j4 uImage dtbs LOADADDR=0xC2000040
 +
<li>更新系统内核和设备树</li>
 +
<li>测试</li>
 +
系统启动后可以查看目录/sys/bus/iio/devices/
 +
<pre>
 +
root@fsmp1a:~# ls /sys/bus/iio/devices/
 +
iio:device0
 +
</pre>
 +
如果系统中有多个iio设备,这里可能会有很多个iio目录,确定哪个目录是我们的设备对应目录,可以通过查看/sys/bus/iio/devices/iio\:device0/name信息确认:
 +
<pre>
 +
root@fsmp1a:~# cat /sys/bus/iio/devices/iio\:device0/name
 +
0-0040
 +
</pre>
 +
 +
由显示信息每个驱动对应设备可能有所不同,当前显示内容为设备的物理地址,与设备树中地址一致,可以确认iio:device0是当前设备对应目录
 +
查看当目录下内容:
 +
 +
<pre>
 +
root@fsmp1a:~# ls -l /sys/bus/iio/devices/iio\:device0/
 +
total 0
 +
-r--r--r-- 1 root root 4096 Feb  7 15:51 dev
 +
-rw-r--r-- 1 root root 4096 Feb  7 15:51 in_humidityrelative_offset
 +
-rw-r--r-- 1 root root 4096 Feb  7 15:51 in_humidityrelative_raw
 +
-rw-r--r-- 1 root root 4096 Feb  7 15:51 in_humidityrelative_scale
 +
-rw-r--r-- 1 root root 4096 Feb  7 15:51 in_temp_offset
 +
-rw-r--r-- 1 root root 4096 Feb  7 15:51 in_temp_raw
 +
-rw-r--r-- 1 root root 4096 Feb  7 15:51 in_temp_scale
 +
-r--r--r-- 1 root root 4096 Feb  7 15:51 name
 +
drwxr-xr-x 2 root root    0 Feb  7 15:51 power
 +
lrwxrwxrwx 1 root root    0 Feb  7 15:50 subsystem -> ../../../../../../../bus/iio
 +
-rw-r--r-- 1 root root 4096 Feb  7 15:50 uevent
 +
</pre>
 +
文件说明:<br>
 +
文件in_ temp_scale为温度标尺,计算公式如下,公式来自与驱动对应代码:
 +
 +
<center>[[Image:62-3-1.png]]</center><br>
 +
 +
<center>Scale<sub>temp</sub>=(175.72×1000×4)/65535=10.725097656</center>
 +
 +
in_ temp_offset为数据偏移,计算公式如下,公式来自于驱动对应代码:
 +
 +
<center>[[Image:62-3-2.png]]</center><br>
 +
 +
<center>offset<sub>temp</sub>=(-46.85×65536)/(4×175.72)=-4368</center>
 +
 +
in_ temp_raw为原始数据,计算公式如下,公式来自于驱动对应代码:
 +
 +
<center>[[Image:62-3-3.png]]</center><br>
 +
 +
<center>Raw<sub>temp</sub>=Code<sub>temp</sub>/4 </center>
 +
 +
阅读SI7006芯片手册可以看到温度的计算公式为:
 +
 +
<center>Temperature(℃)=(175.72×Code<sub>temp</sub>)/65535-46.85</center>
 +
 +
上述公式与驱动返回值看不出直接对应关系,所以我们按照驱动提供的scale、offset及Raw的计算公式对公式进行处理,得到最终公式计算过程如下:
 +
 +
<center>[[Image:62-3-4.png]]</center><br>
 +
 +
编写测试程序如下:
 +
 +
编写测试程序或参考:“光盘资料:华清远见-FS-MP1A开发资料\02-程序源码\06-资源扩展板测试程序\03-si7006_test”
 +
 +
Si7006_test.c
 +
<pre>
 +
#include <stdint.h>
 +
#include <string.h>
 +
#include <fcntl.h>
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <unistd.h>
 +
#include <errno.h>
 +
 +
int read_sysfs_float(const char *device, const char *filename, float *val)
 +
{
 +
    int ret = 0;
 +
    FILE  *sysfsfp;
 +
    char temp[128];
 +
 +
    memset(temp, '0', 128);
 +
 +
    ret = sprintf(temp, "/sys/bus/iio/devices/%s/%s", device, filename);
 +
    if (ret < 0)
 +
        goto error;
 +
 +
    sysfsfp = fopen(temp, "r");
 +
    if (!sysfsfp) {
 +
        ret = -errno;
 +
        goto error;
 +
    }
 +
 +
    errno = 0;
 +
    if (fscanf(sysfsfp, "%f\n", val) != 1) {
 +
        ret = errno ? -errno : -ENODATA;
 +
        if (fclose(sysfsfp))
 +
            perror("read_sysfs_float(): Failed to close dir");
 +
 +
        goto error;
 +
    }
 +
 +
    if (fclose(sysfsfp))
 +
        ret = -errno;
 +
 +
error:
 +
 +
    return ret;
 +
}
 +
 +
int read_sysfs_int(const char *device, const char *filename, int *val)
 +
{
 +
    int ret = 0;
 +
    FILE  *sysfsfp;
 +
    char temp[128];
 +
 +
    memset(temp, '0', 128);
 +
 +
    ret = sprintf(temp, "/sys/bus/iio/devices/%s/%s", device, filename);
 +
    if (ret < 0)
 +
        goto error;
 +
 +
    sysfsfp = fopen(temp, "r");
 +
    if (!sysfsfp) {
 +
        ret = -errno;
 +
        goto error;
 +
    }
 +
 +
    errno = 0;
 +
    if (fscanf(sysfsfp, "%d\n", val) != 1) {
 +
        ret = errno ? -errno : -ENODATA;
 +
        if (fclose(sysfsfp))
 +
            perror("read_sysfs_float(): Failed to close dir");
 +
 +
        goto error;
 +
    }
 +
 +
    if (fclose(sysfsfp))
 +
        ret = -errno;
 +
 +
error:
 +
 +
    return ret;
 +
}
 +
 +
 +
int main(int argc, char *argv[])
 +
{
 +
    int temp_raw = 0;
 +
    int temp_offset = 0;
 +
    float temp_scale = 0;
 +
 +
    int hum_raw = 0;
 +
    int hum_offset = 0;
 +
    float hum_scale = 0;
 +
 +
    while(1) {
 +
        /*read temp data*/
 +
        read_sysfs_int(argv[1], "in_temp_raw", &temp_raw);
 +
        read_sysfs_int(argv[1], "in_temp_offset", &temp_offset);
 +
        read_sysfs_float(argv[1], "in_temp_scale", &temp_scale);
 +
 +
        printf("temperature = %.2f\n", (temp_raw + temp_offset) * temp_scale / 1000);
 +
 +
        read_sysfs_int(argv[1], "in_humidityrelative_raw", &hum_raw);
 +
        read_sysfs_int(argv[1], "in_humidityrelative_offset", &hum_offset);
 +
        read_sysfs_float(argv[1], "in_humidityrelative_scale", &hum_scale);
 +
 +
        printf("humidity = %.2f%%\n", (hum_raw + hum_offset) * hum_scale / 1000);
 +
       
 +
        sleep(1);
 +
    }
 +
 +
    return 0;
 +
}
 +
 +
</pre>
 +
 +
编译测试程序拷贝背到系统中并执行,效果如下:
 +
 +
<pre>
 +
root@fsmp1a:~# ./si7006_test iio:device0
 +
temperature = 29.11
 +
humidity = 32.54%
 +
temperature = 29.13
 +
humidity = 32.55%
 +
temperature = 29.12
 +
humidity = 32.58%
 +
temperature = 29.11
 +
humidity = 32.59%
 +
temperature = 29.13
 +
humidity = 32.59%
 +
 +
</pre>
 +
</ol>

2021年3月24日 (三) 08:57的最新版本

实验原理

打开扩展板原理图对照扩展板可以看到扩展板有1个温湿度传感器SI7006,如下图:

62-1-1.png

由上图可见可通过I2C总线与SI7006通信。

62-1-2.png
扩展板与底板接口对照图

查看原理图可知数据线I2C1_SDA、I2C1_SCL和I2C_INT1管脚对应关系如下:

原理图网络编号 对应管脚 管脚功能 管脚功能码
I2C1_SCL PF14 I2C1_SCL AF5
I2C1_SDA PF15 I2C1_SDA AF5

查看SI7006芯片手册确认设备七位从机地址为:0x40

62-1-3.png

实验平台

华清远见开发环境,FS-MP1A平台

实验步骤

  1. 导入交叉编译工具链
  2. linux@ubuntu:$ source /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
    
  3. 内核配置
  4. 内核中没有SI7006的驱动,但是可以找到SI7020和SI7005的驱动,通过查阅资料及芯片手册对比,可以发现SI7020和SI7006兼容,所以使用SI7020的驱动即可。

    drivers/iio/humidity/si7020.c
    

    执行make menuconfig配置内核对应选项

    linux@ubuntu:$ make menuconfig 
    Device Drivers  --->
    	<*> Industrial I/O support  --->
    		Humidity sensors  --->
    			<*> Si7013/20/21 Relative Humidity and Temperature Sensors
    
  5. 修改设备树
  6. 参考linux内核文档:

    Documentation/devicetree/bindings/i2c/i2c-stm32.txt
    

    修改设备树文件:

    arch/arm/boot/dts/stm32mp157a-fsmp1a-extended.dts
    

    由于i2c1在stm32mp151.dtsi中已完成定义,这里需要在原有基础添加与硬件对应的相关信息,在文件stm32mp157a-fsmp1a-extended.dts末尾集成并添加i2c1相关内容:

    &i2c1 {
    	pinctrl-names = "default", "sleep";
    	pinctrl-0 = <&i2c1_pins_b>;
    	pinctrl-1 = <&i2c1_pins_sleep_b>;
    	i2c-scl-rising-time-ns = <100>;
    	i2c-scl-falling-time-ns = <7>;
    	status = "okay";
    	/delete-property/dmas;
    	/delete-property/dma-names;
    
    	si7020: si7020@40 {
    		compatible = "silabs,si7020";
    		reg = <0x40>;
    	};
    };
    

    仿照设备树对于i2c管脚的配置添加i2c1管脚配置:

    &pinctrl {
    	i2c1_pins_b: i2c1-0 {
    		pins {
    			pinmux = <STM32_PINMUX('F', 14, AF5)>, /* I2C1_SCL */
    					   <STM32_PINMUX('F', 15, AF5)>; /* I2C1_SDA */
    			bias-disable;
    			drive-open-drain;
    			slew-rate = <0>;
    		};
    	};
    
    	i2c1_pins_sleep_b: i2c1-1 {
    		pins {
    			pinmux = <STM32_PINMUX('F', 14, ANALOG)>, /* I2C1_SCL */
    					   <STM32_PINMUX('F', 15, ANALOG)>; /* I2C1_SDA */
    		};
    	};
    };
    
    
  7. 重新编译内核和设备树文件
  8. linux@ubuntu:$ make -j4 uImage dtbs LOADADDR=0xC2000040
    
  9. 更新系统内核和设备树
  10. 测试
  11. 系统启动后可以查看目录/sys/bus/iio/devices/

    root@fsmp1a:~# ls /sys/bus/iio/devices/
    iio:device0
    

    如果系统中有多个iio设备,这里可能会有很多个iio目录,确定哪个目录是我们的设备对应目录,可以通过查看/sys/bus/iio/devices/iio\:device0/name信息确认:

    root@fsmp1a:~# cat /sys/bus/iio/devices/iio\:device0/name 
    0-0040
    

    由显示信息每个驱动对应设备可能有所不同,当前显示内容为设备的物理地址,与设备树中地址一致,可以确认iio:device0是当前设备对应目录 查看当目录下内容:

    root@fsmp1a:~# ls -l /sys/bus/iio/devices/iio\:device0/
    total 0
    -r--r--r-- 1 root root 4096 Feb  7 15:51 dev
    -rw-r--r-- 1 root root 4096 Feb  7 15:51 in_humidityrelative_offset
    -rw-r--r-- 1 root root 4096 Feb  7 15:51 in_humidityrelative_raw
    -rw-r--r-- 1 root root 4096 Feb  7 15:51 in_humidityrelative_scale
    -rw-r--r-- 1 root root 4096 Feb  7 15:51 in_temp_offset
    -rw-r--r-- 1 root root 4096 Feb  7 15:51 in_temp_raw
    -rw-r--r-- 1 root root 4096 Feb  7 15:51 in_temp_scale
    -r--r--r-- 1 root root 4096 Feb  7 15:51 name
    drwxr-xr-x 2 root root    0 Feb  7 15:51 power
    lrwxrwxrwx 1 root root    0 Feb  7 15:50 subsystem -> ../../../../../../../bus/iio
    -rw-r--r-- 1 root root 4096 Feb  7 15:50 uevent
    

    文件说明:
    文件in_ temp_scale为温度标尺,计算公式如下,公式来自与驱动对应代码:

    62-3-1.png

    Scaletemp=(175.72×1000×4)/65535=10.725097656

    in_ temp_offset为数据偏移,计算公式如下,公式来自于驱动对应代码:

    62-3-2.png

    offsettemp=(-46.85×65536)/(4×175.72)=-4368

    in_ temp_raw为原始数据,计算公式如下,公式来自于驱动对应代码:

    62-3-3.png

    Rawtemp=Codetemp/4

    阅读SI7006芯片手册可以看到温度的计算公式为:

    Temperature(℃)=(175.72×Codetemp)/65535-46.85

    上述公式与驱动返回值看不出直接对应关系,所以我们按照驱动提供的scale、offset及Raw的计算公式对公式进行处理,得到最终公式计算过程如下:

    62-3-4.png

    编写测试程序如下:

    编写测试程序或参考:“光盘资料:华清远见-FS-MP1A开发资料\02-程序源码\06-资源扩展板测试程序\03-si7006_test”

    Si7006_test.c

    #include <stdint.h>
    #include <string.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    
    int read_sysfs_float(const char *device, const char *filename, float *val)
    {
        int ret = 0;
        FILE  *sysfsfp;
        char temp[128]; 
    
        memset(temp, '0', 128);
    
        ret = sprintf(temp, "/sys/bus/iio/devices/%s/%s", device, filename);
        if (ret < 0)
            goto error;
    
        sysfsfp = fopen(temp, "r");
        if (!sysfsfp) {
            ret = -errno;
            goto error;
        }
    
        errno = 0;
        if (fscanf(sysfsfp, "%f\n", val) != 1) {
            ret = errno ? -errno : -ENODATA;
            if (fclose(sysfsfp))
                perror("read_sysfs_float(): Failed to close dir");
    
            goto error;
        }
    
        if (fclose(sysfsfp))
            ret = -errno;
    
    error:
    
        return ret;
    }
    
    int read_sysfs_int(const char *device, const char *filename, int *val)
    {
        int ret = 0;
        FILE  *sysfsfp;
        char temp[128]; 
    
        memset(temp, '0', 128);
    
        ret = sprintf(temp, "/sys/bus/iio/devices/%s/%s", device, filename);
        if (ret < 0)
            goto error;
    
        sysfsfp = fopen(temp, "r");
        if (!sysfsfp) {
            ret = -errno;
            goto error;
        }
    
        errno = 0;
        if (fscanf(sysfsfp, "%d\n", val) != 1) {
            ret = errno ? -errno : -ENODATA;
            if (fclose(sysfsfp))
                perror("read_sysfs_float(): Failed to close dir");
    
            goto error;
        }
    
        if (fclose(sysfsfp))
            ret = -errno;
    
    error:
    
        return ret;
    }
    
    
    int main(int argc, char *argv[])
    {
        int temp_raw = 0;
        int temp_offset = 0;
        float temp_scale = 0;
    
        int hum_raw = 0;
        int hum_offset = 0;
        float hum_scale = 0;
    
        while(1) {
            /*read temp data*/
            read_sysfs_int(argv[1], "in_temp_raw", &temp_raw);
            read_sysfs_int(argv[1], "in_temp_offset", &temp_offset);
            read_sysfs_float(argv[1], "in_temp_scale", &temp_scale);
    
            printf("temperature = %.2f\n", (temp_raw + temp_offset) * temp_scale / 1000);
    
            read_sysfs_int(argv[1], "in_humidityrelative_raw", &hum_raw);
            read_sysfs_int(argv[1], "in_humidityrelative_offset", &hum_offset);
            read_sysfs_float(argv[1], "in_humidityrelative_scale", &hum_scale);
    
            printf("humidity = %.2f%%\n", (hum_raw + hum_offset) * hum_scale / 1000);
            
            sleep(1);
        }
    
        return 0;
    }
    
    

    编译测试程序拷贝背到系统中并执行,效果如下:

    root@fsmp1a:~# ./si7006_test iio:device0
    temperature = 29.11
    humidity = 32.54%
    temperature = 29.13
    humidity = 32.55%
    temperature = 29.12
    humidity = 32.58%
    temperature = 29.11
    humidity = 32.59%
    temperature = 29.13
    humidity = 32.59%