I2C_SLAVE ioctl目的 [英] I2C_SLAVE ioctl purpose

查看:155
本文介绍了I2C_SLAVE ioctl目的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写用于使用常规linux i2c驱动程序linux/i2c-dev.h

I am writing code for implementing a simple i2c read/write function using the general linux i2c driver linux/i2c-dev.h

我对ioctl感到困惑:I2C_SLAVE

内核文档说明如下:

您可以通过使用read(2)和write(2)调用来进行普通的i2c事务. 您不需要传递地址字节.相反,将其设置为 尝试访问设备之前,请先使用ioctl I2C_SLAVE

You can do plain i2c transactions by using read(2) and write(2) calls. You do not need to pass the address byte; instead, set it through ioctl I2C_SLAVE before you try to access the device

但是我正在使用ioctl I2C_RDWR,在该位置我再次使用i2c_msg.addr设置从站地址.

However I am using the ioctl I2C_RDWR where I again set the slave address using i2c_msg.addr.

内核文档还提到了以下内容:

The kernel documentation also mentions the following :

某些ioctl()调用用于管理任务,并由以下方法处理 直接使用i2c-dev.示例包括I2C_SLAVE

Some ioctl() calls are for administrative tasks and are handled by i2c-dev directly. Examples include I2C_SLAVE

那么必须使用ioctl I2C_SLAVE吗?如果是这样,我是否需要设置一次或每次执行读写操作?

So is it must to use the ioctl I2C_SLAVE? If so do I need to set it just once or every time I perform a read and write?

如果我有一个i2c设备,我可以在该设备上测试代码,就不会打扰你们,但是不幸的是我现在没有一个.

If I had an i2c device I could have just tested the code on the device and would not have bothered you guys but unfortunately I don't have one right now.

感谢您的帮助.

推荐答案

从用户空间与i2c设备进行通信的主要方法有三种.

There are three major methods of communicating with i2c devices from userspace.

此方法允许同时读取/写入和发送不间断的消息序列.并非所有的i2c设备都支持此方法.

This method allows for simultaneous read/write and sending an uninterrupted sequence of message. Not all i2c devices support this method.

在使用此方法执行i/o之前,您应该使用ioctl I2C_FUNCS操作检查设备是否支持此方法.

Before performing i/o with this method, you should check whether the device supports this method using an ioctl I2C_FUNCS operation.

使用此方法,您不需要执行ioctl I2C_SLAVE操作-使用消息中嵌入的信息在幕后完成.

Using this method, you do not need to perform an ioctl I2C_SLAVE operation -- it is done behind the scenes using the information embedded in the messages.

这种I/O方法功能更强大,但结果代码更冗长.如果设备不支持I2C_RDWR方法,则可以使用此方法.

This method of i/o is more powerful but the resulting code is more verbose. This method can be used if the device does not support the I2C_RDWR method.

使用此方法,您要做需要执行ioctl I2C_SLAVE操作(或者,如果设备繁忙,则执行I2C_SLAVE_FORCE操作).

Using this method, you do need to perform an ioctl I2C_SLAVE operation (or, if the device is busy, an I2C_SLAVE_FORCE operation).

此方法使用基本文件I/O系统调用 read() write() .使用此方法不可能进行不间断的顺序操作.如果设备不支持I2C_RDWR方法,则可以使用此方法.

This method uses the basic file i/o system calls read() and write(). Uninterrupted sequential operations are not possible using this method. This method can be used if the device does not support the I2C_RDWR method.

使用此方法,您要做需要执行ioctl I2C_SLAVE操作(或者,如果设备繁忙,则执行I2C_SLAVE_FORCE操作).

Using this method, you do need to perform an ioctl I2C_SLAVE operation (or, if the device is busy, an I2C_SLAVE_FORCE operation).

除非您需要将芯片像文件一样对待,否则我想不出哪种方法比其他方法更可取.

I can't think of any situation when this method would be preferable to others, unless you need the chip to be treated like a file.

我尚未测试此示例,但它显示了写入i2c设备的概念流程.-自动检测是否使用ioctl I2C_RDWR或smbus技术.

I haven't tested this example, but it shows the conceptual flow of writing to an i2c device.-- automatically detecting whether to use the ioctl I2C_RDWR or smbus technique.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include <errno.h>
#include <string.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>

#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_DEVICE  0x00

int i2c_ioctl_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data, size_t size)
{
    int i, j = 0;
    int ret;
    uint8_t *buf;
    // the extra byte is for the regaddr
    size_t buff_size = 1 + size;

    buf = malloc(buff_size);
    if (buf == NULL) {
        return -ENOMEM;
    }

    buf[j ++] = regaddr;
    for (i = 0; i < size / sizeof(uint16_t); i ++) {
        buf[j ++] = (data[i] & 0xff00) >> 8;
        buf[j ++] = data[i] & 0xff;
    }

    struct i2c_msg messages[] = {
        {
            .addr = dev,
            .buf = buf,
            .len = buff_size,
        },
    };

    struct i2c_rdwr_ioctl_data payload = {
        .msgs = messages,
        .nmsgs = sizeof(messages) / sizeof(messages[0]),
    };

    ret = ioctl(fd, I2C_RDWR, &payload);
    if (ret < 0) {
        ret = -errno;
    }

    free (buf);
    return ret;
}

int i2c_ioctl_smbus_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data, size_t size)
{
    int i, j = 0;
    int ret;
    uint8_t *buf;

    buf = malloc(size);
    if (buf == NULL) {
        return -ENOMEM;
    }

    for (i = 0; i < size / sizeof(uint16_t); i ++) {
        buf[j ++] = (data[i] & 0xff00) >> 8;
        buf[j ++] = data[i] & 0xff;
    }

    struct i2c_smbus_ioctl_data payload = {
        .read_write = I2C_SMBUS_WRITE,
        .size = I2C_SMBUS_WORD_DATA,
        .command = regaddr,
        .data = (void *) buf,
    };

    ret = ioctl (fd, I2C_SLAVE_FORCE, dev);
    if (ret < 0)
    {
        ret = -errno;
        goto exit;
    }

    ret = ioctl (fd, I2C_SMBUS, &payload);
    if (ret < 0)
    {
        ret = -errno;
        goto exit;
    }

exit:
    free(buf);
    return ret;
}

int i2c_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data, size_t size)
{
    unsigned long funcs;

    if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
        return -errno;
    }

    if (funcs & I2C_FUNC_I2C) {
        return i2c_ioctl_write (fd, dev, regaddr, data, size);
    } else if (funcs & I2C_FUNC_SMBUS_WORD_DATA) {
        return i2c_ioctl_smbus_write (fd, dev, regaddr, data, size);
    } else {
        return -ENOSYS;
    }
}

int parse_args (uint8_t *regaddr, uint16_t *data, size_t size, char *argv[])
{
    char *endptr;
    int i;

    *regaddr = (uint8_t) strtol(argv[1], &endptr, 0);
    if (errno || endptr == argv[1]) {
        return -1;
    }

    for (i = 0; i < size / sizeof(uint16_t); i ++) {
        data[i] = (uint16_t) strtol(argv[i + 2], &endptr, 0);
        if (errno || endptr == argv[i + 2]) {
            return -1;
        }
    }

    return 0;
}

void usage (int argc, char *argv[])
{
    fprintf(stderr, "Usage: %s regaddr data [data]*\n", argv[0]);
    fprintf(stderr, "  regaddr   The 8-bit register address to write to.\n");
    fprintf(stderr, "  data      The 16-bit data to be written.\n");
    exit(-1);
}

int main (int argc, char *argv[])
{
    uint8_t regaddr;
    uint16_t *data;
    size_t size;
    int fd;
    int ret = 0;

    if (argc < 3) {
        usage(argc, argv);
    }

    size = (argc - 2) * sizeof(uint16_t);
    data = malloc(size);
    if (data == NULL) {
        fprintf (stderr, "%s.\n", strerror(ENOMEM));
        return -ENOMEM;
    }

    if (parse_args(&regaddr, data, size, argv) != 0) {
        free(data);
        usage(argc, argv);
    }

    fd = open(I2C_ADAPTER, O_RDWR | O_NONBLOCK);
    ret = i2c_write(fd, I2C_DEVICE, regaddr, data);
    close(fd);

    if (ret) {
        fprintf (stderr, "%s.\n", strerror(-ret));
    }

    free(data);

    return ret;
}

这篇关于I2C_SLAVE ioctl目的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆