Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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

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,

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 !!!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top