Search code examples
qtembeddedembedded-linuxioctli2c

Cannot read i2c device properly


I am trying to write an embedded qt application that reads the specific i2c rtc device. Here is my code to init i2c:

int addr = 0x68;        // The I2C address of the RTC

sprintf(filename,I2C_FILE_NAME);
if ((file = open(filename,O_RDWR)) < 0)
{
    qDebug()<<"Failed to open the bus.";
    return;
}

if (ioctl(file,I2C_SLAVE_FORCE,addr) < 0)
{
    qDebug()<<"Failed to acquire bus access and/or talk to slave.\n";
    return;
}

To read from device:

unsigned char addr = 0x68;
unsigned char reg = 0x00;
unsigned char inbuf[2], outbuf;

struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[2];

/*
* In order to read a register, we first do a "dummy write" by writing
* 0 bytes to the register we want to read from.  This is similar to
* the packet in set_i2c_register, except it's 1 byte rather than 2.
*/
outbuf = reg;
messages[0].addr  = addr;
messages[0].flags = 0;
messages[0].len   = sizeof(outbuf);
messages[0].buf   = &outbuf;
/* The data will get returned in this structure */
messages[1].addr  = addr;
messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;
messages[1].len   = 2;
messages[1].buf   = inbuf;
/* Send the request to the kernel and get the result back */
packets.msgs      = messages;
packets.nmsgs     = 2;
if(ioctl(file, I2C_RDWR, &packets) < 0)
{
    qDebug()<<"Unable to send data";
    return;
}
qDebug() << inbuf[0];

What I am trying to do is just read rtc device's register that holds the "seconds". What I get is some numbers but those numbers looks good at first but there is some weird incrementation. Like, 55,56,56,57 then it jumps to 64? then it is going up to 89 then 0? I don't know why this happens or what is wrong with my code?


Solution

  • The problem is that the register doesn't hold a simple count for the number of seconds. The upper bits hold tens of seconds and the lower bits hold unit seconds.

    You can obtain tens of seconds with (inbuf[0] >> 4) & 0x7; and unit seconds with inbuf[0] & 0xf.

    Instead of trying to print seconds with qDebug() << inbuf[0];, use something like:

    qDebug() << (10 * ((inbuf[0] >> 4) & 0x7) + (inbuf[0] & 0xf));