Tzarls
Authorised Reseller
Authorised Reseller
Posts: 263
Joined: Tue Feb 26, 2013 6:59 am

I2C - Small percentage of corrupted data

Mon Mar 20, 2017 2:18 am

Hi. I´m trying to have my Pi3 receive data from an Adafruit Trinket (3v version) using I2C. Basically the Trinket is counting form 0 to 1023. Everytime I send a message to it it adds 1 to the counter and stores the number in 2 registers. Then from the RPi I send 2 requests to read the value - 2 requests because on the Trinket the number is stored using 2 bytes. On the Pi I reassemble the number and print it to the screen. The programs I´ve written for this work fine most of the time, but every once in a while the byte corresponding to the LSB "looses" its leftmost bit - instead of going from 0 to 255 it goes up to 127, then goes back 0 and up to 127 again.... It happens about 6 to 10 times for every 10000 transactions. Of course this alters the resulting number I receive.

I tried to do this first in Python and the problem was always present - meaning the LSB always went from 0 to 127 twice before the MSB had 1 added to it. The I found some posts on the internet stating that Python was too slow for it to be able to use I2C correctly so I re-wrote everything in C++. I got far better results but there´s the occasional hicup.

The connections are pretty simple: The Trinket is being powered by the RPi using one of the ground pins and one of the 5v pins (the Trinket´s on board regulators get it down to 3v3). Then 2 simple jumper wires connec SDA and SCL on the RPi to the corresponding pins on the Trinket. The trinket is mounted on a protoboard and the Rpi is also connected using the protoboard and a T-Cobbler. The T-cobbler is connected to the RPi with a 40 wire flat cable.

This is the code used for the Trinket:

Code: Select all

#include <TinyWireS.h>

#define I2C_SLAVE_ADDRESS 0x04

byte reg[] = {0x00, 0x00};
byte reg_idx = 0;

int ticks = 0;
int number = 0;

void onRequest()
{
  TinyWireS.send(reg[reg_idx]);
  reg_idx = (reg_idx == 1) ? 0 : 1;
}

void onReceive(uint8_t dataSize)
{
  if (dataSize < 1)
    return;
    
  while(TinyWireS.available())
  {
    number = TinyWireS.receive();

    if (number == 1)
    {
      //int a2 = analogRead(2);
      int a2 = ticks;
      reg[0] = lowByte(a2);
      reg[1] = highByte(a2);
      //reg[0] = a2 & 255;
      //reg[1] = a2 >> 8;

      reg_idx = 0;
        
      ticks++;
      
      if (ticks > 1023)
        ticks = 0;      
    }    
  }
}

void setup()
{
    TinyWireS.begin(I2C_SLAVE_ADDRESS);
    TinyWireS.onRequest(onRequest);
    TinyWireS.onReceive(onReceive);
}

void loop()
{
  TinyWireS_stop_check();
}
This is the C++ source(I got the original from where the credits state and then patched it all over the place as the result of the many tests I´ve performed trying to get it work 100% of the time):

Code: Select all

/******************************************************************************
i2ctest.cpp
Raspberry Pi I2C interface demo
Byron Jacquot @ SparkFun Electronics>
4/2/2014
https://github.com/sparkfun/Pi_Wedge

A brief demonstration of the Raspberry Pi I2C interface, using the SparkFun
Pi Wedge breakout board.

Resources:

This example makes use of the Wiring Pi library, which streamlines the interface
the the I/O pins on the Raspberry Pi, providing an API that is similar to the
Arduino.  You can learn about installing Wiring Pi here:
http://wiringpi.com/download-and-install/

The I2C API is documented here:
https://projects.drogon.net/raspberry-pi/wiringpi/i2c-library/

The init call returns a standard file descriptor.  More detailed configuration
of the interface can be performed using ioctl calls on that descriptor.
See the wiringPi I2C implementation (wiringPi/wiringPiI2C.c) for some examples.
Parameters configurable with ioctl are documented here:
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/i2c/dev-interface

Hardware connections:

This file interfaces with the SparkFun MCP4725 breakout board:
https://www.sparkfun.com/products/8736

The board was connected as follows:
(Raspberry Pi)(MCP4725)
GND  -> GND
3.3V -> Vcc
SCL  -> SCL
SDA  -> SDA

An oscilloscope probe was connected to the analog output pin of the MCP4725.

To build this file, I use the command:
>  g++ i2ctest.cpp -lwiringPi

Then to run it, first the I2C kernel module needs to be loaded.  This can be 
done using the GPIO utility.
> gpio load i2c 400
> ./a.out

This will run the MCP through its output range several times.  A rising 
sawtooth will be seen on the analog output.

Development environment specifics:
Tested on Raspberry Pi V2 hardware, running Raspbian.
Building with GCC 4.6.3 (Debian 4.6.3-14+rpi1)

This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!

Distributed as-is; no warranty is given.
******************************************************************************/

#include <iostream>
#include <errno.h>
#include <wiringPiI2C.h>
#include <unistd.h>

using namespace std;

int main()
{
   int fd, result, l, h;
   int num = 0;
   int prevNum = 1023;
   bool goOn = true;
   int count = 10000;
   int errors = 0;

   // Initialize the interface by giving it an external device ID.
   // The MCP4725 defaults to address 0x60.   
   //
   // It returns a standard file descriptor.
   // 
   fd = wiringPiI2CSetup(0x04);

   cout << "Init result: "<< fd << endl;

	while (count >= 0)
   {
	   count--;
      // I tried using the "fast write" command, but couldn't get it to work.  
      // It's not entirely obvious what's happening behind the scenes as
      // regards to endianness or length of data sent.  I think it's only 
      // sending one byte, when we really need two.
      //
      // So instead I'm doing a 16 bit register access.  It appears to 
      // properly handle the endianness, and the length is specified by the 
      // call.  The only question was the register address, which is the 
      // concatenation of the command (010x = write DAC output) 
      // and power down (x00x = power up) bits.
      //result = wiringPiI2CWriteReg16(fd, 0x40, (i & 0xfff) );
      
      result = wiringPiI2CWrite(fd, 1);
      if(result == -1)
      {
         cout << "Error sending.  Errno is: " << errno << endl;
         goOn = false;
	 }
	 else
	 {
		 //sleep(1);
		 l = wiringPiI2CRead(fd);
		 if(l == -1)
		 {
			 cout << "Error reading l.  Errno is: " << errno << endl;
			 goOn = false;
		 }
		 
		 h = wiringPiI2CRead(fd);
		 if(h == -1)
		 {
			 cout << "Error reading h.  Errno is: " << errno << endl;
			 goOn = false;
		 }
		 
		num = (h * 256 + l);
		cout << "Numero: " << num << "    l: " << l << "    h: " << h << endl;
		
		if (prevNum != 1023 && num - prevNum != 1)
		{
			cout << "ERROR DE NUMERO!!!!!!!!!!!!!!!!!!!!" << endl;
			//sleep(3);
			errors++;
		}
			
		prevNum = num;
	}
	//sleep(1);
  }
  cout << errors;
}
Can you spot any problem in my code that might lead to the problem I described? Could it be a timing problem? Clock conflict? Is I2C reliable and usable on the RPi?

dgordon42
Posts: 795
Joined: Tue Aug 13, 2013 6:55 pm
Location: Dublin, Ireland

Re: I2C - Small percentage of corrupted data

Tue Mar 21, 2017 6:41 pm

I've had similar problems using the I2c Bus to send and receive data between a Pi and an Arduino Leonardo.
I use Python on the Pi, both with the Python SMBus module, and with the pigpio libraries.
Summery of my results:

Code: Select all

        Results from long runs of i2c_comm_test 6b & 7b

Computer = RaspberryPi.local
Arduino Leonardo running i2c_comm_test6a.ino
Notes:-
A 'transaction' is the sequential writing and reading back
of 6 bytes from the Pi to the Arduino
I2C Bus speed = 100 kHz (Pi default)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
i2c_comm_test6b.py

Using Python SMBus for I2c communications

Recorded results:

Transactions = 530196
Data errors = 1456
Bus write errors = 618

Start = 00:37:38
End = 08:35:31

Calculated results:

Running time: 32,333 seconds
Transaction rate : 16.4 per second
Data error rate : 0.045 per second
Av. time between data errors : 22.21 seconds
Bus write error rate : 0.019 per second
Av time between bus write errors : 52.32 seconds

NOTE: the pigpiod daemon was running during these tests.
CPU usage (from htop) ~ 2%
pigpio CPU usage ~ 6%
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
i2c_comm_test7b.py

Using pigpio & pigpiod for I2c communications

Recorded results:

Transactions = 450462
Data errors = 1299

Start Time = 08:49:45
End Time = 16:44:07

Calculated results:

Running Time : 32,122 seconds
Transaction rate : 14.0 per second
Error rate : 0.040 per second
Av time between errors : 24.73 seconds
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Comparasion:

                                SMBus   pigpio
Transaction Rate:               16.4    14.0    per second
Error rate :                    0.045   0.040   per second
Av. Time between errors         22.21   24.73   seconds
So now when I code I use a 'try - except' structure in Python to catch the I2c Bus errors, and a rolling average of the last 10 readings to smooth out the data errors.

There have been one or two posts on here from people with similar experiences, but I have not seen any solutions.

Hope this helps,
Dave.

Tzarls
Authorised Reseller
Authorised Reseller
Posts: 263
Joined: Tue Feb 26, 2013 6:59 am

Re: I2C - Small percentage of corrupted data

Tue Mar 21, 2017 6:46 pm

I was thinking of encoding everything on the Trinket side to use only 7 bits of each byte to store the data, unless anyone else knows a better way. I still have to try a stronger pullup resistor - the stock ones are 1.8kOhm I think. Unless that´s strong enough.

If that doesn´t work then I´ll use the 7bit workaround. Thanks for sharing your results.

User avatar
Gavinmc42
Posts: 5079
Joined: Wed Aug 28, 2013 3:31 am

Re: I2C - Small percentage of corrupted data

Thu Mar 23, 2017 4:08 am

Never really had much luck getting reliable i2c data on Linux.
Had to put error checking in and most times multiple reads to get a reading..
Sometimes have a string of sensors on 5m cable, slowing clock rate down to 10khz helps.

Mostly these days I have moved to Ultibo for baremetal i2c comms etc
Have tested reading every 10secs for a week, not a single error :o
Much more reliable, I think something in the Linux OS messes i2c comms up.
It's not just Raspbian either, same sort of thing on piCore
I'm dancing on Rainbows.
Raspberries are not Apples or Oranges

davef
Posts: 64
Joined: Wed Feb 20, 2013 8:39 pm
Location: Christchurch, NZ

Re: I2C - Small percentage of corrupted data

Tue Apr 11, 2017 8:09 am

One of the main reasons I moved to the Raspberry Pi was flaky I2C on another Linux hardware platform. I have run I2C on the AVR ATmega series without any problems for years.

Running the latest Jessie Lite and trying to talk to a ADS1015 breakout board.

I modified code by Lewis Loflin lewis@bvu.net to use this 12bit ADC.

http://www.bristolwatch.com/rpi/ads1115.html

The breakout board circuitry is similar to the setup in the TI app note. It has 10K pullups on the SDA and SCL lines and a 10K pulling ALERT to suppy and a 10K pulling ADDR to ground. I have pulled the ADDR pin directly to ground and the ALERT pin to ground, for my tests.

The notes in Lewis's code says "the pullups on the module caused problems", but I thought maybe his module possibly had much lower value resistors. I can not easily remove the 4 * 10K as they are in one package. But if anyone suggests that these 10K pullups could cause a problem in parallel with the 1K8 pullups on the SDA and SCL lines on the RaspberryPi then I will get them off.

Now to my problem ... I can do tens of accesses and get the correct voltage reading. Then literally moving a few wires around or touching the attached breadboard ground can cause corrupted values, ie 60-70% of the actual value. When the values are corrupted I can take my finger off the ground and the values can stay corrupted for tens of accesses over say a few minute period then come right. In summary it behaves very flaky.

Can't attach pictures with enough detail, however I can see a difference between the good and the bad. The traces appear to start with a simple sequence, which I assume is the master addressing the slave. This part of the transaction appears to remain unchanged between the good and the bad. However, about half-way along the "bad" trace I can see the "lows" start creeping up and the data sequence obviously changes.

Should I be running the ADS1015 at 5V and use a level translator? Or is a I2C bus master a more robust implementation.

Any suggestions welcomed.

davef

davef
Posts: 64
Joined: Wed Feb 20, 2013 8:39 pm
Location: Christchurch, NZ

Re: I2C - Small percentage of corrupted data

Tue Apr 11, 2017 10:17 am

As it appeared quite "layout" sensitive I re-wired the I2C lines to the ADS1015. The SDA and SCL lines are about 25mm long and I now use a dedicated 3V3 (pin 1) and ground (pin 6) wires to the breakout board.

I can now poke my fingers around and hook up 'scope probes to the I2C breakout board with no changes to the indicated ADC value.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: I2C - Small percentage of corrupted data

Wed Apr 12, 2017 8:56 pm

davef wrote:As it appeared quite "layout" sensitive I re-wired the I2C lines to the ADS1015. The SDA and SCL lines are about 25mm long and I now use a dedicated 3V3 (pin 1) and ground (pin 6) wires to the breakout board.

I can now poke my fingers around and hook up 'scope probes to the I2C breakout board with no changes to the indicated ADC value.
every (and i really mean every) problem i had with i2c in years of use was linked to wiring.

and i have to admit i have some problems even now.
If i use a breadboard to connect all my i2c devices, first or then a "i2c error" will pop up.
And i have this setup in my domotics system
And when you get one, then eften it's enough to touch cables in their holes on the board to get errors..

I tried with this kind of boards:
http://www.dx.com/p/prototype-printed-c ... O6TWDuLSUk
and this kind
http://www.dx.com/p/170-points-mini-bre ... O6TXDuLSUk
and obviously also this type
http://www.dx.com/p/mini-prototype-prin ... O6TYDuLSUk

but on the other hand, when the connection is ok i never got any error.

User avatar
joan
Posts: 15254
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: I2C - Small percentage of corrupted data

Wed Apr 12, 2017 9:04 pm

@Massi

Ditto, I have had few problems in hundreds of thousands of transactions using the Linux driver on the Pi.

The only reason I can think of is because I use nice short wiring and don't suffer the electrical problems others hit through using I2C out of spec.

Massi
Posts: 1691
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: I2C - Small percentage of corrupted data

Wed Apr 12, 2017 9:16 pm

joan wrote:I have had few problems in hundreds of thousands of transactions using the Linux driver on the Pi.
i wrote a small python script (based on pigpio) with 4 concurrent threads accessing i2c to "stress" the connections.
connections ok -> NO errors at all (some "unknown handle" here and there, never felt brave enough to ask you :))
connections ko -> TONS of errors..

Definitely the quality of connections is (by far) the first thing to check for i2c transactions

may i ask what breadboard do you prefer (and do you use)? :)

User avatar
mahjongg
Forum Moderator
Forum Moderator
Posts: 13557
Joined: Sun Mar 11, 2012 12:19 am
Location: South Holland, The Netherlands

Re: I2C - Small percentage of corrupted data

Wed Apr 12, 2017 9:29 pm

what could, I repeat could, be the problem is that the Pullups for I2C on the raspberry PI pull the I2C clock and data signal up to 3.3Volt, NOT to the more common 5.0 Volt. This means that any I2C device on that 3V3 level I2C bus MUST reliably accept a 3.3V signal as "high". Sometimes the I2C device expects TTL (CMOS HCT) levels, and with the device powered with 5.0 V that means only a level above 70% (0.7 times) VCC will be reliably interpreted as a valid high. 0.7 times 5.0V is 3.5V, meaning 3.3V is NOT enough to reliably be seen as a logical high signal. Which means errors will be common.

The best solution (designed by the I2C inventor Philips) is to use two n-FETS and two pullups to 5.0V to create I2C compatible level shifters, that convert an 3V3 I2C bus to a 5.0V I2C bus. like so:

Image

Tzarls
Authorised Reseller
Authorised Reseller
Posts: 263
Joined: Tue Feb 26, 2013 6:59 am

Re: I2C - Small percentage of corrupted data

Thu Apr 13, 2017 2:05 pm

mahjongg wrote:what could, I repeat could, be the problem is that the Pullups for I2C on the raspberry PI pull the I2C clock and data signal up to 3.3Volt, NOT to the more common 5.0 Volt. This means that any I2C device on that 3V3 level I2C bus MUST reliably accept a 3.3V signal as "high". Sometimes the I2C device expects TTL (CMOS HCT) levels, and with the device powered with 5.0 V that means only a level above 70% (0.7 times) VCC will be reliably interpreted as a valid high. 0.7 times 5.0V is 3.5V, meaning 3.3V is NOT enough to reliably be seen as a logical high signal. Which means errors will be common.

The best solution (designed by the I2C inventor Philips) is to use two n-FETS and two pullups to 5.0V to create I2C compatible level shifters, that convert an 3V3 I2C bus to a 5.0V I2C bus. like so:

Image
Well, in my case level shouldn't be a problem since both ghe Raspberry and the trinket I'm using are both 3V3. I think I'll have a look at my connections.

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