Last active
March 7, 2025 23:13
-
-
Save JamesDunne/9b7fbedb74c22ccc833059623f47beb7 to your computer and use it in GitHub Desktop.
C library for reading/writing I2C slave device registers from Raspberry Pi 1 Model B
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
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.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to get the reg address for the i2c slave device?