i2c User Space Application

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i2c User Space Application

Jump to solution
4,063 Views
ritesh_panchal
Contributor I

I am using imx6qsabresd board.

I want to develop user space application to access on board i2c based mma8451q 3-Axis Orientation/Motion Detection Sensor.

I am using eclipse for development.

Below is my code for that.

#include <stdlib.h>

#include <stdio.h>

#include <linux/i2c-dev.h>

#include <fcntl.h>

#define SLAVE_ADDRESS 0x1D

// I2C Linux device handle

int g_i2cFile;

// open the Linux device

void i2cOpen()

{

  g_i2cFile = open("/dev/i2c-0", O_RDWR);

  if (g_i2cFile < 0) {

  perror("i2cOpen");

  puts("I2C Open Failed");

  exit(1);

  }

  else

  puts("I2C Open Success");

}

// close the Linux device

void i2cClose()

{

  close(g_i2cFile);

}

// set the I2C slave address for all subsequent I2C device transfers

void i2cSetAddress(int address)

{

  if (ioctl(g_i2cFile, I2C_SLAVE, address) < 0) {

  perror("i2cSetAddress");

  puts("I2C Set Address Failed");

  exit(1);

  }

  else

  puts("I2C Set Address Success");

}

int main(void) {

  unsigned char res,i;

        puts("MMA8451Q Accelerometer Test Program"); /* prints Hello World */

        i2cOpen();

        i2cSetAddress(SLAVE_ADDRESS);

        res = i2c_smbus_read_byte_data(g_i2cFile, 0x0D);

        printf("Result= %d\n\r\n\r", res);

        i2cClose();

        return 0;

}

First function i2c_smbus_read_byte_data() cannot be found by eclipse.

So i searched around and found solution. I run "sudo apt-get install libi2c-dev" and replace i2c_dev.h in "/opt/poky/1.8/sysroots/cortexa9hf-vfp-neon-poky-linux-gnueabi/usr/include/linux" from newly created i2c_dev.h in "/usr/include/linux".

Now i can successfully compile the code.

So is this a right step?

And the output of the code is

MMA8451Q Accelerometer Test Program

I2C Open Success

I2C Set Address Success

Result= 255

It should be 0x1A (Device ID).

I am getting 255 result fro all the address.

So whats wrong in this code?

0 Kudos
1 Solution
1,780 Views
BrilliantovKiri
Senior Contributor I

bool I2C::read(unsigned char addr, unsigned char reg,

                unsigned short &val, bool msb) const

{

    i2c_rdwr_ioctl_data data;

    i2c_msg msgs[2];

    __u8 buf[sizeof(__u8) * 2] = {reg, 0};

  

    if (-1 == _fd)

        return false;

    msgs[0].addr = static_cast<__u16>(addr);

    msgs[0].buf = buf;

    msgs[0].flags = 0;

    msgs[0].len = static_cast<__u16>(sizeof(unsigned char));

    msgs[1].addr = static_cast<__u8>(addr);

    msgs[1].flags = I2C_M_RD;

    msgs[1].len = static_cast<__u16>(sizeof(unsigned short));

    msgs[1].buf = buf;

    data.msgs = msgs;

    data.nmsgs = 2;

    if (-1 == ioctl(_fd, I2C_RDWR, &data))

        return false;

    val = (buf[msb ? 1 : 0] << 8) | buf[msb ? 0 : 1];

    return true;

}

View solution in original post

0 Kudos
4 Replies
1,781 Views
BrilliantovKiri
Senior Contributor I

bool I2C::read(unsigned char addr, unsigned char reg,

                unsigned short &val, bool msb) const

{

    i2c_rdwr_ioctl_data data;

    i2c_msg msgs[2];

    __u8 buf[sizeof(__u8) * 2] = {reg, 0};

  

    if (-1 == _fd)

        return false;

    msgs[0].addr = static_cast<__u16>(addr);

    msgs[0].buf = buf;

    msgs[0].flags = 0;

    msgs[0].len = static_cast<__u16>(sizeof(unsigned char));

    msgs[1].addr = static_cast<__u8>(addr);

    msgs[1].flags = I2C_M_RD;

    msgs[1].len = static_cast<__u16>(sizeof(unsigned short));

    msgs[1].buf = buf;

    data.msgs = msgs;

    data.nmsgs = 2;

    if (-1 == ioctl(_fd, I2C_RDWR, &data))

        return false;

    val = (buf[msb ? 1 : 0] << 8) | buf[msb ? 0 : 1];

    return true;

}

0 Kudos
1,780 Views
ritesh_panchal
Contributor I

Thanks for the Reply.

I am not getting the 0 for all register read.

Below is my program. I modified to clear eclipse compilation error.

void I2C_read(unsigned char addr, unsigned char reg, unsigned char msb)

{

    __u16 val;

  struct i2c_rdwr_ioctl_data data;

    struct i2c_msg msgs[2];

    __u8 buf[sizeof(__u8) * 2] = {reg, 0};

    msgs[0].addr = (__u16)(addr);

    msgs[0].buf = buf;

    msgs[0].flags = 0;

    msgs[0].len = (__u16)(sizeof(unsigned char));

    msgs[1].addr = (__u8)(addr);

    msgs[1].flags = I2C_M_RD;

    msgs[1].len = (__u16)(sizeof(unsigned short));

    msgs[1].buf = buf;

    data.msgs = msgs;

    data.nmsgs = 2;

    if (-1 == ioctl(g_i2cFile, I2C_RDWR, &data))

    {

    }

    val = (buf[msb ? 1 : 0] << 8) | buf[msb ? 0 : 1];

    printf("Result = %d\n\r", val);

}

I2C_read(0x0D,0x00,0);

the result:

MMA8451Q Accelerometer Test Program

I2C Open Success

I2C Set Address Success

Result= 0

I got 0 for all address.

Also tried for I2C_read(0x0D,0x00,1); but thje result is 0.

Whats wrong in my code?

Sensor Datasheet

http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8451Q.pdf

Refer Page19 i am reading register 0x0D.

0 Kudos
1,780 Views
BrilliantovKiri
Senior Contributor I

Why you use address 0xD if datasheet describe 0x1C and 0x1D?

I think you can use register 0xD (WHO_AM_I) for check programm, it should return 0x1A.

0 Kudos
1,780 Views
ritesh_panchal
Contributor I

Ya. That's my mistake.

I figured it out.

The device address is 0x1C. And if i try to open it will give message "device or resource busy".

This device driver is added as build in in kernel. So i unable to remove it. So i can't able to open i2c.

So i modify kernel configuration. And Add other i2c based MAG3110 (Digital Compass) as module.

I tried for adding MMA8451Q as module but bitbake giving me error.

And after restart i remove the module. And Run Program with correct device id.

And i am getting the Right Result.

Thanks.

But now i want to use MAC3110 kernel driver API in my application code.

Actually i am new to linux field.

So can you guide me how to so that?

0 Kudos