Arduino hangs after several minutes using i2c connection (with a raspebrry pi)

I have connected a Raspberry pi (RPI) and an arduino using I2C. The RPI is using the library Smbus and it´s the master and the arduino is using the library Wire and it´s the slave. The RPI send a byte and receive three (from arduino). It runs properly but, after several minutes (or hours) running, the arduino stops and hang by itself. I don´t know why.
It isn´t a problem of pull-up resistor not even voltage level (3,3 V. RPI and 5 V. arduino).
I have read several forums with topics about this problem but, I am not able to find an answer and a solution.
I have observed that arduino goes on running after a handmade reset. I could do resets automatically using a RPI´s GPIO pin but I don´t know when because, as i said, arduino stops randomly.
Any idea about a way of avoid those stops?.
Thank you

Any idea about a way of avoid those stops?

Without seeing your code, no idea.

edit: You really should use a logic level converter between a 5v device and a 3.3v device. I use this converter for I2C.

The code for arduino is:

#include "Wire.h"
void setup()
{ Serial.begin(9600);
array[0]=23; array[1]=50; array[2]=150;
Wire.begin(13); delay(300);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
}
void loop()
{ delay(100);
contador=0;
}
void receiveEvent(int lede)
{
int x = Wire.read(); //Leemos el dato recibido
}
void requestEvent()
{ numero=Wire.write(array[contador]);
contador=contador+1;
}

The code for Raspberry is:

bus.write_byte(13, 15); time.sleep(0.05);
dato1 = bus.read_byte(13); time.sleep(0.02)
dato2 = bus.read_byte(13); time.sleep(0.02)
dato3 = bus.read_byte(13); time.sleep(0.02)

I don't see where the array array is declared.

I can see where this could cause problems if the array index (contador) became larger than the array.

void requestEvent()
{ numero=Wire.write(array[contador]);
contador=contador+1;
}

Thank you for your answer. I had declared it like "int array[3]" but really, i am only using array[0], array[1] and array [2]. Now, i have changed it to "int array[2]" but i´m getting the same error.

You are using as many characters as the RPi sends during the 100ms. You must insure you do not overflow the array. Use something like this. Either quit writing to the array, or process the array and empty it.

void requestEvent()
{
  if(contador < 2)
  {
    numero=Wire.write(array[contador]);
    contador=contador+1;
  }
}

I have checked writing fixed integer numbers in stead of array but it is not running fine. Those number are read several times but after several minutes the arduino hang. So, i think the fault is not the array.

I would have checked your code, but you have yet to post any Arduino sketch that will compile.

edit: I have a RPi with I2C working with C and Python. If you post that code, I can check all of it.

Thank you for your help.

This is the whole arduino´s code: (Sorry for comments in spanish)

#include "Wire.h" 
#include <DHT11.h>
#include "DHT.h"
DHT dht;

int pin=10; /*conectar en este pin digital el DHT11*/
int tempentero,humentero,temp,humi;
DHT11 dht11(pin); 

int led = 13; 

int perimetral1=5; 
int perimetral2=2; 
int perimetral3=3; 
int perimetral4=4; 
int presenciaext=6; //pin digital para detectar presencia exterior
int i; //para ser un contador
int c,numero;
int array[2];
byte primeravez[5];


void setup()
{
Serial.begin(9600);
pinMode(led,OUTPUT);
pinMode(perimetral1,INPUT);
pinMode(perimetral2,INPUT);
pinMode(perimetral3,INPUT);
pinMode(perimetral4,INPUT);
pinMode(pin,INPUT);

dht.setup(pin); // data pin donde se conecta el DHT22
c=0;
numero=0;
digitalWrite(led,LOW);

for (i=0;i<5;i++) 
{
primeravez[i]=0;  
}  

Wire.begin(13); //Empezamos la comunicación I2C con dirección 4 (dispositivo slave)
delay(300);

Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
//Serial.print("Se ha reiniciado  "); 
}

void loop()
{
digitalWrite(led,LOW);
delay(dht.getMinimumSamplingPeriod()); 
  
humi= dht.getHumidity(); 
temp= dht.getTemperature();

temp=temp*100;tempentero=temp/100; //solo parte entera temperatura
humi=humi*100;humentero=humi/100; //solo parte entera humedad

if ((tempentero<50) && (tempentero>=0))
{
array[0]=tempentero;
}
if ((humentero<100) && (humentero>=0))
{
array[1]=humentero;
}

   
if ((digitalRead(perimetral1)==HIGH)&& (primeravez[1]==0))
{
array[2]=1;
primeravez[1]=1;
} //detector perimetral1

if ((digitalRead(perimetral2)==HIGH)&& (primeravez[2]==0))
{
array[2]=2;
primeravez[2]=1;
} //detector perimetral2

if ((digitalRead(perimetral3)==HIGH)&& (primeravez[3]==0))
{
array[2]=3;
primeravez[3]=1;
} //detector perimetral3

if ((digitalRead(perimetral4)==HIGH)&& (primeravez[4]==0))
{
array[2]=4;
primeravez[4]=1;
} //detector perimetral4

}



void receiveEvent(int lede)
{
int x = Wire.read(); //Leemos el dato recibido
digitalWrite(led,HIGH);
c=0;
}


void requestEvent()
{

Wire.write(array[c]);

if (c==2) //ha enviado ya el array[o], el array[1] y el array[2]
{
for (i=0;i<5;i++) 
{
primeravez[i]=0;
}
array[0]=0;array[1]=0;array[2]=0;
}

c=c++;


}

And this is RPI code (python):

import datetime
import time
import smbus

bus = smbus.SMBus(1)  #Para poder funcionar con el protocolo de comunicaciones I2C.
dato=[range(4) for i in range(21)]
datop=[range(4) for i in range(21)]

while TRUE:
    address=1
    while address<21: #There will be 20 arduinos but now i´m doing checks only with one (nº13)
        try: #avoid the hang of execution if it is not possible write the data
            bus.write_byte(address, 5);# send nº 5 to arduinos  #only for checks                     
            time.sleep(0.1); #give time to arduino for read the data
        except:
            pass

        try: #avoid the hang of execution if it is not possible readthe data
            datop[address][1] = bus.read_byte(address);   time.sleep(0.03)
            datop[address][2] = bus.read_byte(address);   time.sleep(0.03)
            datop[address][3] = bus.read_byte(address);   time.sleep(0.03)
        except:
            pass

        if (dato1 <100): #check for no valid data. If they are valid pass value to another array
            dato[address][1]=datop[address][1]; dato[address][2]=datop[address][2];                      dato[address][3]=datop[address][3]; #datos validos

        else: #No valid received data. I´m going to do a reset to the arduino using GPIO 24 
            GPIO.digitalWrite(24,GPIO.LOW);
            time.sleep(0.1)
            GPIO.digitalWrite(24,GPIO.HIGH);
            time.sleep(0.1)#tiempo para que arduino reseteado este operativo otra vez

        address=address+1;
        time.sleep(0.06);

As you will see, i have included a check in order to detect no valid data (when the value of byte received is lower than 100). When it happens i do a reset to arduino using a GPIO Pin.

I´m trying to avoid those resets because it happens often (working only with an arduino but, my project will need 20 of them so, the problem will be much more frequent).

I’m running a simple i2c test with my RPi in C and an Arduino Due. Both are 3.3v devices. How often do you want to poll the Arduino? How many times per second? How many bytes do you want to read? Right now I’m testing at about 85 per second, reading one byte from the Due.

edit: How long average is it to your fail? I’m coming up on 10 minutes with no fail or missed byte. I do not have DHT sensor, so I can’t test that part of it.

edit2: I can test part of the DHT library. It disables interrupts while reading the IC, and when it does, the i2c read function fails while interrupts are disabled.

I am using for the test a not original arduino nano but i did checks with a UNO R3 getting the same failures.

I'm trying to make a homemade alarm system. There will be 20 arduinos placed in windows and doors connected to i2c bus. The RPI will control the system sending one byte with orders to each arduino (for example for turn the light on/off, etc) and reading three bytes from each one with information about temperature, humidity and state of different sensors (presence, open window, smoke, etc,). So i need the maximun speed of poll but, free of errors. At the end, it will depend on the value of seconds included in the commands "time. Sleep(xx)" between the three readings done from each arduino.

The average time between failures is aprox. One hour and half. Sometimes it happens a few minutes after start the test but sometimes it keeps running 2-3 hours.

About the DHT library, i didn't know it disables the interrupts. Maybe, it is the cause of the problem. I did checks fixing the values sent (without temperatute reading using DHT) Getting the same failure but i kept #include dht.t. I will repeat it avoiding the use of that library and we will know if it is the problem.

Thank you

You do have a good ground connection between the Arduino and the RPi, correct?

What are the symptoms of the hang? Does the Arduino quit running, or just loses the i2c connection?

Yes, i have a good ground connection so i think it is not the problem.

I have included in the arduino's code commands in order to turn a led on and off. So i can see if the arduino is running or it is stopped. I have observed that before hang, the last byte sent is not correct (typically 255). That data must be between 15 and 45 because is the temperature (in celsius) so, my handmade solution is: if RPI receives a byte higher than 50 it will do a reset to the arduino.

I am trying to avoid this solution because, as you know, my system will have 20 arduinos connected. I cannot use 20 individual reset wires so, If RPI has to do a reset it will be done to all arduinos (using only one wire) every time one of them hangs. I supose it will happen often, so a lot of data will be lost and the system will be continuously interrupted.

255 unsigned is -1 signed. That is usually an error return code. Would you be willing to run my test code to see how the i2c connection works?

Yes, please include your codes (arduino and RPI) and,when i have free time, i will check it. If i get the same failure, maybe we could think that it is a hardware problem/connection problem, not a code or library problem.

Here is the Arduino code. I use 115200 baud. I left the interrupt test but commented it out.

#include <Wire.h>
byte array[3];
int contador = 0;
int numero;

void setup()
{
  Serial.begin(115200);
  array[0]=23; array[1]=50; array[2]=150; 
  Wire.begin(13); delay(300);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
}

void loop()
{
  delay(100);
  Serial.println(contador,DEC);
  contador=0;

/*
  noInterrupts();
  delayMicroseconds(50000);
  interrupts();
*/

}

void receiveEvent(int lede)
{
  int x = Wire.read(); //Leemos el dato recibido
}

void requestEvent()
{
  numero=Wire.write(array[0]);
  numero=Wire.write(array[1]);
  numero=Wire.write(array[2]);

  contador=contador+1;
}

Here is the RPi C code. Save it as i2ctest.c. Compile it with this
cc ./i2ctest.c -o i2ctest

Run it with this
sudo ./i2ctest

#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int fd;
unsigned char buf[6];

int main(int argc, char **argv)
{
    const char *i2cDevice = "/dev/i2c-1";
    const int i2cAddress = 13;
    unsigned char i;


    if ((fd = open(i2cDevice, O_RDWR)) < 0) {
        printf("Failed to open i2c port\n");
        exit(1);
    }

    if (ioctl(fd, I2C_SLAVE, i2cAddress) < 0) {
        printf("Unable to configure i2c address\n");
        exit(1);
    }

	while(1)
	{
		int testRtn = read(fd,buf,3);
		printf("%d %d %d %d\r\n",testRtn,buf[0],buf[1],buf[2]);
		usleep(10000);
	}
}

Insure you have the i2c development package installed on the RPi.

i have check your codes and i´m always getting the same:

3 150 255 255
3 150 255 255
3 150 255 255
...................

i don´t understand anything

You should be getting this:
3 23 50 150
3 23 50 150

edit: The Mega works differently than my Due. I used a logic level converter with my Mega2560 and this change to the Arduino code, and it works fine.

void requestEvent()
{
  numero=Wire.write(array,3);
  contador=contador+1;
}

Ok. i will check it and post the results.

Otherwise, you wrote "Insure you have the i2c development package installed on the RPi" how can i know if i have that package installed?.

i´m using SmBus package in my RPI´s code for I2C, is it the same or you are refering to another one?

Thank you for your interest

If it compiles and runs, you have the package installed. I got the same erroneous result you did on my Mega. With the new code, yours should run ok also. I ran mine 6 hours last night without a fail.

edit I do use a logic level converter. This one: