-
-
Save JamesDunne/9b7fbedb74c22ccc833059623f47beb7 to your computer and use it in GitHub Desktop.
| #include <stdio.h> | |
| #include <string.h> | |
| #include <fcntl.h> | |
| #include <linux/i2c-dev.h> | |
| // Terrible portability hack between arm-linux-gnueabihf-gcc on Mac OS X and native gcc on raspbian. | |
| #ifndef I2C_M_RD | |
| #include <linux/i2c.h> | |
| #endif | |
| typedef unsigned char u8; | |
| // Global file descriptor used to talk to the I2C bus: | |
| int i2c_fd = -1; | |
| // Default RPi B device name for the I2C bus exposed on GPIO2,3 pins (GPIO2=SDA, GPIO3=SCL): | |
| const char *i2c_fname = "/dev/i2c-1"; | |
| // Returns a new file descriptor for communicating with the I2C bus: | |
| int i2c_init(void) { | |
| if ((i2c_fd = open(i2c_fname, O_RDWR)) < 0) { | |
| char err[200]; | |
| sprintf(err, "open('%s') in i2c_init", i2c_fname); | |
| perror(err); | |
| return -1; | |
| } | |
| // NOTE we do not call ioctl with I2C_SLAVE here because we always use the I2C_RDWR ioctl operation to do | |
| // writes, reads, and combined write-reads. I2C_SLAVE would be used to set the I2C slave address to communicate | |
| // with. With I2C_RDWR operation, you specify the slave address every time. There is no need to use normal write() | |
| // or read() syscalls with an I2C device which does not support SMBUS protocol. I2C_RDWR is much better especially | |
| // for reading device registers which requires a write first before reading the response. | |
| return i2c_fd; | |
| } | |
| void i2c_close(void) { | |
| close(i2c_fd); | |
| } | |
| // Write to an I2C slave device's register: | |
| int i2c_write(u8 slave_addr, u8 reg, u8 data) { | |
| int retval; | |
| u8 outbuf[2]; | |
| struct i2c_msg msgs[1]; | |
| struct i2c_rdwr_ioctl_data msgset[1]; | |
| outbuf[0] = reg; | |
| outbuf[1] = data; | |
| msgs[0].addr = slave_addr; | |
| msgs[0].flags = 0; | |
| msgs[0].len = 2; | |
| msgs[0].buf = outbuf; | |
| msgset[0].msgs = msgs; | |
| msgset[0].nmsgs = 1; | |
| if (ioctl(i2c_fd, I2C_RDWR, &msgset) < 0) { | |
| perror("ioctl(I2C_RDWR) in i2c_write"); | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| // Read the given I2C slave device's register and return the read value in `*result`: | |
| int i2c_read(u8 slave_addr, u8 reg, u8 *result) { | |
| int retval; | |
| u8 outbuf[1], inbuf[1]; | |
| struct i2c_msg msgs[2]; | |
| struct i2c_rdwr_ioctl_data msgset[1]; | |
| msgs[0].addr = slave_addr; | |
| msgs[0].flags = 0; | |
| msgs[0].len = 1; | |
| msgs[0].buf = outbuf; | |
| msgs[1].addr = slave_addr; | |
| msgs[1].flags = I2C_M_RD | I2C_M_NOSTART; | |
| msgs[1].len = 1; | |
| msgs[1].buf = inbuf; | |
| msgset[0].msgs = msgs; | |
| msgset[0].nmsgs = 2; | |
| outbuf[0] = reg; | |
| inbuf[0] = 0; | |
| *result = 0; | |
| if (ioctl(i2c_fd, I2C_RDWR, &msgset) < 0) { | |
| perror("ioctl(I2C_RDWR) in i2c_read"); | |
| return -1; | |
| } | |
| *result = inbuf[0]; | |
| return 0; | |
| } |
How to get the reg address for the i2c slave device?
I've just singed in to github to thank you Sr. this helped me a lot. I was using the example below but it did not work.
if (read(file, buf, 2) != 2) {
/* ERROR HANDLING: i2c transaction failed
std::cout << "Failed to Read Address " << std::endl;
}
It was just until i read this post that I realized that I was doing something something wrong. Now the communication with the peripheral from my beaglebone black seems to be working.
This code works very well. Thank you for sharing with us
I get erroes:
--Multiple definition of 'i2c_fd'
--Multiple definition of 'i2c_fname'
How can i fix it?..
Thank you for the code. It just worked on my Raspberry 4 first time. Code is a nice simple Read/Write and it straight forward.
Great stuff.
Two quick questions.
-
Is there a way to send len bytes directly without allocating a buffer of len+1 bytes, filling it in, then sending.
-
Why use inbuf instead of msgs[1].buf = result.
Hi,
It is possible to write and read in one operation ioctl(i2c_fd, I2C_RDWR, &msgset)?
I mean, write value to reg and read it to verify it was written correctly.