嘿,我正在尝试为运行 PetaLinux(嵌入式 Linux 操作系统)的嵌入式系统编写用户空间应用程序以将一些数据移动到 I2C,尽管我认为这不是影响问题的原因。我收到连接超时和分段错误。
该函数具有指示它写入第一个 I2C 总线的宏。我在 main 中指定要写入的数据并将其传递给 i2c_write,然后将其传递给 i2c_ioctl_write。
这是代码:
#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
#define REG_ADDR 0x00
int i2c_ioctl_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data)
{
printf("i2c_ioctl_write\n");
int i, j = 0;
int ret;
uint8_t *buf;
buf = malloc(1 + 2 * (sizeof(data) / sizeof(data[0])));
if (buf == NULL) {
return -ENOMEM;
}
printf("\tBuffer Allocation Successful...\n");
buf[j ++] = regaddr;
for (i = 0; i < (sizeof(data) / sizeof(data[0])); i ++) {
buf[j ++] = (data[i] & 0xff00) >> 8;
buf[j ++] = data[i] & 0xff;
}
printf("\tBuffer Setup Successful...\n");
struct i2c_msg messages[] = {
{
.addr = dev,
.buf = buf,
.len = sizeof(buf) / sizeof(buf[0]),
},
};
printf("\tSetup I2C Messages...\n");
struct i2c_rdwr_ioctl_data payload = {
.msgs = messages,
.nmsgs = sizeof(messages) / sizeof(messages[0]),
};
printf("\tSetup I2C IOCTL Payload...\n");
ret = ioctl(fd, I2C_RDWR, &payload);
printf("\tWrote with IOCTL...\n");
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)
{
printf("i2c_ioctl_smbus_write\n");
int i, j = 0;
int ret;
uint8_t *buf;
buf = malloc(2 * (sizeof(data) / sizeof(data[0])));
if (buf == NULL) {
return -ENOMEM;
}
for (i = 0; i < (sizeof(data) / sizeof(data[0])); 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)
{
printf("i2x_write\n");
uint64_t funcs;
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
return -errno;
}
if (funcs & I2C_FUNC_I2C) {
return i2c_ioctl_write (fd, dev, regaddr, data);
} else if (funcs & I2C_FUNC_SMBUS_WORD_DATA) {
return i2c_ioctl_smbus_write (fd, dev, regaddr, data);
} else {
return -ENOSYS;
}
}
int main (int argc, char *argv[])
{
printf("main\n");
uint8_t regaddr;
int fd;
int ret = 0;
uint16_t data[] = {1, 2, 4};
fd = open(I2C_ADAPTER, O_RDWR | O_NONBLOCK);
ret = i2c_write(fd, I2C_DEVICE, REG_ADDR, data);
close(fd);
if (ret) {
fprintf (stderr, "%s.\n", strerror(-ret));
}
free(data);
return ret;
}
当我在 QEMU 上运行程序时,我得到以下输出:
main i2x_write i2c_ioctl_write 缓冲区分配成功...缓冲区设置成功...设置 I2C 消息设置 I2C IOCTL 有效负载 cdns-i2c e0004000.i2c:超时等待完成 写入 IOCTL 连接超时。分段故障
我认为它在线上失败了
ret = ioctl(fd, I2C_RDWR, &payload);
但我不知道为什么。有效载荷是否构造不当?
更新:这是当前代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.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 main (int argc, char *argv[])
{
int fd;
int ret = 0;
fd = open(I2C_ADAPTER, O_RDWR | O_NONBLOCK);
uint64_t funcs;
int addr = 0X00;
if (ioctl(fd, I2C_SLAVE, addr) < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
printf("Cannot setup as slave");
exit(1);
}
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
printf("ioctl failed");
return -errno;
}
printf("funcs & I2C_FUNC_I2C: %llu\n", funcs & I2C_FUNC_I2C);
printf("funcs & I2C_FUNC_SMBUS_WORD_DATA: %llu\n", funcs & I2C_FUNC_SMBUS_WORD_DATA);
__u8 reg = 0x10;
__s32 res;
if (funcs & I2C_FUNC_I2C) {
char buf[10];
printf("Attempting to write to I2C bus via I2C protocol...\n");
buf[0] = reg;
buf[1] = 0x43;
buf[2] = 0x65;
int bytes_written = write(fd, buf, 3);
if(bytes_written != 3) {
printf("Wrote %d bytes", bytes_written);
printf("\tFailed to write to I2C Bus\n");
close(fd);
return -1;
}
else {
printf("\tSuccesful write to I2C Bus\n");
}
char buf2[10];
printf("Attempting to read from I2C bus via I2C protocol...\n");
if(read(fd, buf2, 1) != 1) {
printf("\tFailed to do I2C read from Bus\n");
close(fd);
return -1;
}
else {
printf("\tRead successful. Comparing read results from original write buffer...");
printf("\t\tWritten value: %c", buf[0]);
printf("\t\tRead value: %c", buf2[0]);
}
return 0;
} else if (funcs & I2C_FUNC_SMBUS_WORD_DATA) {
printf("Attempting to write to I2C bus via SMBus protocol...\n");
//res = i2c_smbus_write_word_data(fd, REG_ADDR, 0x6543);
res = 1;
if(res < 0) {
printf("\tFailed to write to I2C Bus\n");
close(fd);
return -1;
}
else {
printf("\tSuccesful write to I2C Bus\n");
}
//res = i2c_smbus_read_word_data(fd, REG_ADDR);
if(res < 0) {
printf("\tFailed to read from I2C Bus\n");
close(fd);
return -1;
}
else {
printf("\tRead successful. Comparing read results from original write buffer...");
printf("\t\tWritten value: %c", 0x6543);
printf("\t\tRead value: %c", res);
}
} else {
printf("Cannot write to I2C");
return -ENOSYS;
}
close(fd);
if (ret) {
fprintf (stderr, "%s.\n", strerror(-ret));
}
return ret;
}
我能够通过删除 free() 来摆脱 seg 错误,所以谢谢。我已经查明了发生在 Cadence I2C 驱动程序中的超时的确切问题:
这仍在发生。
如前所述,我向从站写入的方式可能存在一些问题,导致从站不发送 ACK,从而导致超时。我不确定我需要写哪些寄存器。我感觉需要更改 I2C_DEVICE 宏以及 addr 和 reg 变量。