gobot.io/x/gobot/v2@v2.1.0/system/I2C.md (about)

     1  # I2C
     2  
     3  This document describes some basics for developers.
     4  
     5  ## Byte order
     6  
     7  All common libraries (smbus, digispark, firmata, i2cget) read and write I2C data in the order LSByte, MSByte.  
     8  Often the devices store its bytes in the reverse order and therefor needs to be swapped after reading.
     9  
    10  ## Linux syscall implementation
    11  
    12  In general there are different ioctl features for I2C
    13  
    14  * IOCTL I2C_RDWR, needs "I2C_FUNC_I2C"
    15  * IOCTL SMBUS, needs "I2C_FUNC_SMBUS.."
    16  * SYSFS I/O
    17  * call of "i2c_smbus_* methods"
    18  
    19  >The possible functions should be checked before by "I2C_FUNCS".
    20  
    21  ## SMBus ioctl workflow and functions
    22  
    23  > Some calls are branched by kernels [i2c-dev.c:i2cdev_ioctl()](https://elixir.bootlin.com/linux/latest/source/drivers/i2c/i2c-dev.c#L392)
    24  > to the next listed calls.
    25  
    26  Set the device address `ioctl(file, I2C_SLAVE, long addr)`. The call set the address directly to the character device.  
    27  
    28  Query the supported functions `ioctl(file, I2C_FUNCS, unsigned long *funcs)`. The call is converted to in-kernel function
    29  [i2c.h:i2c_get_functionality()](https://elixir.bootlin.com/linux/latest/source/include/linux/i2c.h#L902)
    30  
    31  Execute a function, if supported `ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)`. The call is converted by
    32  kernels [i2c-dev.c:i2cdev_ioctl_smbus](https://elixir.bootlin.com/linux/latest/source/drivers/i2c/i2c-dev.c#L311) to
    33  [i2c.h:i2c_smbus_xfer()](https://elixir.bootlin.com/linux/latest/source/include/linux/i2c.h#L140). This leads to call of
    34  [i2c-core-smbus.c:i2c_smbus_xfer_emulated()](https://elixir.bootlin.com/linux/latest/source/drivers/i2c/i2c-core-smbus.c#L607)
    35  if adapter.algo->smbus_xfer() is not implemented (that means there is no implementation for the current platform/adapter).
    36  
    37  ```C
    38  /* This is the structure as used in the I2C_SMBUS ioctl call */
    39  struct i2c_smbus_ioctl_data {
    40    __u8 read_write;
    41    __u8 command;
    42    __u32 size;
    43    union i2c_smbus_data __user *data;
    44  };
    45  
    46  /*
    47   * Data for SMBus Messages
    48   */
    49  #define I2C_SMBUS_BLOCK_MAX 32  /* As specified in SMBus standard */
    50  union i2c_smbus_data {
    51    __u8 byte;
    52    __u16 word;
    53    __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
    54               /* and one more for user-space compatibility */
    55  };
    56  
    57  ```
    58  
    59  ```C
    60  // default preparation for call of "status = __i2c_transfer(adapter, msg, nmsgs)"
    61  
    62  msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
    63  msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
    64  
    65  msgbuf0[0] = command;
    66  
    67  struct i2c_msg msg[2] = {
    68    {
    69      .addr = addr,
    70      .flags = flags,
    71      .len = 1,
    72      .buf = msgbuf0,
    73    }, {
    74      .addr = addr,
    75      .flags = flags | I2C_M_RD,
    76      .len = 0,
    77      .buf = msgbuf1,
    78    },
    79  };
    80  /* note: msg[0].buf == msgbuf0, means
    81           msg[0].buf[0] == msgbuf0[0]
    82           msg[0].buf[1] == msgbuf0[1]
    83           msg[0].buf[2] == msgbuf0[2]
    84  */
    85  ```
    86  
    87  ### Data flow for I2C_FUNC_SMBUS_WRITE_BYTE
    88  
    89  ```C
    90  i2c_smbus_write_byte(const struct i2c_client *client, u8 value);
    91  \\would call:
    92  i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
    93  ```
    94  
    95  gobot: d.smbusAccess(I2C_SMBUS_WRITE, val, I2C_SMBUS_BYTE, nil), calls without a platform driver  
    96  
    97  ```C
    98  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write=I2C_SMBUS_WRITE, command=val, size=I2C_SMBUS_BYTE, *data=NULL);
    99  ```
   100  
   101  ```C
   102  // by default preparation (see above)
   103  msg[0].len = 1;
   104  msg[0].buf[0] = command; // corresponds to "val"
   105  nmsg = 1;
   106  ```
   107  
   108  ### Data flow for I2C_FUNC_SMBUS_WRITE_BYTE_DATA
   109  
   110  ```C
   111  i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value);
   112  // would call:
   113  data.byte = value;
   114  i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_BYTE_DATA, &data);
   115  ```
   116  
   117  gobot: d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, unsafe.Pointer(&data)), calls without a platform driver
   118  
   119  ```C
   120  datasize = sizeof(data->byte);
   121  copy_from_user(&temp, data, datasize);
   122  
   123  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write=I2C_SMBUS_WRITE, command=reg, size=I2C_SMBUS_BYTE_DATA, *data=&temp);
   124  
   125  // leads to:
   126  msg[0].len = 2;
   127  msg[0].buf[0] = command; // corresponds to "reg"
   128  msg[0].buf[1] = data->byte;
   129  nmsg = 1;
   130  ```
   131  
   132  ### Data flow for I2C_FUNC_SMBUS_WRITE_WORD_DATA
   133  
   134  ```C
   135  i2c_smbus_write_word_data(const struct i2c_client *client, u8 command, u16 value);
   136  // would call:
   137  data.word = value;
   138  i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_WORD_DATA, &data);
   139  ```
   140  
   141  gobot: d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, unsafe.Pointer(&data)), calls without a platform driver
   142  
   143  ```C
   144  datasize = sizeof(data->word);
   145  copy_from_user(&temp, data, datasize);
   146  
   147  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write=I2C_SMBUS_WRITE, command=reg, size=I2C_SMBUS_WORD_DATA, *data=&temp);
   148  
   149  // leads to:
   150  msg[0].len = 3;
   151  msg[0].buf[0] = command;
   152  msg[0].buf[1] = data->word & 0xff;
   153  msg[0].buf[2] = data->word >> 8;
   154  nmsg = 1;
   155  ```
   156  
   157  ### Data flow for I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
   158  
   159  ```C
   160  i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values);
   161  // would call:
   162  data.block[0] = length; // set first data element to length
   163  memcpy(&data.block[1], values, length); // ...followed by the real data values
   164  i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_BLOCK_DATA, &data);
   165  ```
   166  
   167  gobot: do not use this feature, but this would call without a platform driver
   168  
   169  ```C
   170  datasize = sizeof(data->block); // it seems this just blocks 32+2
   171  copy_from_user(&temp, data, datasize); // but possibly this only copy what is there
   172  
   173  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_WRITE, command=reg, size==I2C_SMBUS_BLOCK_DATA, *data==&temp);
   174  
   175  // leads to:
   176  // this reads the length from given user data, first element, add 2 for command and one more for user space compatibility:
   177  msg[0].len = data->block[0] + 2;
   178  msg[0].buf[0] = command; // by i2c_smbus_try_get_dmabuf(&msg[0], command)
   179  msg[0].buf + 1 = data->block; // copy with size!, by memcpy(msg[0].buf + 1, data->block, msg[0].len - 1);
   180  nmsg = 1;
   181  ```
   182  
   183  > "i2c_smbus_write_block_data" adds the real data size as first value in data. Writing this to the device is intended
   184  > for SMBus devices, see "section 6.5.7 Block Write/Read" of [smbus 3.0 specification](http://smbus.org/specs/SMBus_3_0_20141220.pdf).
   185  > Implementing this behavior in gobot leads to writing the size as first data element, but this is normally not useful
   186  > for i2c devices. When using ioctl calls there is no way to drop the size element by using this call.
   187  
   188  ### Data flow for I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
   189  
   190  ```C
   191  i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values);
   192  // would call:
   193  data.block[0] = length; // set first data element to length
   194  memcpy(data.block + 1, values, length); // ...followed by the real data values
   195  i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA, &data);
   196  ```
   197  
   198  gobot:
   199  
   200  ```go
   201  // set the first element with the data size
   202  dataLen := len(data)
   203  buf := make([]byte, dataLen+1)
   204  buf[0] = byte(dataLen)
   205  copy(buf[1:], data)
   206  d.smbusAccess(I2C_SMBUS_WRITE, reg, I2C_SMBUS_I2C_BLOCK_DATA, unsafe.Pointer(&buf[0]))
   207  ```
   208  
   209  ...calls without a platform driver
   210  
   211  ```C
   212  datasize = sizeof(data->block); // it seems this just blocks 32+2
   213  copy_from_user(&temp, data, datasize); // but possibly this only copy what is there
   214  
   215  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_WRITE, command=reg, size==I2C_SMBUS_I2C_BLOCK_DATA,
   216    *data==&temp);
   217  
   218  // this reads the length from given user data, first element, add 1 for command:
   219  msg[0].len = data->block[0] + 1;
   220  msg[0].buf[0] = command; // by i2c_smbus_try_get_dmabuf(&msg[0], command)
   221  msg[0].buf + 1 = data->block + 1; // copy real data without size, by memcpy(msg[0].buf + 1, data->block + 1, data->block[0]);
   222  nmsg=1
   223  ```
   224  
   225  ### Data flow for I2C_FUNC_SMBUS_READ_BYTE
   226  
   227  ```C
   228  i2c_smbus_read_byte(const struct i2c_client *client);
   229  // would call:
   230  i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data);
   231  return data.byte;
   232  ```
   233  
   234  gobot: d.smbusAccess(I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, unsafe.Pointer(&data)), calls without a platform driver
   235  
   236  ```C
   237  datasize = sizeof(data->byte); // &temp keeps empty
   238  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=0, size==I2C_SMBUS_BYTE, *data==&temp);
   239  
   240  msg[0].len = 1; // per default
   241  msg[0].flags = I2C_M_RD | flags;
   242  msg[0].buf[0] = 0; // from command
   243  nmsgs = 1;
   244  ```
   245  
   246  afterwards copy content to target structure
   247  
   248  ```C
   249  data->byte = msg[0].buf[0]; // copy read value back to given data pointer and one level above
   250  copy_to_user(data, &temp, datasize); // copy one byte back to given data pointer
   251  ```
   252  
   253  ### Data flow for I2C_FUNC_SMBUS_READ_BYTE_DATA
   254  
   255  ```C
   256  i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command);
   257  // would call:
   258  i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, command, I2C_SMBUS_BYTE_DATA, &data);
   259  return data.byte;
   260  ```
   261  
   262  gobot: d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, unsafe.Pointer(&data)), calls without a platform driver
   263  
   264  ```C
   265  datasize = sizeof(data->byte); // &temp keeps empty
   266  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=reg, size==I2C_SMBUS_BYTE_DATA, *data==&temp);
   267  
   268  msg[0].len = 1; // per default
   269  msg[0].buf[0] = command;
   270  msg[1].len = 1;
   271  nmsgs = 2;
   272  ```
   273  
   274  afterwards copy content to target structure
   275  
   276  ```C
   277  data->byte = msg[1].buf[0]; // copy read value back to given data pointer and one level above
   278  copy_to_user(data, &temp, datasize); // copy one byte back to given data pointer
   279  ```
   280  
   281  ### Data flow for I2C_FUNC_SMBUS_READ_WORD_DATA
   282  
   283  ```C
   284  i2c_smbus_read_word_data(const struct i2c_client *client, u8 command);
   285  // would call:
   286  status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, command, I2C_SMBUS_WORD_DATA, &data);
   287  return data.word;
   288  ```
   289  
   290  gobot: d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, unsafe.Pointer(&data)), calls without a platform driver
   291  
   292  ```C
   293  datasize = sizeof(data->word); // &temp keeps empty
   294  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=reg, size==I2C_SMBUS_BYTE_DATA, *data==&temp);
   295  
   296  msg[0].len = 1; // per default
   297  msg[0].buf[0] = command;
   298  msg[1].len = 2;
   299  nmsgs = 2;
   300  ```
   301  
   302  afterwards copy content to target structure
   303  
   304  ```C
   305  data->word = msgbuf1[0] | (msgbuf1[1] << 8); // copy read value back to given data pointer and one level above
   306  copy_to_user(data, &temp, datasize); // copy 2 bytes back to given data pointer
   307  ```
   308  
   309  ### Data flow for I2C_FUNC_SMBUS_READ_BLOCK_DATA
   310  
   311  ```C
   312  i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values);
   313  // would call:
   314  i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, command, I2C_SMBUS_BLOCK_DATA, &data);
   315  // data.block[0] is the read length (N)
   316  memcpy(values, &data.block[1], data.block[0]); // copy starting from data.block[1] to "values", N elements
   317  return data.block[0]; // number of read bytes (N)
   318  ```
   319  
   320  gobot: do not use this feature, but this would call without a platform driver
   321  
   322  ```C
   323  datasize = sizeof(data->block); // &temp keeps empty
   324  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=reg, size==I2C_SMBUS_BYTE_DATA, *data==&temp);
   325  
   326  msg[0].len = 1; // per default
   327  msg[0].buf[0] = command;
   328  msg[1].flags |= I2C_M_RECV_LEN;
   329  msg[1].len = 1; // block length will be added by the underlying bus driver
   330  msg[1].buf[0] = 0; // by i2c_smbus_try_get_dmabuf(&msg[1], 0);
   331  nmsgs = 2;
   332  ```
   333  
   334  afterwards copy content to target structure
   335  
   336  ```C
   337  memcpy(data->block, msg[1].buf, msg[1].buf[0] + 1); // copy read value back to given data pointer and one level above
   338  copy_to_user(data, &temp, datasize); // copy all bytes (according to given size) back to given data pointer
   339  ```
   340  
   341  ### Data flow for I2C_FUNC_SMBUS_READ_I2C_BLOCK
   342  
   343  ```C
   344  i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, u8 *values);
   345  // would call:
   346  data.block[0] = length; // set first data element to length
   347  i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, command, I2C_SMBUS_I2C_BLOCK_DATA, &data);
   348  // data.block[0] is the read length (N)
   349  memcpy(values, &data.block[1], data.block[0]); // copy starting from data.block[1] to "values", N elements
   350  return data.block[0]; // number of read bytes (N)
   351  ```
   352  
   353  gobot:
   354  
   355  ```go
   356  dataLen := len(data)
   357  // set the first element with the data size
   358  buf := make([]byte, dataLen+1)
   359  buf[0] = byte(dataLen)
   360  copy(buf[1:], data)
   361  log.Printf("buffer: %v", buf)
   362  d.smbusAccess(I2C_SMBUS_READ, reg, I2C_SMBUS_I2C_BLOCK_DATA, unsafe.Pointer(&buf[0])); err != nil {
   363  // get data from buffer without first size element
   364  copy(data, buf[1:])
   365  ```
   366  
   367  ...calls without a platform driver
   368  
   369  ```C
   370  datasize = sizeof(data->block); // &temp keeps empty, datasize includes the "size" byte (means real data + 1)
   371  copy_from_user(&temp, data, datasize); // but possibly this only copy what is there
   372  
   373  i2c_smbus_xfer_emulated(*adapter, addr, flags, read_write==I2C_SMBUS_READ, command=reg, size==I2C_SMBUS_I2C_BLOCK_DATA, *data==&temp);
   374  
   375  msg[0].len = 1; // per default
   376  msg[0].buf[0] = command;
   377  msg[1].len = data->block[0]; // this reads the length from given user data, first element:
   378  msg[1].buf[0] = 0; // by i2c_smbus_try_get_dmabuf(&msg[1], 0);
   379  nmsgs = 2;
   380  ```
   381  
   382  afterwards copy content to target structure
   383  
   384  ```C
   385  // copy read values back, starting from second value (contains length)
   386  memcpy(data->block + 1, msg[1].buf, data->block[0]);
   387  // and one level above:
   388  copy_to_user(data, &temp, datasize); // copy all bytes (according to given size) back to given data pointer
   389  // this means, the caller needs to strip the real data starting from second byte (like "i2c_smbus_read_i2c_block_data")
   390  ```
   391  
   392  ## Links
   393  
   394  * <https://www.kernel.org/doc/Documentation/i2c/dev-interface>
   395  * <https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/i2c-dev.h#L42>
   396  * <https://stackoverflow.com/questions/9974592/i2c-slave-ioctl-purpose> (good for understanding, but there are some
   397    small errors in the provided example)
   398  * <https://stackoverflow.com/questions/55976683/read-a-block-of-data-from-a-specific-registerfifo-using-c-c-and-i2c-in-raspb>
   399  
   400  > Qotation from kernel.org: "If possible, use the provided i2c_smbus_* methods described below instead of issuing direct
   401  > ioctls."  
   402  > We do not do this at the moment, instead we using the "IOCTL SMBUS".
   403  
   404  Because the syscall needs uintptr in Go, there are some known pitfalls with that. Following documents could be helpful:
   405  
   406  * <https://go101.org/article/unsafe.html>
   407  * <https://stackoverflow.com/questions/51187973/how-to-create-an-array-or-a-slice-from-an-array-unsafe-pointer-in-golang>
   408  * <https://stackoverflow.com/questions/59042646/whats-the-difference-between-uint-and-uintptr-in-golang>
   409  * <https://go.dev/play/p/Wd7hWn9Zsu>
   410  * for go vet false positives, see: <https://github.com/golang/go/issues/41205>
   411  
   412  Basically by convert to an uintptr, which is than just a number to an object existing at the moment of creation without
   413  any other reference, the garbage collector will possible destroy the original object. Therefor uintptr should be avoided
   414  as long as possible.