-
-
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; | |
} |
Yes, reg
is the register number to write to or read from. Which register number you want is documented by your I2C device you're talking to and what you're trying to achieve. It's device specific.
I've put
memset(msgs, 0, sizeof(msgs));
memset(msgset, 0, sizeof(msgset));
after declaration, to prevent valgrind from running wild for each call. Hope, it is not that wrong.
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.
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.
Hi..
I am new to this ioctl calling..
in the below function declaration
int i2c_read(u8 slave_addr, u8 reg, u8 *result)
what is reg here..If it is register then how do we find out this register for some i2c?