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.