tsaG
Posts: 80
Joined: Thu Jun 26, 2014 1:30 pm

I2C not reliable

Wed Jul 27, 2016 11:43 pm

Hi,

Im using Wiringpi in my QT application. However, there are 2 values which are not reliable readable.

Here is my terminal Output. I ran the application twice, you can see that there are two different values for days and hour

Code: Select all

[email protected]:/opt/mEICAS/bin $ sudo ./mEICAS
QML debugging is enabled. Only use this in a safe environment.
Unable to query physical screen size, defaulting to 100 dpi.
To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).
Connection Handerl: 12
Hardware ID:  1
[...]
Month of year:  135
day of month:  27
day Bits  0 : 0
day Bits  1 : 0
day Bits  2 : 0
day Bits  3 : 1
day Bits  4 : 1
day Bits  5 : 0
day Bits  6 : 1
day Bits  7 : 1
minute:  156
seconds:  185
hour:  23


^[email protected]:/opt/mEICAS/bin $ sudo ./mEICAS
QML debugging is enabled. Only use this in a safe environment.
Unable to query physical screen size, defaulting to 100 dpi.
To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).
Connection Handerl: 12
Hardware ID:  1
[...]
Month of year:  7
day of month:  155
day Bits  0 : 1
day Bits  1 : 0
day Bits  2 : 0
day Bits  3 : 1
day Bits  4 : 1
day Bits  5 : 0
day Bits  6 : 1
day Bits  7 : 1
minute:  29
seconds:  12
hour:  151

As Slave, Im using an Arduino zero (ATSAMD21G16A) style MCU.

Here is my Code on the Arduino

Code: Select all

void receiveEvent(int howMany) {
  while (Wire.available())
  {
    // read I2C value
    requestedByte = Wire.read();
  }
}
void requestEvent()
{
  switch (requestedByte) {
    case 1: { //Sends the Device Name
        String DeviceName = NAME;
        uint8_t buf [DeviceName.length() + 1]; //Create Buffer with length +1
        DeviceName.getBytes(buf, DeviceName.length() + 1); //Convert String to Char Array
        for (int i = 0; i < sizeof buf; i++) {
          Wire.write(buf[i]);
        }
        break;
      }
    case 2: { //Sends the Device Hardware ID (Serial)
        Wire.write(ID);
        break;
      }
    case 3: { //Sends the Device Hardware Version
        Wire.write(HARDVERSION);
        break;
      }
    case 4: { //Sends the Device Software Version
        Wire.write(SOFTVERSION);
        break;
      }
    case 5: { //Send several status values
        bool r0 = gps.location.isValid();
        bool r1 = gps.date.isValid();
        bool r2 = gps.time.isValid();
        bool r3 = 0;
        bool r4 = 0;
        bool r5 = 0;
        bool r6 = 0;
        bool r7 = 0;
        char statusByte = (r0 << 7) | (r1 << 6) | (r2 << 5) | (r3 << 4) | (r4 << 3) | (r5 << 2) | (r6 << 1) | r7;
        Wire.write(statusByte);
        break;
      }
    case 6: { //Sends the Device Software Version
        I2cInt32Write(gps.altitude.feet());
        break;
      }
    case 7: { //Sends the GPS latitude (double)
        I2cInt32Write(gps.location.lat());
        break;
      }
    case 8: { //Sends the GPS longitude (double)
        I2cInt32Write(gps.location.lng());
        break;
      }
    case 9: { //Sends the GPS speed in knots (double)
        I2cInt32Write(gps.speed.knots());
        break;
      }
    case 10: { //Sends the GPS course in degree (double)
        I2cInt32Write(gps.course.deg());
        break;
      }
    case 11: { //Sends the GPS year (uint16_t)
        I2cInt32Write(gps.date.year());
        break;
      }
    case 12: { //Sends the GPS month (uint8_t)
        Wire.write(gps.date.month());
        break;
      }
    case 13: { //Sends the GPS day (uint8_t)
        Wire.write(gps.date.day());
        break;
      }
    case 14: { //Sends the GPS hour of the day (uint8_t)
        Wire.write(gps.time.hour());
        break;
      }
    case 15: { //Sends the GPS minute of the day (uint8_t)
        Wire.write(gps.time.minute());
        break;
      }
    case 16: { //Sends the GPS second of the day (uint8_t)
        Wire.write(gps.time.second());
        break;
      }
  }
}

void I2cIntWrite(int bigVal) {
  Wire.write((byte *)&bigVal, sizeof(int));
}
void I2cInt32Write(int32_t bigVal) {
  Wire.write((byte *)&bigVal, sizeof(int32_t));
}
My code on the app:

Code: Select all

void mainBoard::readMCU()
{

    int handler = wiringPiI2CSetup(MCUAdress);//initialize the MCU on the I2C Bus
    if(handler == -1) {
        qDebug("I2C connection failed.");
    }

    ID =  wiringPiI2CReadReg8(handler, 0x02);
    qDebug() << "Hardware ID: " << ID;

   ...

    day =  wiringPiI2CReadReg8(handler, 0xD); //get the day
    qDebug() << "day of month: " << day;
    for (int i = 0; i < 8; i++) {  // Extract the bits
        statusBits[7-i] = (day >> i) & 1;  //shift each bit and store it

    }
     // For debug purposes,print the received data
    for (int i = 0; i < 8; i++) {
    qDebug() << "day Bits " << i << ":"  << statusBits[i];
    }

    hour =  wiringPiI2CReadReg8(handler, 0xE); //get the hour
    qDebug() << "hour: " << hour;
}
As you can see on the month value which is also split into bits, the first bit is swapped. I can verify that the Arduino sends 00011011 using my oscilloscpe, the Raspberry receives 10011011. Is there anything I can tweak? I planned to increase the I2C speed, of course after it works reliable.

tsaG
Posts: 80
Joined: Thu Jun 26, 2014 1:30 pm

Re: I2C not reliable

Thu Jul 28, 2016 12:04 am

I got it working! It looks like the default speed of the I2C Port is to slow (?). I set it to 1Mhz, now it is working flawlessly :)

EDIT: Maybe I can use this thread for another question. How do I read a 32bit Value using WiringPi?

My Arduino is sending it in 4 bytes. I tried to read it like this:

Code: Select all

    
int32_t altitudeLow =  wiringPiI2CReadReg16(handler, 0x6); //get the year
int8_t altitude1Low = wiringPiI2CRead(handler);
int8_t altitude1high= wiringPiI2CRead(handler);
But this just gives me
altituteLow: 92
altitute1Low = -118
altitute1high = -118

The Arduino part looks like this

Code: Select all

[...]
case 6: { //Sends the GPS altitude
        I2cInt32Write(gps.altitude.feet());
        break;
      }
[...]
void I2cInt32Write(int32_t bigVal) {
  Wire.write((byte *)&bigVal, sizeof(int32_t));
}

christian-nils
Posts: 11
Joined: Wed Jun 22, 2016 9:27 am

Re: I2C not reliable

Thu Jul 28, 2016 5:46 am

Hello,

I just post to say that I had a problem with the i2c baudrate as well. I had to set it to 2Mbps to make the communication work. However the i2c slave device that I use is supposed to work between 100 and 400kbps...

Greetings,

Christian-Nils

christian-nils
Posts: 11
Joined: Wed Jun 22, 2016 9:27 am

Re: I2C not reliable

Thu Jul 28, 2016 5:58 am

tsaG wrote:
EDIT: Maybe I can use this thread for another question. How do I read a 32bit Value using WiringPi?

My Arduino is sending it in 4 bytes. I tried to read it like this:

Code: Select all

    
int32_t altitudeLow =  wiringPiI2CReadReg16(handler, 0x6); //get the year
int8_t altitude1Low = wiringPiI2CRead(handler);
int8_t altitude1high= wiringPiI2CRead(handler);
[/code]
Instead of ReadReg16, you might be able to use Read instead.
If you send the register with the Write command first.

Code: Select all

wiringPiI2CWrite(handler, 0x6);
int32_t altitudeLow =  wiringPiI2CRead(handler); //get the year
Another alternative would be to use the SMBus protocol (https://www.kernel.org/doc/Documentatio ... s-protocol) instead of WiringPi.

/CN

tsaG
Posts: 80
Joined: Thu Jun 26, 2014 1:30 pm

Re: I2C not reliable

Thu Jul 28, 2016 11:24 am

Hi!

Thanks for the hint to the SMBUS protocoll, I got rid of Wiringpi and I got it working! Now I can read the double ( which is actually 8 byte :) ) over I2C

Here is a part of my program:

Code: Select all

#include <linux/i2c-dev.h> //include this file for native I2C

void mainBoard::readMCU()
{
    int opResult = 0;   // for error checking of operations

    // Create a file descriptor for the I2C bus
    int i2cHandle = open("/dev/i2c-1", O_RDWR);
    if (i2cHandle < 0){
        qDebug() << "Error whileopening port";
        exit(-1);
    }
    // maybe not needed? tell that we are not using a 10 bit Address
    opResult = ioctl(i2cHandle, I2C_TENBIT, 0);

    // Set the device address
    opResult = ioctl(i2cHandle, I2C_SLAVE, MCUAdress);
    if (opResult < 0){
        qDebug() << "Error while setting the Address";
        exit(-1);
    }

    //read the ID
    ID = i2c_smbus_read_byte_data(i2cHandle, 0x02);
    qDebug() << "Hardware ID: " << ID;

    hardwareRev =  i2c_smbus_read_byte_data(i2cHandle, 0x03);
    qDebug() << "Hardware Revision: " << hardwareRev;

    softwareRev =  i2c_smbus_read_byte_data(i2cHandle, 0x04);
    qDebug() << "Software Revision: " << softwareRev;

    int statusBytes =  i2c_smbus_read_byte_data(i2cHandle, 0x05);
    qDebug() << "Status Byte: " << statusBytes;
    for (int i = 0; i < 8; i++) {  // Extract the bits
        statusBits[7-i] = (statusBytes >> i) & 1;  //shift each bit and store it
    }

    __u8 buflat[8];
    int reslat = i2c_smbus_read_i2c_block_data(i2cHandle, 0x07, 8, (__u8 *)buflat); //read 8 times 1 byte
   latitude = *reinterpret_cast<double*>(buflat);  //put those 8 bytes into one double.
    qDebug() <<"Latitude" << latitude;

}

christian-nils
Posts: 11
Joined: Wed Jun 22, 2016 9:27 am

Re: I2C not reliable

Thu Jul 28, 2016 12:27 pm

Super! Good job! :D

Return to “Interfacing (DSI, CSI, I2C, etc.)”

Who is online

Users browsing this forum: No registered users and 9 guests