12

There are many references to using i2c_smbus_ functions when developing embedded Linux software to communicate on the I2C bus. When i2c_smbus functions such as i2c_smbus_read_word_data are referenced in software project for ARM8 processor errors such as ‘i2c_smbus_read_word_data’ was not declared in this scope are generated at compile.

Investigation of the following header files indicate the absence of most i2c_smbus function definition.

  • /usr/arm-linux-gnueabi/include/linux/i2c.h
  • /usr/arm-linux-gnueabi/include/linux/i2c-dev.h

Also in that following reference i2c.h file has all the i2c_smbus defined.

How can this problem be resolved?

Research references

  1. Using I2C from userspace in Linux
  2. I2C Communication from Linux Userspace – Part II
  3. I2C dev interface
Mahendra Gunawardena
  • 1,956
  • 5
  • 26
  • 45
  • The quickest google ever shows that you need to include . – Vicky Aug 06 '14 at 11:36
  • I don't see i2c-smbus.h included in either of the above arm-linux-gnueabi paths. – Mahendra Gunawardena Aug 06 '14 at 11:44
  • The file was added to the **kernel** in 2010 as include/linux/i2c-smbus.h **however having it in the kernel sources doesn't necessarily mean it will be in your userspace include directories on a given system** For reference, mainline commit is here https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/include/linux/i2c-smbus.h?id=b5527a7766f0505dc72efe3cefe5e9dea826f611 – Chris Stratton Aug 06 '14 at 15:01
  • But I don't see functions as i2c_smbus_read_byte_data defined in i2c-smbus.h. But do see these functions defined in i2c.h per the attach link. http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/include/linux/i2c.h#L80. I was wondering how to update the library files /usr/arm-linux-gnueabi/include/linux/i2c.h to include i2c_smbus functions. I am not sure if it possible. I have posted a question on ask.ubuntu c if there is a process to update the arm-linux-gnueabi libraries. http://askubuntu.com/questions/507628/how-to-update-usr-arm-linux-gnueabi-include-libraries-on-ubuntu-12-04-lts – Mahendra Gunawardena Aug 06 '14 at 16:37
  • @MahendraGunawardena Are you implementing the driver in user-space or in kernel space? – raghav3276 Aug 08 '14 at 05:10
  • @raghav3276 Userspace. – Mahendra Gunawardena Aug 08 '14 at 19:01
  • @MahendraGunawardena Mostly, the I2C functions from user-space are controlled and accessed using `ioctl()`, `read()` and `write()`. I recommend you to go through the Linux Documentation itself, on how to access the i2c devices from userspace : http://lxr.free-electrons.com/source/Documentation/i2c/dev-interface – raghav3276 Aug 09 '14 at 07:39
  • @raghav3276, I used read() and write() to get the program working. I have published the base code at https://github.com/mahengunawardena/BeagleboneBlack_I2C_ADXL345. Can you please point me understand how to use i2c_smbus_read_word_data. Looks like the smbus library is far more capable. I like to know how to get smbus library installed. Am I correct to assume that smbus is used in kernel space. – Mahendra Gunawardena Aug 09 '14 at 09:28
  • @MahendraGunawardena Yes, those functions are generally for kernel space. But, the same implementation has been carried onto the user space as well. If you observe the syntax of the user-space `i2c_smbus_*()` functions, they accept a 'file descriptor' as their first argument, unlike the kernel space functions which accept the `i2c_client` as its argument. For example `i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command)`(kernel space), `i2c_smbus_read_byte_data(int file, __u8 command)`(user space). – raghav3276 Aug 11 '14 at 04:09
  • @MahendraGunawardena You can make use of the functions, by installing `i2c_tools` and `libi2c-dev` packages. – raghav3276 Aug 11 '14 at 04:14
  • @raghav3276, thank you. I will install libi2c-dev and see if it will give access to the smbus functions. I already have i2c-tools installed. – Mahendra Gunawardena Aug 12 '14 at 00:10

4 Answers4

17

Because you are using a wrong header file for your application.

If you see an extern on the function i2c_smbus_read_word_data() in your header, it's a header file for your kernel, but not for your application. The Linux kernel has i2c_smbus_read_word_data() and other i2c smbus functions for its internal use. But they are a) not system calls, or b) not accessible from your application.

Instead, get i2c-tools from Linux Kernel Wiki and install it. If you are using Debian, just

sudo apt-get install libi2c-dev

and use i2c_smbus_read_word_data() or any other interfaces they offer.

Version Notes

i2c-dev, untill version 3.x, used be a header only package, meaning that there was no library to link to. All functions were inline functions defined using ioctl().

e.g.)

static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
                                     int size, union i2c_smbus_data *data)
{
        struct i2c_smbus_ioctl_data args;

        args.read_write = read_write;
        args.command = command;
        args.size = size;
        args.data = data;
        return ioctl(file,I2C_SMBUS,&args);
}
   :
static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
{
        union i2c_smbus_data data;
        if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
                             I2C_SMBUS_WORD_DATA,&data))
                return -1;
        else
                return 0x0FFFF & data.word;
}

But since v4.0, it start to be a standard shared library with libi2c.so.0 and i2c/smbus.h. You have to include the header file in your source code

#include <i2c/smbus.h>

And link libi2c.so.0 with -li2c

gcc -o a.out main.o -li2c
Yasushi Shoji
  • 4,028
  • 1
  • 26
  • 47
  • 1
    Some seven years later... I had to link to `i2c` (https://stackoverflow.com/questions/50154296/undefined-reference-to-i2c-smbus-read-word-dataint-unsigned-char) – Ryan H. Sep 08 '21 at 18:44
  • 1
    Thanks @RyanH., I've added version 4.0 and newer in "Version Notes" – Yasushi Shoji Sep 09 '21 at 11:51
3

I ran into this today. The i2c_smbus_* functions are defined in:

/usr/include/linux/i2c-dev.h

...but when I would try to cross-compile for ARM on an older version of Ubuntu, I was running into errors such:

i2c_smbus_read_block_data was not declared in this scope

Turns out the functions are not defined in the equivalent ARM-specific location:

/usr/arm-linux-gnueabi/include/linux/i2c-dev.h

When cross-compiling, this 2nd older header file is the one used. Had to re-declare locally a few of the inline i2c_smbus_... functions to get around the problem.

Stéphane
  • 19,459
  • 24
  • 95
  • 136
3

Based on https://unix.stackexchange.com/questions/621854/usr-include-linux-i2c-dev-h-does-not-contain-i2c-smbus-read-word-data-functio, I have found this fixes the function not defined errors:

#include <i2c/smbus.h>

I am currently working with legacy code that references various i2c_smbus functions. It has:

#include <linux/i2c-dev-user.h>

and it fails to compile. Surely, this include used to work, but it seems the lib's header files changed at some point. I did refresh/reinstall libi2c-dev recently.

Note that I added the above include. I can't remove the original include. It is still needed.

FYI: I have not tried cross-compiling yet.

steve
  • 1,021
  • 1
  • 14
  • 29
2

From the i2c Linux kernel documentation:

Please note that there are two files named "i2c-dev.h" out there, one is distributed with the Linux kernel and is meant to be included from kernel driver code, the other one is distributed with i2c-tools and is meant to be included from user-space programs. You obviously want the second one here.

So you need to include the i2c-dev.h from i2c-tools not from the Linux kernel.

jcoffland
  • 5,238
  • 38
  • 43