gpt4 book ai didi

linux - I2C_SLAVE ioctl 目的

转载 作者:IT王子 更新时间:2023-10-29 00:25:11 28 4
gpt4 key购买 nike

我正在编写代码,使用通用的 linux i2c 驱动程序 linux/i2c-dev.h 实现一个简单的 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 设置从机地址。

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

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

那么是不是一定要用ioctl I2C_SLAVE?如果是这样,我是否需要只设置一次或每次执行读写时设置它?

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

感谢您的帮助。

最佳答案

从用户空间与 i2c 设备通信的主要方法有 3 种。

1。 IOCTL I2C_RDWR

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

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

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

2。 IOCTL SMBUS

这种 i/o 方法更强大,但生成的代码更冗长。如果设备不支持I2C_RDWR方法,可以使用此方法。

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

3。 SYSFS I/O

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

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

我想不出在任何情况下这种方法比其他方法更可取,除非您需要将芯片视为文件。


完整的 IOCTL 示例

我没有测试这个例子,但它显示了写入 i2c 设备的概念流程。-- 自动检测是否使用 ioctl I2C_RDWR 或 smbus 技术。

#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;
}

关于linux - I2C_SLAVE ioctl 目的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9974592/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com