I've tried to compile a single program in C to read and write to a device through I2C bus but I'm getting this error:
Error: undefined reference to i2c_smbus_read_byte_data
I have already installed these packages: libi2c-dev
and i2c-tools
.
I'm using Ubuntu and arm-linux-gnueabi-gcc compiler (cross compile with Eclipse Luna IDE)
Here is the whole code:
/*
http://www.zerozone.it/2014/05/primi-esperimenti-con-la-beaglebone-black-collegare-10dof-via-i2c/
DOF10 I2C Test program
v0.1 - 05.05.2014
I wrote this program just to test DOF10 funcionality with my BeagleBone Black.
You can buy DOF10 module and a beagleBone from eBay with few dollars...have fun !
Written by Michele <o-zone@zerozone.it> Pinassi
BLOG @ www.zerozone.it
Feel free to use this code as you want. No any warranty, in any case: use at your own risks !
*/
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#define DEBUG
#define L3G4200D_I2C_ADDR 0x69
#define ADXL345_I2C_ADDR 0x53
typedef signed char s8;
typedef unsigned char u8;
typedef signed short s16;
typedef unsigned short u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long s64;
typedef unsigned long u64;
int i2cHandle; // Bus I2C file handle
int I2C_setAddress(unsigned char deviceAddr) {
if (ioctl(i2cHandle, I2C_SLAVE, deviceAddr) < 0) {
printf("Error while set I2C address 0x%x: %d error\n",deviceAddr,errno);
return -1;
}
return 0;
}
unsigned char I2C_readByte(unsigned char deviceAddr,unsigned char regAddr) {
unsigned char res;
I2C_setAddress(deviceAddr);
res = i2c_smbus_read_byte_data(i2cHandle,regAddr);
#ifdef DEBUG
printf("[DEBUG] 0x%x @ 0x%x => 0x%x\n",deviceAddr,regAddr,res);
#endif
return res;
}
int I2C_writeWord(unsigned char deviceAddr, __u8 regAddr, __u16 value) {
int res;
I2C_setAddress(deviceAddr);
res = i2c_smbus_write_word_data(i2cHandle, regAddr, value);
if(res < 0) {
printf("Error writing 0x%x to 0x%x register on i2c bus\n",value, regAddr);
return -1;
}
return 1;
}
int I2C_writeByte(unsigned char deviceAddr, __u8 regAddr, __u8 value) {
int res;
I2C_setAddress(deviceAddr);
res = i2c_smbus_write_byte_data(i2cHandle, regAddr, value);
if(res < 0) {
printf("Error writing 0x%x to 0x%x register on i2c bus\n",value, regAddr);
return -1;
}
return 1;
}
// 0: 250 dps - 1: 500 dps - 2: 2000 dps
int L3G4200D_init(char fullScale) {
if(I2C_readByte(L3G4200D_I2C_ADDR,0x0F)!=0xD3) {
printf("ERROR communicating with L3D4200D !\n");
return -1;
}
// Enable x, y, z and turn off power down:
I2C_writeByte(L3G4200D_I2C_ADDR, 0x20, 0b00001111);
// If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2:
I2C_writeByte(L3G4200D_I2C_ADDR, 0x21, 0b00000000);
// Configure CTRL_REG3 to generate data ready interrupt on INT2
// No interrupts used on INT1, if you'd like to configure INT1
// or INT2 otherwise, consult the datasheet:
I2C_writeByte(L3G4200D_I2C_ADDR, 0x22, 0b00001000);
// CTRL_REG4 controls the full-scale range, among other things:
fullScale &= 0x03;
I2C_writeByte(L3G4200D_I2C_ADDR, 0x23, fullScale<<4);
// CTRL_REG5 controls high-pass filtering of outputs, use it if you'd like:
I2C_writeByte(L3G4200D_I2C_ADDR, 0x24, 0b00000000);
}
void L3G4200D_getGyroValues() {
int x,y,z;
x = (I2C_readByte(L3G4200D_I2C_ADDR, 0x29)&0xFF)<<8; // MSB
x |= (I2C_readByte(L3G4200D_I2C_ADDR, 0x28)&0xFF); // LSB
y = (I2C_readByte(L3G4200D_I2C_ADDR, 0x2B)&0xFF)<<8;
y |= (I2C_readByte(L3G4200D_I2C_ADDR, 0x2A)&0xFF);
z = (I2C_readByte(L3G4200D_I2C_ADDR, 0x2D)&0xFF)<<8;
z |= (I2C_readByte(L3G4200D_I2C_ADDR, 0x2C)&0xFF);
printf("L2D4200D = X:%d Y:%d Z:%d\n",x,y,z);
}
void ADXL345_init() {
// Set +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
I2C_writeByte(ADXL345_I2C_ADDR,0x31,0x01);
// Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
I2C_writeByte(ADXL345_I2C_ADDR,0x2D,0x08);
}
void ADXL345_readAccel() {
int x,y,z;
// each axis reading comes in 10 bit resolution, ie 2 bytes. LSB first, MSB next
x = (I2C_readByte(ADXL345_I2C_ADDR, 0x33)&0xFF)<<8; // MSB
x |= (I2C_readByte(ADXL345_I2C_ADDR, 0x32)&0xFF); // LSB
y = (I2C_readByte(ADXL345_I2C_ADDR, 0x35)&0xFF)<<8; // MSB
y |= (I2C_readByte(ADXL345_I2C_ADDR, 0x34)&0xFF); // LSB
z = (I2C_readByte(ADXL345_I2C_ADDR, 0x37)&0xFF)<<8; // MSB
z |= (I2C_readByte(ADXL345_I2C_ADDR, 0x36)&0xFF); // LSB
printf("ADXL345 = X:%d Y:%d Z:%d\n",x,y,z);
}
void main(int argc, char *argv[]) {
char filename[20];
printf("Open I2C bus...");
snprintf(filename, 19, "/dev/i2c-1");
i2cHandle = open(filename, O_RDWR);
if (i2cHandle < 0) {
printf("Error while opening device %s: %d error\n",filename,errno);
exit(1);
}
printf("OK !\nInitializing L3G4200D...");
L3G4200D_init(2);
printf("OK !\nInitializing ADXL345...");
ADXL345_init();
printf("OK !\n");
while(1) {
L3G4200D_getGyroValues();
ADXL345_readAccel();
sleep(1);
}
close(i2cHandle);
}
I created another topic with title and more appropriate/clear details:
How to resolve the link error "undefined reference to `i2c_smbus_read_byte_data'"
If the library is installed properly then this looks like a linker issue by all means.
You can verify that i2c_smbus_read_byte_data()
is defined in
Linux/drivers/i2c/i2c-core.c
and has a function prototype in,
include/linux/i2c.h
So may be you could do a
#include <linux/i2c.h>