扩展板心率/血氧传感器驱动移植

1.实验原理

打开扩展板原理图对照扩展板可以看到扩展板有 1 个心率 / 血氧传感器,如下图:

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

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

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

 2.实验步骤

1) 导入交叉编译工具链

linux@ubuntu:$ source /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/environm ent-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi

2) 内核配置

内核中提供了 max30102 的驱动,只要在内核中配置对应选项即可,驱动路径为:
drivers/iio/health/max30102.c
执行 make menuconfig 配置内核对应选项
linux@ubuntu:$ make menuconfig
Device Drivers --->
        <*> Industrial I/O support --->
                Health Sensors --->
                        Heart Rate Monitors --->
                                <*> MAX30102 heart rate and pulse oximeter sensor

3) 修改设备树

参考 linux 内核文档:
Documentation/devicetree/bindings/i2c/i2c-stm32.txt
Documentation/devicetree/bindings/iio/health/max30102.txt
修改设备树文件:
arch/arm/boot/dts/stm32mp157a-fsmp1a-extended.dts
由于 i2c1 相关内容上节已经做了添加,本节只需在原有基础添加与硬件对应的相关信息 即可,在文件 stm32mp157a-fsmp1a-extended.dts i2c1 节点添加 max30102 内容,红色字体部分为添加内容:
&i2c1 {
    ……
    ap3216c: ap3216c@1e {
        compatible = "liteon,ap3216c";
        reg = <0x1e>;
        interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
        interrupt-parent = <&gpiof>;
    };
    max30102: max30102@57 {
        compatible = "maxim,max30102";
        reg = <0x57>;
        maxim,red-led-current-microamp = <7000>;
        maxim,ir-led-current-microamp = <7000>;
        interrupt-parent = <&gpiob>;
        interrupts = <12 IRQ_TYPE_EDGE_FALLING >;
    };
};

4) 重新编译内核和设备树文件

linux@ubuntu:$ make -j4 uImage dtbs LOADADDR=0xC2000040

5) 更新系统内核和设备树

6) 测试

系统启动后可以查看目录 /sys/bus/iio/devices/
root@fsmp1a:~# ls /sys/bus/iio/devices/
iio:device0 iio:device1
如果系统中有多个 iio 设备,这里可能会有很多个 iio 设备目录,确定哪个目录是我们的设备对应目录,可以通过查看/sys/bus/iio/devices/iio:device*/name 信息确认
root@fsmp1a:~# cat /sys/bus/iio/devices/iio:device*/name
0-0040
ap3216c
max30102
由显示信息可以确认 iio:device2 是当前设备对应目录
max30102 /sys 目录下的内容如下:
root@fsmp1a:~# ls /sys/bus/iio/devices/iio\:device2/ -R
/sys/bus/iio/devices/iio:device2/:
buffer dev in_temp_raw in_temp_scale name of_node power
scan_elements subsystem uevent

/sys/bus/iio/devices/iio:device2/buffer:
data_available enable length watermark

/sys/bus/iio/devices/iio:device2/power:
autosuspend_delay_ms control runtime_active_time
runtime_status runtime_suspended_time

/sys/bus/iio/devices/iio:device2/scan_elements:
in_intensity_ir_en in_intensity_ir_type in_intensity_red_index
in_intensity_ir_index in_intensity_red_en in_intensity_red_type
上述文件多为 max30102 驱动提供的属性文件及使能文件,由于心率并不像前文环境光及接近传感器那样数据比较简单,并不能通过读取一个文件获得当前的心率或血氧,而是通过一系列的数据计算出来的,这样 sys 文件系统的接口就不能完全适用了,所以需要结合系统调用以字符设备的方式获取对应数据,然后在计算出心率和血氧。
关键文件说明:
/sys/bus/iio/devices/iio:device2/scan_elements/(in_intensity_ir_en/in_intensity_red_en):
通道使能,通过写 1 0 使能或关闭通道。
/sys/bus/iio/devices/iio:device2/scan_elements/(in_intensity_ir_type/in_intensity_red_type):
通道数据类型,读取格式为: be:u18/32>>8 be 表示数据为大端存储 (big endian) u 表示
数据为无符号数, 18/32>>8 表示 32 位数据左移 8 位后有效数据为 18 位。
/sys/bus/iio/devices/iio:device2/scan_elements/(in_intensity_ir_index/in_intensity_red_index):
读取数据为当前通道的序号, red 0 通道, ir 1 通道
/sys/bus/iio/devices/iio:device2/buffer/length
写入数据用来设置缓存区样本数量。
/sys/bus/iio/devices/iio:device2/buffer/enable
写入 1 0 用来使能设备采样或停止设备采样。

7) 编写测试程序

max30102_test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>

#define DATA_MASK ((1 << 18) - 1)
#define DATA_SHIFT 8

#define DATA_BUF_SIZE 400

char device_name[128];
unsigned int aun_red_buf[DATA_BUF_SIZE];
unsigned int aun_ir_buf[DATA_BUF_SIZE];

extern void maxim_heart_rate_and_oxygen_saturation(unsigned int *pun_ir_buffer ,
int n_ir_buffer_length, unsigned int *pun_red_buffer , int *pn_spo2,
int *pch_spo2_valid , int *pn_heart_rate , int *pch_hr_valid);

int write_sys_int(char *filename, int data)
{
    int ret = 0;
    FILE *filp;

    //printf("filename = %s\n", filename);

    filp = fopen(filename, "w");
    if (!filp) {
        ret = -errno;
        fprintf(stderr, "failed to open %s\n", filename);
        goto error;
    }

    ret = fprintf(filp, "%d", data);
    if (ret < 0) {
        if (fclose(filp))
            perror("_write_sysfs_int(): Failed to close dir");

        goto error;
    }

    if (fclose(filp)) {
        ret = -errno;
        goto error;
    }

    return 0;

error:
    return ret;
}

int enable_disable_all_channels(int enable)
{
    int ret = 0;
    char red_enable[128] = {0};
    char ir_enable[128] = {0};

                            
    sprintf(red_enable,"/sys/bus/iio/devices/%s/scan_elements/in_intensity_red_en",
    device_name);
    sprintf(ir_enable, "/sys/bus/iio/devices/%s/scan_elements/in_intensity_ir_en",
    device_name);

    ret = write_sys_int(red_enable, enable);
    if (ret < 0) {
        fprintf(stderr, "Failed to enable/disable %s", red_enable);
        return ret;
    }

    ret = write_sys_int(ir_enable, enable);
    if (ret < 0) {
        fprintf(stderr, "Failed to enable/disable %s", ir_enable);
        return ret;
    }

    return 0;
}

int enable_disable_buffer(int enable)
{
    int ret = 0;
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小徐的记事本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值