扩展板空气温湿度传感器驱动移植
实验原理
打开扩展板原理图对照扩展板可以看到扩展板有1个温湿度传感器SI7006,如下图:

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

查看原理图可知数据线I2C1_SDA、I2C1_SCL和I2C_INT1管脚对应关系如下:
| 原理图网络编号 | 对应管脚 | 管脚功能 | 管脚功能码 |
|---|---|---|---|
| I2C1_SCL | PF14 | I2C1_SCL | AF5 |
| I2C1_SDA | PF15 | I2C1_SDA | AF5 |
查看SI7006芯片手册确认设备七位从机地址为:0x40

实验平台
华清远见开发环境,FS-MP1A平台
实验步骤
- 导入交叉编译工具链
- 内核配置
- 修改设备树
- 重新编译内核和设备树文件
- 更新系统内核和设备树
- 测试
linux@ubuntu:$ source /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
内核中没有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
参考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 */
};
};
};
linux@ubuntu:$ make -j4 uImage dtbs LOADADDR=0xC2000040
系统启动后可以查看目录/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为温度标尺,计算公式如下,公式来自与驱动对应代码:

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

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

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

编写测试程序如下:
编写测试程序或参考:“光盘资料:华清远见-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%