首页 > 系统相关 >linux 使用iio 通过I2C 方式采集实例

linux 使用iio 通过I2C 方式采集实例

时间:2024-08-11 14:55:49浏览次数:18  
标签:i2c struct data dev linux iio I2C my

IIO (Industrial I/O)子系统通过I2C方式采集数据的实例。这个例子包括驱动程序和用户空间应用程序。

首先,让我们创建一个简单的IIO驱动程序,它通过I2C接口与ADC (模数转换器) 通信,并通过PCI总线连接到系统。

1. 驱动程序 (my_iio_driver.c):

```c
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>

#define DRIVER_NAME "my_iio_driver"
#define I2C_ADC_ADDR 0x48  // 假设ADC的I2C地址是0x48

struct my_iio_data {
    struct pci_dev *pdev;
    struct i2c_client *i2c;
    struct iio_dev *indio_dev;
};

static int my_iio_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
                           int *val, int *val2, long mask)
{
    struct my_iio_data *data = iio_priv(indio_dev);
    int ret;
    u16 raw_val;

    switch (mask) {
    case IIO_CHAN_INFO_RAW:
        ret = i2c_smbus_read_word_data(data->i2c, 0);
        if (ret < 0)
            return ret;
        raw_val = ret;
        *val = raw_val & 0xFFF;  // 假设ADC是12位
        return IIO_VAL_INT;
    default:
        return -EINVAL;
    }
}

static const struct iio_info my_iio_info = {
    .read_raw = my_iio_read_raw,
};

static const struct iio_chan_spec my_iio_channels[] = {
    {
        .type = IIO_VOLTAGE,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
    },
};

static int my_iio_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
    struct my_iio_data *data;
    struct i2c_adapter *i2c_adapter;
    struct i2c_board_info i2c_info = {
        I2C_BOARD_INFO("my_adc", I2C_ADC_ADDR),
    };
    int ret;

    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;

    data->pdev = pdev;

    ret = pcim_enable_device(pdev);
    if (ret) {
        dev_err(&pdev->dev, "Failed to enable PCI device\n");
        return ret;
    }

    // 假设I2C控制器在BAR 0
    i2c_adapter = i2c_get_adapter(0);  // 使用适当的I2C适配器号
    if (!i2c_adapter) {
        dev_err(&pdev->dev, "Failed to get I2C adapter\n");
        return -ENODEV;
    }

    data->i2c = i2c_new_client_device(i2c_adapter, &i2c_info);
    if (IS_ERR(data->i2c)) {
        dev_err(&pdev->dev, "Failed to create I2C client\n");
        return PTR_ERR(data->i2c);
    }

    data->indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
    if (!data->indio_dev) {
        ret = -ENOMEM;
        goto err_remove_i2c;
    }

    data->indio_dev->name = DRIVER_NAME;
    data->indio_dev->dev.parent = &pdev->dev;
    data->indio_dev->info = &my_iio_info;
    data->indio_dev->modes = INDIO_DIRECT_MODE;
    data->indio_dev->channels = my_iio_channels;
    data->indio_dev->num_channels = ARRAY_SIZE(my_iio_channels);

    ret = devm_iio_device_register(&pdev->dev, data->indio_dev);
    if (ret) {
        dev_err(&pdev->dev, "Failed to register IIO device\n");
        goto err_remove_i2c;
    }

    pci_set_drvdata(pdev, data);

    return 0;

err_remove_i2c:
    i2c_unregister_device(data->i2c);
    return ret;
}

static void my_iio_remove(struct pci_dev *pdev)
{
    struct my_iio_data *data = pci_get_drvdata(pdev);
    i2c_unregister_device(data->i2c);
}

static struct pci_device_id my_iio_ids[] = {
    { PCI_DEVICE(0x1234, 0x5678) },  // 替换为实际的 Vendor ID 和 Device ID
    { 0, }
};
MODULE_DEVICE_TABLE(pci, my_iio_ids);

static struct pci_driver my_iio_driver = {
    .name = DRIVER_NAME,
    .id_table = my_iio_ids,
    .probe = my_iio_probe,
    .remove = my_iio_remove,
};

module_pci_driver(my_iio_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("IIO driver for ADC over I2C and PCI");
```

2. 用户空间应用程序 (iio_read_app.c):

```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define IIO_DEVICE "/sys/bus/iio/devices/iio:device0"

int main()
{
    char filename[256];
    char buf[16];
    int fd, ret;
    unsigned long raw_value;

    // 构建原始数据文件的路径
    snprintf(filename, sizeof(filename), "%s/in_voltage_raw", IIO_DEVICE);

    // 打开文件
    fd = open(filename, O_RDONLY);
    if (fd < 0) {
        fprintf(stderr, "Failed to open %s: %s\n", filename, strerror(errno));
        return -1;
    }

    // 读取原始值
    ret = read(fd, buf, sizeof(buf));
    if (ret < 0) {
        fprintf(stderr, "Failed to read from %s: %s\n", filename, strerror(errno));
        close(fd);
        return -1;
    }

    // 关闭文件
    close(fd);

    // 将读取的字符串转换为整数
    raw_value = strtoul(buf, NULL, 10);

    // 打印结果
    printf("Raw ADC value: %lu\n", raw_value);

    return 0;
}
```

使用说明:

1. 编译并加载驱动程序:
   ```
   make -C /lib/modules/$(uname -r)/build M=$PWD modules
   sudo insmod my_iio_driver.ko
   ```

2. 编译用户空间应用程序:
   ```
   gcc -o iio_read_app iio_read_app.c
   ```

3. 运行应用程序:
   ```
   ./iio_read_app
   ```

这个例子展示了如何创建一个基于IIO的驱动程序,它通过PCI总线连接到系统,并使用I2C与ADC通信。用户空间应用程序通过sysfs接口读取ADC的原始值。

请注意,这个例子是一个简化的演示。在实际应用中,你可能需要:

1. 根据实际的ADC型号调整I2C通信协议。
2. 添加更多的IIO通道和属性。
3. 实现缓冲模式以支持连续采样。
4. 添加触发支持以实现定时或外部触发采样。
5. 根据实际的PCI设备和I2C控制器调整驱动程序。

此外,你可能还需要考虑电压转换、校准等更高级的功能,以将原始ADC值转换为实际的电压值。
 

标签:i2c,struct,data,dev,linux,iio,I2C,my
From: https://blog.csdn.net/zhangyihu321/article/details/141085646

相关文章

  • Linux C++ 多线程编程
    LinuxC++多线程编程参考教程:c++:互斥锁/多线程的创建和unique_lock<mutex>的使用_mutex头文件vc++-CSDN博客1.编写unique_mutex1.1创建文件夹通过终端创建一个名为unique_mutex的文件夹以保存我们的VSCode项目,在/unique_mutex目录下打开vscode。rosnoetic@rosnoetic-Virt......
  • Linux常用命令(图文并茂+超详细!)
    ......
  • Linux5:Shell编程——函数、重定向
    目录前言一、函数1.函数结构2.函数实例3.函数传参二、重定向1.输出重定向2.输入重定向3.同时使用4.重定向深入了解 5.垃圾桶总结前言    Shell编程将会在本章完结 一、函数1.函数结构#!/bin/sh#函数functionfun1(){echo"thisisaf......
  • Linux源码下载渠道是什么
    Linux源码可以从多个渠道下载,以下是几个主要的下载途径:1.Linux官方网站官方网站地址:https://www.kernel.org/在Linux官方网站上,你可以找到最新版本的Linux内核源码包以及之前版本的源码包。网站主页通常会显示最新版本的Linux内核,点击该版本号即可进入下载页面。在下载页面上,......
  • linux系统CENTOS 7安装docker
    前言:使用阿里云镜像,在CENTOS7版本上安装docker容器,方便使用docker容器安装其他软件。前置准备如果已经安装了docker,先将其卸载。yumremovedocker安装docker安装docker依赖的软件包。sudoyuminstall-yyum-utilsdevice-mapper-persistent-datalvm2添加阿里......
  • Linux基于Redis实现短地址服务
    一、应用场景为什么要使用短地址服务,具体使用的业务场景如下:URL压缩,把原始长地址压缩成短地址,便于文本长度限制的场景使用(短信、社交网络、网络营销)    —营销短信有字数限制,链接太长会影响短信内容的条数(涉及到费用问题)。    — 相对于长链接,短链接更......
  • Linux:@2024-08-10 最新的Openssl-3.3.1 Openssh-9.8p1 Centos7上的编译后二进制 一键
     附件:Portable_Openssl-Openssh9.8p1-bin-el7.v1.2.1.tgz.zip特点:适用于centos7.x 已经编译为二进制对老版本的关键二进制文件sshd、sftp、scp、openssl进行了备份升级前,自动打开一个端口为2222的老版本的sshd服务,你可以连接那个2222的服务,以防死翘翘。对sshd_config进......
  • Linux发行版软件包数量
    软件包数量很客观,质量上很主观。ArchLinux软件包数量第一,并且软件安装上最全面,原因如下:还有一个重要的ArchLinuxCN仓库非常非常实用,举两个例子clash-verge和deadbeef,前面是最常用,后面是很少见但是很好。这个软件包数量第一基本上没有异议,而Aur只需要简单的代理就行,有人帮你......
  • Linux调试器-gdb的使用
    文章目录Linux调试器-gdb的使用背景使用Linux调试器-gdb的使用背景程序的发布方式有两种,debug模式和release模式Linuxgcc/g++出来的二进制文件,默认是release模式要想使用gdb调试,必须在将源程序生成二进制程序的时候加上-g使用q,ctrl+d:退出调试list/l行号......
  • 提高效率:Linux 正则表达式实用技巧
    目录前言匹配符号用法讲解“.”用法[]用法“*”用法“.*”用法“\?”用法“\+”用法“\\{n\\}”用法\\{m,n\\}用法锚点符号“^”用法“$”用法“^$”用法或|用法前言在Linux系统中,正则表达式(RegularExpressions,简称regex)是一个强大的工具,广泛应......