Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Arduino I²C freezes after startup

Tags:

arduino

I'm attempting an I²C setup in which one master Arduino controls two slaves.

Enter image description here

I'm using two 2000 ohm pullup resistors for the I²C and all boards are Arduino Duemilanoves. Both the I²C setup and the control setup function properly when disconnected from each other, but when connected the Arduinos become unresponsive as soon as the first wire.write function is called. I cease to receive serial messages, the slave Arduinos stop receiving messages from the master, and I loose the ability to turn the system on and off using the button.

I've tried adding short delays after each wire.write function and have used a variety of pullup resistors in an attempt to fix the problem, but nothing seems to work. How can I fix this?

Master Code:

#include <Wire.h>

int potPin1 = 0;    // Select the input pin for the potentiometer
int potPin2 = 1;
int potVal1;       // Variable to store the value coming from the sensor
int potVal2;
int times=0;   // All the below variables are used to control an on-off button
int state=0;
int lastState=0;
boolean pot=false;

void setup()
{
    pinMode(13, OUTPUT);  //LED that turns on when system is activated
    pinMode(3, INPUT);    //Button that turns on system
    Serial.begin(9600);
    Wire.begin();
}

void loop(){
    state=digitalRead(3);
    if(state != lastState){
        if(state==HIGH){
            times++;
            Serial.println(times);
        }
        else{
            Serial.println("off");
        }
    }

    lastState=state;

    if(times%2 ==1)
    {
        turnPotOn();
    }
    else
    {
        turnPotOff();
    }

//All code in the loop up to this point turns the system on and off at button press. //The following code corresponds to I²C based upon potentiometer readings.

    if(pot==true)
    {
        potVal1 = analogRead(potPin1);    // Read the value from the sensor
        potVal2 = analogRead(potPin2);

        if((potVal1>700) && (300<potVal2) && (potVal2<700))
        {
            arduino1_motor1();
        }
        else if ((potVal1<330) && (336<potVal2) && (potVal2<683))
        {
            arduino1_motor2();
        }
        else if ((potVal2>683) && (330<potVal1) && (potVal1<640))
        {
            arduino2_motor3();
        }
        else if ((potVal2<336) && (330<potVal1) && (potVal1<640))
        {
            arduino2_motor4();
        }
        else if ((potVal2<336) && (potVal1<330))
        {
            arduino12_motor24();
        }
        else if ((potVal2>683) && (potVal1>640))
        {
            arduino12_motor23();
        }
        else if ((potVal2>683) && (potVal1<640))
        {
            arduino11_motor23();
        }
        else if ((potVal2<336) && (potVal1>330))
        {
            arduino11_motor24();
        }
        else
        {
            arduino12_still();
        }
    }
    else
    {
        // arduino1_still();
        // arduino2_still();
        Serial.println("OFF");
    }
}

void turnPotOff()
{
    digitalWrite(13, LOW);
    pot=false;
}

void turnPotOn()
{
    digitalWrite(13, HIGH);
    pot=true;
}

void arduino1_motor1()
{
    Wire.beginTransmission(5);
    Wire.write('A');
    Wire.endTransmission();
    arduino2_still();
    Serial.println("A1 in M1 d");
}

void arduino1_motor2()
{
    Wire.beginTransmission(5);
    Wire.write('B');
    Wire.endTransmission();
    arduino2_still();
    Serial.println("A1 in m2 d");
}

void arduino12_still()
{
    arduino1_still();
    arduino2_still();
    Serial.println("A1 & A2 stl");
}

void arduino2_motor3()
{
    arduino1_still();
    Wire.beginTransmission(10);
    Wire.write('M3');
    Wire.endTransmission();
    Serial.println("A2 in M3 d");
}

void arduino2_motor4()
{
    arduino1_still();
    Wire.beginTransmission(10);
    Wire.write('D');
    Wire.endTransmission();
    Serial.println("A2 in M4 d");
}

void arduino12_motor24()
{
    Wire.beginTransmission(5);
    Wire.write('B');
    Wire.endTransmission();
    Wire.beginTransmission(10);
    Wire.write('D');
    Wire.endTransmission();
    Serial.println("A1 & A2 in M2 and M4 d");
}

void arduino12_motor23()
{
    Wire.beginTransmission(5);
    Wire.write('B');
    Wire.endTransmission();
    Wire.beginTransmission(10);
    Wire.write('C');
    Wire.endTransmission();
    Serial.println("A1 & A2 in M2 and M3 d");
}

void arduino11_motor24()
{
    Wire.beginTransmission(5);
    Wire.write('A');
    Wire.endTransmission();
    Wire.beginTransmission(10);
    Wire.write('D');
    Wire.endTransmission();
    Serial.println("A1 & A2 in M1 and M4 d");
}

void arduino11_motor23()
{
    Wire.beginTransmission(5);
    Wire.write('A');
    Wire.endTransmission();
    Wire.beginTransmission(5);
    Wire.write('C');
    Wire.endTransmission();
    Serial.println("A1 & A2 in M1 and M3 d");
}

void arduino1_still()
{
    Wire.beginTransmission(5);
    Wire.write('S');
    Wire.endTransmission();
}

void arduino2_still()
{
    Wire.beginTransmission(10);
    Wire.write('S');
    Wire.endTransmission();
}

Slave 1 Code:

#include <Servo.h>
#include <Wire.h>

Servo myservo1;
Servo myservo2;

void setup()
{
    Serial.begin(9600);          //  setup serial
    myservo1.attach(2);
    myservo2.attach(3);
    Wire.begin(5);
    Wire.onReceive(receiveEvent);


}

void loop()
{
}

void receiveEvent(int howMany)
{
  while(Wire.available())
  {
    char v = Wire.read();

    if(v == 'A')
    {
      myservo1.write(0);
      myservo2.write(180);
      Serial.println("Arduino 1 in motor 1 direction");
    }
    else if(v == 'B')
    {
      myservo1.write(180);
      myservo2.write(0);
      Serial.println("Arduino 1 in motor 2 direction");
    }
    else
    {
      myservo1.write(90);
      myservo2.write(85);
      Serial.println("Arduino 1 still");
    }
  }
}

Slave 2:

#include <Servo.h>
#include <Wire.h>

Servo myservo3;
Servo myservo4;

void setup()
{
    Serial.begin(9600);         // Setup serial
    myservo3.attach(2);
    myservo4.attach(3);
    Wire.begin(10);
    Wire.onReceive(receiveEvent);
}

void loop()
{
}

void receiveEvent(int howMany)
{
    while(Wire.available())
    {
        char v = Wire.read();

        if(v == 'C')
        {
            myservo3.write(0);
            myservo4.write(180);
            Serial.println("Arduino 2 in motor 3 direction");
        }
        else if(v == 'D')
        {
            myservo3.write(180);
            myservo4.write(0);
            Serial.println("Arduino 2 in motor 4 direction");
        }
        else
        {
            myservo3.write(90);
            myservo4.write(90);
            Serial.println("Arduino 2 still");
        }
    }
}
like image 311
pongAssist Avatar asked Nov 01 '12 22:11

pongAssist


2 Answers

the "receive event" is inside an ISR, which doesn't exit until the event function returns

oh by the way, the AVR hardware holds the I2C bus in a frozen state until this event exits, also known as clock stretching

oh guess what, Wire didn't declare the FIFO variables as volatile, so even though he has while (Wire.available()), that becomes an infinite loop because available() will never change, because it's all happening in an interrupt and rxBufferIndex and rxBufferLength are not declared as volatile

http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_volatile

this is one possible cause

insert angry rant about Arduino and its terrible libraries here

solution? use another library, the TWI utilities that "Wire.h" borrows can be used directly if you know how, and it's great, I use it all the time.

like image 68
Frank26080115 Avatar answered Oct 13 '22 20:10

Frank26080115


This might help you out a bit:

Okay so this is going to be a wall of text and I already closed the tab once on accident before posting so I might sound angry, because this "feature" of the Arduino is really bad and it will cost you $$ if you plug a 3.3v device into it. You're using the Wire Library which enables really bad 20k internal pullups on the SDA and SCL pins.

ON EACH ARDUINO. You have a situation where the total pullup resistance is now borked(screwed up). You need to do research on how to disable the internal pullups. I recommend modifying the library. For holistic reasons this sort of control should never be done in software. Double check his math on the required external pullup. The capacitance of each SCL/SDA pin on the Arduino should be 10pF.

Here is the formula direct from the ATMEGA datasheet

http://i.imgur.com/ZAByF.png

Here is the ATMEGA datasheet, see section 21 for the I2C section

http://www.atmel.com/Images/doc8161.pdf

like image 36
Cameron Barge Avatar answered Oct 13 '22 20:10

Cameron Barge