在 Linux 上使用 I2C 进行读/写
我正在尝试读取/写入通过地址 0b 1010 011
上的 I2C 总线连接的 FM24CL64-GTR FRAM
芯片。
当我尝试写入 3 个字节(数据地址 2 个字节,+ 数据一个字节)时,我收到一条内核消息 ([12406.360000] i2c-adapter i2c-0: sendbytes: NAK bailout。
) ,以及写入返回 != 3。请参阅下面的代码:
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
int file;
char filename[20];
int addr = 0x53; // 0b1010011; /* The I2C address */
uint16_t dataAddr = 0x1234;
uint8_t val = 0x5c;
uint8_t buf[3];
sprintf(filename,"/dev/i2c-%d",0);
if ((file = open(filename,O_RDWR)) < 0)
exit(1);
if (ioctl(file,I2C_SLAVE,addr) < 0)
exit(2);
buf[0] = dataAddr >> 8;
buf[1] = dataAddr & 0xff;
buf[2] = val;
if (write(file, buf, 3) != 3)
exit(3);
...
但是,当我写入 2 个字节,然后写入另一个字节时,我没有收到内核错误,但当尝试从 FRAM 读取时,我总是返回 0。这是从 FRAM 读取的代码:
uint8_t val;
if ((file = open(filename,O_RDWR)) < 0)
exit(1);
if (ioctl(file,I2C_SLAVE,addr) < 0)
exit(2);
if (write(file, &dataAddr, 2) != 2) {
exit(3);
if (read(file, &val, 1) != 1) {
exit(3);
没有一个函数返回错误值,我也尝试过:
#include <linux/i2c.h>
struct i2c_rdwr_ioctl_data work_queue;
struct i2c_msg msg[2];
uint8_t ret;
work_queue.nmsgs = 2;
work_queue.msgs = msg;
work_queue.msgs[0].addr = addr;
work_queue.msgs[0].len = 2;
work_queue.msgs[0].flags = 0;
work_queue.msgs[0].buf = &dataAddr;
work_queue.msgs[1].addr = addr;
work_queue.msgs[1].len = 1;
work_queue.msgs[1].flags = I2C_M_RD;
work_queue.msgs[1].buf = &ret;
if (ioctl(file,I2C_RDWR,&work_queue) < 0)
exit(3);
也成功,但始终返回 0。这是否表明硬件问题,或者我做错了什么?
Linux 上是否有通过 I2C 的 FM24CL64-GTR 的 FRAM 驱动程序?API 是什么? 任何链接都会有帮助。
I'm trying to read/write to a FM24CL64-GTR FRAM
chip that is connected over a I2C bus on address 0b 1010 011
.
When I'm trying to write 3 bytes (data address 2 bytes, + data one byte), I get a kernel message ([12406.360000] i2c-adapter i2c-0: sendbytes: NAK bailout.
), as well as the write returns != 3. See code below:
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
int file;
char filename[20];
int addr = 0x53; // 0b1010011; /* The I2C address */
uint16_t dataAddr = 0x1234;
uint8_t val = 0x5c;
uint8_t buf[3];
sprintf(filename,"/dev/i2c-%d",0);
if ((file = open(filename,O_RDWR)) < 0)
exit(1);
if (ioctl(file,I2C_SLAVE,addr) < 0)
exit(2);
buf[0] = dataAddr >> 8;
buf[1] = dataAddr & 0xff;
buf[2] = val;
if (write(file, buf, 3) != 3)
exit(3);
...
However when I write 2 bytes, then write another byte, I get no kernel error, but when trying to read from the FRAM, I always get back 0. Here is the code to read from the FRAM:
uint8_t val;
if ((file = open(filename,O_RDWR)) < 0)
exit(1);
if (ioctl(file,I2C_SLAVE,addr) < 0)
exit(2);
if (write(file, &dataAddr, 2) != 2) {
exit(3);
if (read(file, &val, 1) != 1) {
exit(3);
None of the functions return an error value, and I have also tried it with:
#include <linux/i2c.h>
struct i2c_rdwr_ioctl_data work_queue;
struct i2c_msg msg[2];
uint8_t ret;
work_queue.nmsgs = 2;
work_queue.msgs = msg;
work_queue.msgs[0].addr = addr;
work_queue.msgs[0].len = 2;
work_queue.msgs[0].flags = 0;
work_queue.msgs[0].buf = &dataAddr;
work_queue.msgs[1].addr = addr;
work_queue.msgs[1].len = 1;
work_queue.msgs[1].flags = I2C_M_RD;
work_queue.msgs[1].buf = &ret;
if (ioctl(file,I2C_RDWR,&work_queue) < 0)
exit(3);
Which also succeeds, but always returns 0. Does this indicate a hardware issue, or am I doing something wrong?
Are there any FRAM drivers for FM24CL64-GTR over I2C on Linux, and what would the API be? Any link would be helpful.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我没有使用该特定设备的经验,但根据我们的经验,许多 I2C 设备都有“怪癖”,需要解决方法,通常是在驱动程序级别之上。
我们还使用 Linux (CELinux) 和 Linux 上的 I2C 设备驱动程序。 但我们的应用程序代码还有一个重要的 I2C 模块,其中包含用于处理我们所使用过的所有各种设备的所有解决方法智能。
另外,在处理 I2C 问题时,我经常发现需要重新熟悉源规范:
http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf
以及像样的示波器的使用。
祝你好运,
上面的链接已失效,这里有一些其他链接:
http://www.nxp.com/documents/user_manual/UM10204.pdf" rel="nofollow noreferrer">http://www.nxp.com nxp.com/documents/user_manual/UM10204.pdf
当然还有维基百科:
http://en.wikipedia.org/wiki/I%C2%B2C
I do not have experience with that particular device, but in our experience many I2C devices have "quirks" that require a work-around, typically above the driver level.
We use linux (CELinux) and an I2C device driver with Linux as well. But our application code also has a non-trivial I2C module that contains all the work-around intelligence for dealing with all the various devices we have experience with.
Also, when dealing with I2C issues, I often find that I need to re-acquaint myself with the source spec:
http://www.nxp.com/acrobat_download/literature/9398/39340011.pdf
as well as the usage of a decent oscilloscope.
Good luck,
Above link is dead, here are some other links:
http://www.nxp.com/documents/user_manual/UM10204.pdf
and of course wikipedia:
http://en.wikipedia.org/wiki/I%C2%B2C
NAK 是一个很大的提示:WriteProtect 引脚被外部上拉,并且必须驱动至接地,之后地址和数据字节的单次写入成功(第一个代码段)。
对于读取,可以先写出地址(使用 write()),然后可以从该地址开始读取顺序数据。
The NAK was a big hint: the WriteProtect pin was externally pulled up, and had to be driven to ground, after that a single write of the address followed by data-bytes is successful (first code segment).
For reading the address can be written out first (using write()), and then sequential data can be read starting from that address.
请注意,使用 struct i2c_rdwr_ioctl_data 和 struct i2c_msg 的方法(即您给出的最后一个代码部分)比其他方法更有效,因为使用该方法方法执行 I2c 的重复启动功能。
这意味着您可以避免
STA-WRITE-STO -> STA-READ-...-STO
转换,因为您的通信将变为STA-WRITE-RS-READ-...STO
(RS
= 重复开始)。 因此,可以为您节省冗余的STO-STA
瞬态。并不是说它在时间上有很大差异,但如果不需要,为什么会失去它......
只是我的 2 ct。
最佳 rgds,
Note that the method using the
struct i2c_rdwr_ioctl_data
and thestruct i2c_msg
(that is, the last code part you've given) is more efficient than the other ones, since with that method you execute the repeated start feature of I2c.This means you avoid a
STA-WRITE-STO -> STA-READ-<data>...-STO
transition, because your communication will becomeSTA-WRITE-RS-READ-<data>...STO
(RS
= repeated start). So, saves you a redundantSTO-STA
transient.Not that it differs a lot in time, but if it's not needed, why losing on it...
Just my 2 ct.
Best rgds,
你有一些错误!
ic
的地址为十六进制的Ax
,x
可以是任何值,但高 4 位应为A=1010
!!!You had some mistakes!
The address of
ic
isAx
in hex,x
can be anything but the 4 upper bits should beA=1010
!!!