在 Linux 上使用 I2C 进行读/写

发布于 2024-07-13 00:38:01 字数 1781 浏览 8 评论 0原文

我正在尝试读取/写入通过地址 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

此生挚爱伱 2024-07-20 00:38:01

我没有使用该特定设备的经验,但根据我们的经验,许多 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

亚希 2024-07-20 00:38:01

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.

物价感观 2024-07-20 00:38:01

请注意,使用 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 the struct 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 become STA-WRITE-RS-READ-<data>...STO (RS = repeated start). So, saves you a redundant STO-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,

罪#恶を代价 2024-07-20 00:38:01

你有一些错误!

ic 的地址为十六进制的 Axx 可以是任何值,但高 4 位应为 A=1010!!!

You had some mistakes!

The address of ic is Ax in hex, x can be anything but the 4 upper bits should be A=1010 !!!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文