title: Access device's register i2c
body: <p>I recently bought a <a href="http://playground.arduino.cc/uploads/Main/mpu-6050.jpg" rel="nofollow noreferrer">gy-521 board</a> and I'm trying to use it with a Raspberry Pi 3 through the following connections</p>
  
  <pre><code>RPi3     |     GY-521
  ---------------------
  3.3V &lt;-------&gt; Vcc
  GND  &lt;-------&gt; GND
  SCL  &lt;-------&gt; SCL
  SDA  &lt;-------&gt; SDA
  </code></pre>
  
  <p>Using <code>i2cdetect -y 1</code> I obtain the following</p>
  
  <pre><code>     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
  00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
  10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
  20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
  30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
  40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
  50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
  60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 
  70: -- -- -- -- -- -- -- --
  </code></pre>
  
  <p>so the address of the device is 0x68. Reading the <a href="https://www.olimex.com/Products/Modules/Sensors/MOD-MPU6050/resources/RM-MPU-60xxA_rev_4.pdf" rel="nofollow noreferrer">datasheet</a> I found that for example the acceleration on the X axis is store in registers 3B (higher bits) and 3C (lower bits). My question is <strong>how do I access those registers?</strong></p>
  
  <p>My idea is that if I open <code>/dev/i2c-1</code> as a file descriptor, I can use the normal <code>read</code> and <code>write</code> functions. Then instead of getting data all the time, I can use <code>poll</code> in case of new available data.</p>
  
  <p>I tried to use the <code>read</code> function as suggested in the <a href="https://www.kernel.org/doc/Documentation/i2c/dev-interface" rel="nofollow noreferrer">documentation</a> but that's not working (I only get zeros) and when I use <code>poll</code> it seems like there's no one on the other side and the timeout (100ms) expires. I think I should say to the chip "give me the value of the 3B register" but I can't figure how to do it.</p>
  
  <p><strong>CODE</strong></p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/stat.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;linux/i2c-dev.h&gt;
  #include &lt;sys/ioctl.h&gt;
  #include &lt;stdarg.h&gt;
  #include &lt;poll.h&gt;
  #include &lt;errno.h&gt;
  
  const char *filename = "/dev/i2c-1";
  int DEBUG = 0;
  int ADDRESS = 0x68;
  struct pollfd pfd;
  
  void debug(const char* format, ...)
  {
      if (DEBUG)
      {
          va_list argptr;
          va_start(argptr, format);
          fprintf(stdout, "### ");
          vfprintf(stdout, format, argptr);
          va_end(argptr);
      }
  }
  
  void error_handler(const char *msg)
  {
      perror(msg);
      exit(EXIT_FAILURE);
  }
  
  void set_debug(const char *deb_lev)
  {
      unsigned long num;
      char *p;
      errno = 0;
  
      num = strtoul(deb_lev, &amp;p, 10);
  
      if (errno != 0 || *p != '\0')
          error_handler("set_debug | strtoul");
  
      DEBUG = (num &gt; 0);
  }
  
  int open_file(const char *filename)
  {
      int fd;
  
      if ((fd = open(filename, O_RDWR)) == -1)
          error_handler("open_file | open");
  
      debug("\"%s\" opened at %d\n", filename, fd);
      return fd;
  }
  
  int8_t read_value(int fd)
  {
      debug("Reading from %d\n", fd);
  
      int8_t num;
      char *p = (char *)&amp;num;
      ssize_t size = sizeof(int8_t);
      ssize_t r = 0;
  
      while (size &gt; 0)
      {
          if ((r = read(fd, p, size)) == -1)
              error_handler("read_value | read");
  
          size -= r;
          p += r;
      }
  
      return num;
  }
  
  void command(uint16_t reg, int fd)
  {
      debug("Writing to %d\n", fd);
  
      unsigned char reg_buf[2];
      ssize_t w = 0;
      ssize_t size = sizeof(unsigned char)*2;
  
      reg_buf[0] = (reg &gt;&gt; 0) &amp; 0xFF;
      reg_buf[1] = (reg &gt;&gt; 8) &amp; 0xFF;
  
      if ((w = write(fd, reg_buf, size)) == -1)
          error_handler("command | write");
  }
  
  void read_data_from_imu(struct pollfd *pfd)
  {
      int8_t val;
      int p;
  
      for (;;)
      {
          command(0x3b, pfd-&gt;fd);
  
          switch (p = poll(pfd, 1, 100))
          {
              case -1:
                  error_handler("read_data_from_imu | poll");
              case 0:
                  fprintf(stderr, "Timeout expired\n");
                  break;
              default:
                  val = read_value(pfd-&gt;fd);
                  printf("Read: %u\n", val);
                  break;
          }
      }
  }
  
  int main(int argc, const char **argv)
  {
      if (argc &lt; 2)
      {
          fprintf(stderr, "Usage: %s debug_flag\n", argv[0]);
          return EXIT_FAILURE;
      }
  
      set_debug(argv[1]);
  
      pfd.fd = open_file(filename);
  
      debug("Setting slave address\n");
      if (ioctl(pfd.fd, I2C_SLAVE, ADDRESS) == -1)
          error_handler("main | ioctl");
  
      read_data_from_imu(&amp;pfd);
  
      return EXIT_SUCCESS;
  }
  </code></pre>
  
  <p><strong>EDIT</strong></p>
  
  <p>Thanks to <a href="https://stackoverflow.com/a/39411931/5025931">Kennyhyun</a> adding a <code>write</code> solved the problem.</p>
  
  <p>So, if you want to read the <strong>accelerometer measurement on the x axis</strong>
  you have to do something like this</p>
  
  <pre><code>...
  #define ACCEL_XOUT_H 0x3b
  #define ACCEL_XOUT_L 0x3c
  ...
  write_register(ACCEL_XOUT_H, pfd-&gt;fd);
  x_data = read_value(pfd-&gt;fd);
  write_register(ACCEL_XOUT_L, pfd-&gt;fd);
  x_data = (x_data &lt;&lt; 8) + read_value(pfd-&gt;fd);
  ...
  </code></pre>
  
  <p><strong>EDIT 2</strong></p>
  
  <p>Furthermore, you can simplify the code reading directly for 2 bytes after the write. You'll get something like this (error handling omitted)</p>
  
  <pre><code>int8_t buff[2];
  write_register(ACCEL_XOUT_H, pfd-&gt;fd);
  read(pfd-&gt;fd, buff, 2); //in this way you'll read both the ACCEL_XOUT_H register and the ACCEL_XOUT_L (the next one).
  </code></pre>