三、I2C客户端驱动 —— htu21d

前言

和bmp280一样,使用i2c驱动注册。需要注意的是,设备reset需要15ms,可以使用读出来的第三个字节作为CRC8校验码,进行数据校验。另外,温湿度计算公式如果使用小数,可能编译器默认的参数不支持,可以将小数转化为整数进行计算。

另外,htu21d的i2c支持两种模式,hold master模式支持SCL stretching,更加方便我们主机端读取数据,设备会在数据ADC采集完成之前,控制SCL,不让master继续后续操作,再数据完成采集后,再释放SCL,master才进行后续读取操作。另外一个模式,需要我们自己去轮询读取,指导读取到有ACK的字节,才算htu21d数据准备完毕。但是hold master有一个比较严重的问题,如果SCL stretching期间,htu21d掉电的话,master i2c bus会被占用,导致后续都没办法再继续操作了。

CRC-8

需要确定CRC使用的多项式,多项式的计算公式是依据每一项的指数排序,存在指数的项依次用1填充一个字节的一位,没有的项用0填充。比如下面的多项式:

x^8 + x^5 + x^4 + 1

那么x8 应该填充第8位,x5 应该填充第5位,依次类推,最后的+1,应该是 x0 ,最终得到的数是 100110001 ,这时得到一个9位数的值,因为只需要一个字节,因此去掉第8位,得到 00110001 (0x31)。

crc值会有一个默认初始值,htu21d要求的crc初始值是0。将crc值依次与数据的每个字节异或得到新的crc。在异或了一个字节得到新crc后,需要将当时的crc值向左移位,当最高位为1时,则将当前移位后的值与上述计算的多项式得到的值进行异或后赋给crc,如果最高位不为1,则将移位后的值赋给crc。一个字节8位都移位完成后,crc又与下一个字节异或,继续上面的操作,直到最后一个字节完成,就得到了最终的crc值。

/* x^8 + x^5 + x^4 + 1: 100110001 (00110001 -> 0x31) */
static u8 crc8_calcu(u8 *data, size_t len)
{
   
    /* init value for htu21d: 0x0 */
    u8 crc = 0x0;
    int i, j;

    for (i = 0; i < len; i++) {
   
        crc ^= data[i];
        for (j = 0; j < 8; j++) {
   
            crc = (crc & 0x80) ? ((crc << 1) ^ 0x31) : (crc << 1);
        }
    }
    return crc;
}

设备属性

在提供温湿度接口时,我们这里使用最简单的sysfs接口提供温湿度属性值,或者也可以使用字符设备驱动来完成。。一般温湿度传感器是使用iio子系统或者input子系统来提供用户接口。后续做到相应章节再实现iio和input子系统方式的接口。

总线,设备,驱动,类等内核对象都是拥有属性接口的。可以直接属性定义的宏,定义内核某个对象的属性借口,实现属性的读写功能。读属性为show,写属性为store。设备的属性接口使用以下宏进行定义:

#define DEVICE_ATTR(_name, _mode, _show, _store) \
	struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

static DEVICE_ATTR(temperature, 0644, bmp280_temperature_show,
                    bmp280_temperature_store);

定义属性的名字,sysfs文件节点的权限,读写方法。当属性只读或者只写时,建议不要使用这个接口,可能回到只系统报oops。比如我不支持写,那么我给store传参会是NULL。insmod的时候回报一堆错误警告及堆栈信息出来。
定义完成后,使用 device_create_file 函数创建文件节点。

只读或者只写使用以下宏:

#define DEVICE_ATTR_RO(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_WO(_name) \
	struct device_attribute dev_attr_##_name = __ATTR_WO(_name)

在用户空间,将生成 temperature 和 humidity 两个属性节点,权限只读。可以使用cat读取设备节点,将分别读取到传感器的温度数据和湿度数据。如果支持写权限的话,可以使用echo命令进行写入。这里两个节点是以字符串的格式进行输出的,如果属性节点是输出二进制数据的,可以使用xxd命令进行读取。

设备树配置

&i2c4 {
    status = "okay";

    htu21d: htu21d@40 {
        status = "okay";
        compatible = "se,htu21d";
        reg = <0x40>;
    };
};

这里使用驱动和设备的匹配方式使用设备树风格的方式,会和驱动中 of_device_id 列表中的 compatible 字段进行匹配。可以尝试修改设备树中的compatible属性,设备树风格匹配将失败,继而使用 i2c_device_id 方式进行匹配,这个时候 i2c_device_id 匹配将匹配设备节点的名称,即 "htu21d"

驱动代码

#include "asm-generic/errno-base.h"
#include "linux/device.h"
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>

struct htu21d_dev {
   
    struct i2c_client *client;

    s32 temperature;
    u32 humidity;
};

/* x^8 + x^5 + x^4 + 1: 100110001 (00110001 -> 0x31) */
static u8 crc8_calcu(u8 *data, size_t len)
{
   
    /* init value for htu21d: 0x0 */
    u8 crc = 0x0;
    int i, j;

    for (i 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值