title: Reading / writing from using I2C on Linux
body: <p>I'm trying to read/write to a <code>FM24CL64-GTR FRAM</code> chip that is connected over a I2C bus on address <code>0b 1010 011</code>.</p>
  
  <p>When I'm trying to write 3 bytes (data address 2 bytes, + data one byte), I get a kernel message (<code>[12406.360000] i2c-adapter i2c-0: sendbytes: NAK bailout.</code>), as well as the write returns != 3.  See code below:</p>
  
  <pre><code>#include &lt;linux/i2c-dev.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;stdint.h&gt;
  
  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)) &lt; 0)
      exit(1);
  
  if (ioctl(file,I2C_SLAVE,addr) &lt; 0)
      exit(2);
  
  buf[0] = dataAddr &gt;&gt; 8;
  buf[1] = dataAddr &amp; 0xff;
  buf[2] = val;
  
  if (write(file, buf, 3) != 3)
      exit(3);
  
  ...
  </code></pre>
  
  <p>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:</p>
  
  <pre><code>uint8_t val;
  
  if ((file = open(filename,O_RDWR)) &lt; 0)
      exit(1);
  
  if (ioctl(file,I2C_SLAVE,addr) &lt; 0)
      exit(2);
  
  if (write(file, &amp;dataAddr, 2) != 2) {
      exit(3);
  
  if (read(file, &amp;val, 1) != 1) {
      exit(3);
  </code></pre>
  
  <p>None of the functions return an error value, and I have also tried it with:</p>
  
  <pre><code>#include &lt;linux/i2c.h&gt;
  
  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 = &amp;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 = &amp;ret;
  
  if (ioctl(file,I2C_RDWR,&amp;work_queue) &lt; 0)
      exit(3);
  </code></pre>
  
  <p>Which also succeeds, but always returns 0.  Does this indicate a hardware issue, or am I doing something wrong?</p>
  
  <p>Are there any FRAM drivers for FM24CL64-GTR over I2C on Linux, and what would the API be?  Any link would be helpful.</p>