arduino freezes when connecting i2c device

Hello,

I'm working on a project for a paludarium, it will be in charge of keeping the plants watered and making sure that thei get the right colours of light throughout the day using rgb +cct leds.
for this i use a arduino uno r3 as the brains, a driver for the watering pump, some mosfets to drive the leds and a few !2C devices, thats where the problem comes in :sweat_smile:

I use 3 devices that communicate with the arduino over I2C, a DS3234 real time module, a polulu I2C lcd adaptor, and the adafruit pca9685 16 channel 12 bit servo driver (which i use to have some more pwm pins to work with), all of them on breakout boards.

I was setting up a test to get a hang of working with the pca9685, so i made a sketch that reads a rotary encoder and use that input to controll a dc motor, the enable pins on the motor driver are wired directly to the arduino (pins 7 and 12 as defined in the code below) and the pwm input of that driver to pwm pin 0 on the pca9685, so i uploaded the code and tested just with the rotary encoder to see if everything worked as intended, you know, just putting some serial feedback here and there in the code :grinning: , and it did work, so i disconnected the usb and hooked up the power-supply, everything powered up, hit the button on the encoder, and you guess it, nothing....
Long story short, the arduino completely grinds to a halt when any of the 3 I2C devices gets connected, it doesnt execute any of the code, there is no more serial communication, nothing, with any of the i2c devices connected, and as soon as you disconnect them, it starts working again :o .

i have no idea what could be the problem, the only thing i can really think of is that it has to do with my wiring, i'm kind of making my own shield for the uno in this proyect, using header pins on a prototyping pcb, so maybe the added wires and solder joints going to the cconnectors for the I2C devices messes with it, no idea, i hope someone can help me shed som light on this one :sweat_smile:

thanks in advance and greetings, Nook

this is my test code:

#include <Adafruit_PWMServoDriver.h>

#include <Wire.h>

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
// you can also call it with a different address and I2C interface
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(&Wire, 0x40);


#define floater_btn 8;
#define in_a 7
#define in_b 12
#define pwmnum 0
#define enc_a  2
#define enc_b  3
#define enc_c  8

volatile byte enc_status, enc_dir, enc_but, last_enc;
byte buttons_status;
byte motor_status = 0;
byte motor_dir = 0;
unsigned int pwms = 0;
byte dir;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pwm.begin();
  pwm.setPWMFreq(500);
  
  pinMode(enc_a, INPUT_PULLUP); pinMode(enc_b, INPUT_PULLUP); pinMode(enc_c, INPUT_PULLUP);
  //pinMode(pwm_pin, OUTPUT);
  pinMode(in_a, OUTPUT);
  pinMode(in_b, OUTPUT);
  delay(100);
  motor_status = 0;
 attachInterrupt(digitalPinToInterrupt(enc_a), read_enc, CHANGE);
  attachInterrupt(digitalPinToInterrupt(enc_b), read_enc, CHANGE);
 
}

void loop() {


if (enc_dir == 1){
  enc_dir = 0;
  if (motor_status == 1){
  motor_dir = 0;
  Serial.println("direction 1");
  } else if (motor_status == 0){
    if(pwms >= 255){
      pwms = 255;
    } else {
    pwms ++;
    }
    motor_controll();
    Serial.println("pwm:");
Serial.println(pwms);
  }
}
if(enc_dir == 2){
  enc_dir = 0;
  if(motor_status == 1){
  motor_dir = 1;
  Serial.println("direction 2");
  } else if (motor_status == 0){
    pwms --;
    motor_controll();
    Serial.println("pwm:");
Serial.println(pwms);
  }
}


  
    
    if(motor_status == 1){
      if(enc_but == 128){
     motor_controll();
     delay(900);
   read_but();
  }
  }
  if(motor_status == 0){
    if(enc_but == 128){
    digitalWrite(in_a, LOW);
    digitalWrite(in_b, LOW);
    pwm.setPWM(pwmnum, 0, 4096);
    pwms = 255;
    motor_status = 1;
    Serial.println("stop");
    delay(900);
    read_but();
  }
  }

/*Serial.println(motor_status);
Serial.println(enc_dir);
Serial.println("button stat");
Serial.println(enc_but);*/
read_but();
read_enc();
}
void motor_controll()
{
  if (motor_dir == 0){
    digitalWrite(in_a, HIGH);
    digitalWrite(in_b, LOW);
    pwm.setPWM(pwmnum, 0, (pwms * 16));
   } else if (motor_dir == 1){
    digitalWrite(in_a, LOW);
    digitalWrite(in_b, HIGH);
    pwm.setPWM(pwmnum, 0, (pwms * 16));
   }
   motor_status = 0;
   Serial.println("start");
   
}
void read_but()
{
  bool pin_status;
  delay(3);
  pin_status=digitalRead(enc_c);
  if(pin_status == LOW && enc_but !=128) {enc_but = 128;}
  if(pin_status == HIGH && enc_but ==128){enc_but=1;}
}

void read_enc()
{
  //returns 0 if nothing is set
  //returns 1 if A is set but B is not
  byte a=0;
  delayMicroseconds(200);
  if(digitalRead(enc_a) == HIGH ){a=B01;}
  if(digitalRead(enc_b) == HIGH ){a=a+2;} //set the second bit
  if(last_enc!=a)
  {
    last_enc = a;
    enc_status = enc_status*4;
    enc_status = enc_status + a;
    //Serial.print(enc_status, DEC);Serial.print("/");Serial.print(a, DEC);Serial.print(" ");
    switch(enc_status)
    {
      case 0x4b:enc_dir=1;enc_status=0;break;  //ccw, enc_dir=1 
      case 0x87:enc_dir=2;enc_status=0;break;  //cw enc_dir=2
      default : enc_dir =0;break;
    }
  }
}

My guess is that each breakout board has it's own pull-ups installed and with p.e. three 4k7 pull-ups installed you get a too high sink current, some devices might block the bus or do other weird things.

Start by providing links to the schematics of the used breakout boards. And post a complete wiring diagram of your setup.

the breakout boards i use, are:

https://www.electrodragon.com/product/ds3231-rtc-breakout-board-r2/
https://opencircuit.nl/ProductInfo/1000061/I2C-LCD-interface.pdf <- i have that same one, just branded polulu

as for the diagram, does anyone know a good online tool to draw diagrams? i found tinkercad circuits but it didnt have a rotary encoder..
the circuit is really simple, its a rotary encoder with the button in the shaft, center pin of the encoder part is connected to ground, as is one of the button pins, the other button pin is connected to pin 8 on the arduino, and the two encoder pins are pins 2 and 3 on the arduino, the rest is all I2C (SCL to SCL and SDA to SDA, 5v to 5v and groud to ground)...

also, i doubt that its the pull-ups, because the breakouts are after all designed to be used with a microcontroller such as the arduino, and i cant even plug just one of the three in without it freezing :confused: :confused: :confused:

as for the diagram, does anyone know a good online tool to draw diagrams?

That can be the photo of a hand drawn piece of paper.

the breakout boards i use, are:

The boards that have schematics all include pull-ups. You should remove them except for one of them.

also, i doubt that its the pull-ups, because the breakouts are after all designed to be used with a microcontroller such as the arduino, and i cant even plug just one of the three in without it freezing

Have you tried that with the RTC board? Post the code you used to test this.

found the old school paint online, but it works :smiley:

pylon:
Have you tried that with the RTC board? Post the code you used to test this.

yes, i tried with all of them, using the code from the original post, and it is strange, because all three of them are different adresses, so on that aspect, it could be somthing like the pull-ups but that would mean that you cant use them out of the box, while thats what theyre made for :confused:

void read_enc()
{
  //returns 0 if nothing is set
  //returns 1 if A is set but B is not
  byte a=0;
  delayMicroseconds(200);
  if(digitalRead(enc_a) == HIGH ){a=B01;}
  if(digitalRead(enc_b) == HIGH ){a=a+2;} //set the second bit
  if(last_enc!=a)
  {
    last_enc = a;
    enc_status = enc_status*4;
    enc_status = enc_status + a;
    //Serial.print(enc_status, DEC);Serial.print("/");Serial.print(a, DEC);Serial.print(" ");
    switch(enc_status)
    {
      case 0x4b:enc_dir=1;enc_status=0;break;  //ccw, enc_dir=1
      case 0x87:enc_dir=2;enc_status=0;break;  //cw enc_dir=2
      default : enc_dir =0;break;
    }
  }
}

Why exactly are you wasting 200µs in an interrupt handler?
That may explain your freezings...

sorry for the late answer, here is an update of the situation.

the problem seems to have solved itself somehow, i decided to continue with other parts of the project (code wise, the hardware is still exactly the same), and it just started working again.

i already compared the code and can't quite find whats wrong, but my current sketch is attached here, just in case anyone wants to figure it out :sweat_smile:

pylon:

void read_enc()

{
 //returns 0 if nothing is set
 //returns 1 if A is set but B is not
 byte a=0;
 delayMicroseconds(200);
 if(digitalRead(enc_a) == HIGH ){a=B01;}
 if(digitalRead(enc_b) == HIGH ){a=a+2;} //set the second bit
 if(last_enc!=a)
 {
   last_enc = a;
   enc_status = enc_status*4;
   enc_status = enc_status + a;
   //Serial.print(enc_status, DEC);Serial.print("/");Serial.print(a, DEC);Serial.print(" ");
   switch(enc_status)
   {
     case 0x4b:enc_dir=1;enc_status=0;break;  //ccw, enc_dir=1
     case 0x87:enc_dir=2;enc_status=0;break;  //cw enc_dir=2
     default : enc_dir =0;break;
   }
 }
}




Why exactly are you wasting 200µs in an interrupt handler?
That may explain your freezings...

dont actually know, thats still part of the example code i based my project on...

thanks for all the replies and greetings, Nook

Arduino_moonlightV2.ino (29 KB)