如何使用 i2c/smbus 执行 256 字节块读取

How to perform a 256 byte block read with i2c/smbus

我有这个电源监视器,我正在尝试与之交互以检索它的故障日志 LTC2977(数据 sheet:https://www.analog.com/media/en/technical-documentation/data-sheets/ltc2977.pdf

我是 i2c/pmbus/smbus 的新手,所以请原谅我糟糕的术语或对工作原理的不正确描述。在第 18 页上,数据 sheet 表明我可以像这样与它交互:

The LTC2977 is a slave device. The master can communicate with the LTC2977 using the following formats:

  • Master transmitter, slave receiver
  • Master receiver, slave transmitter

The following SMBus protocols are supported:

  • Write Byte, Write Word, Send Byte
  • Read Byte, Read Word, Block Read
  • Alert Response Address

Figure 1a-12 illustrate the aforementioned SMBus protocols. All transactions support PEC (packet error check) and GCP (group command protocol). The Block Read supports 255 bytes of returned data. For this reason, the PMBus timeout may be extended using the Mfr_config_all_ longer_pmbus_timeout setting.

可以使用 SMBus(PMBus?)命令 0xEE 访问有问题的日志,其中它将吐出 0xFF,后跟包含日志数据的 255 个字节。现在我可以通过执行 i2cdump 来查看设备及其所有内部 commands/registers(?),同样地,如果我执行 i2cget ... 0xEE,我会得到输出 0xff,这就是日志中的第一个条目应该是。我也可以做 i2cget ... 0xEE w,所以作为一个词输出以获得 0x--ff,其中 '-' 是每次我调用 i2cget 时更改的值,也许是我的日志数据?

我的问题是我正在尝试将其作为一个块来阅读,就像我在上面声明的文档一样。我不完全确定该怎么做,所以我尝试了以下操作:

device = open("/dev/i2c-0", O_RDWR);
ioctl(device, I2C_SLAVE_FORCE, 0x30); //0x30 is the i2c slave address

unsigned char buf[256] = {0};
buf[0] = 0xEE; //the smbus command of the log
write(device, buf, 1);
read(device, buf, 256);

我过去曾成功使用其他 i2c 设备像这样读取它们,首先发出命令,然后读入缓冲区。我之前成功使用过的最大缓冲区是 4 字节缓冲区,所以我认为这没什么不同,但是此操作后缓冲区的内容是每个条目现在都是 0xff,我认为这是不正确的看到 i2cget ... 0xEE w 不仅仅包含 0xff

接下来我尝试模拟我看到其他人使用的一些功能 <smbus.h>,我没有这个库可用所以我尝试重新创建 smbus 块读取函数,结果是像这样:

device = open("/dev/i2c-0", O_RDWR);
ioctl(device, I2C_SLAVE_FORCE, 0x30); //0x30 is the i2c slave address

union i2c_smbus_data data;

struct i2c_smbus_ioctl_data args;
args.read_write = I2C_SMBUS_READ;
args.command = 0xEE; //the smbus command of the log
args.size = I2C_SMBUS_BLOCK_DATA;
args.data = &data;

ioctl(device, I2C_SMBUS, &args);

不幸的是,这根本不起作用,它冻结了我的目标,我不得不重新启动它。我不确定这里出了什么问题,但我相信这是与设备交互的更合适或正确的方式,如果我能让它工作的话。我注意到的一件事是 i2c_smbus_data 中的块数据大小仅为 32 字节,这令人困惑,因为我的数据 sheet 似乎表明它将向我发送一个 256 字节的块,这可能是导致它的原因碰撞?我读到你可以忽略这个内置的块大小并自己实现它,但我不确定从哪里开始,这不是和我第一次尝试写入和读入缓冲区一样吗?

如果能提供任何帮助或帮助我了解如何正确使用此 SMBus 或读取日志数据,我们将不胜感激。我相信最坏的情况是我可以在日志命令中检索一个词 255 次来构建它,但这似乎是一个非常糟糕的方法

好的,我设法找到了一个解决方案,有点像 2 的混合。设置 I2C_SLAVE 不再完成(这会导致同一 I2C 缓冲区上的其他设备出现问题吗?我不知道)而是直接使用 I2C_RDWR 执行读取,其中传递了 2 条 i2c 消息,第一个是使用 smbus 命令/子地址写入,第二个是读取那里的数据。

device = open("/dev/i2c-0", O_RDWR);

unsigned char buf[256] = {0};
buf[0] = 0xEE; //the smbus command of the log

struct i2c_msg msgs[2];
msgs[0].addr = 0x30;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = buf;

msgs[1].addr = 0x30;
msgs[1].flags = I2C_M_RD;
msgs[1].len = 256;
msgs[1].buf = buf;

struct i2c_rdwr_ioctl_data args;
args.msgs = msgs;
args.nmsgs = 2;

ioctl(device, I2C_RDWR, &args);

我注意到的一个问题是设备出现了错误的通信错误(尽管为我提供了正确的数据)。数据 sheet 指出它是“非法形成的 i2c/smbus 命令”的全部错误,我想这意味着我做的事情不太正确。对于为什么会出现这种情况的任何评论,我们将不胜感激