Go Down

Topic: Issues when running devices with different addresses on I2C bus (Read 1 time) previous topic - next topic

EscapingTheRoom

Hi all,

I'm working on a project that takes the output of an INA219 Breakout Board and uses it to drive devices connected to the original Wemos D1 Motor Shield (although I've [updated the firmware](https://hackaday.io/project/18439-motor-shield-reprogramming) to avoid I2C crashes).

I've got both devices connected to an Arduino Nano, because for this project I need more I/O than the D1 mini can provide.

The devices are connected to the SCL/SDA ports A4 and A5, and a scan of the I2C bus reveals two devices - the INA219 on 0x40, and the motor shield on 0x30 as expected from the docs.  I also have a servo connected to D9.

The code looks as follows:

Code: [Select]

#include "WEMOS_Motor.h"
#include <Wire.h>
#include <Adafruit_INA219.h> // You will need to download this library
#include <Servo.h>



int pwm = 0;

//Motor shield I2C Address: 0x30
//PWM frequency: 1000Hz(1kHz)
Motor M1(0x30,_MOTOR_A, 1000);//Motor A
Motor M2(0x30,_MOTOR_B, 1000);//Motor B

Servo s1;
Adafruit_INA219 sensor219; // Declare and instance of INA219


void setup(void)
{
  s1.attach(9);
  s1.write(90);
  delay(100);
  s1.write(0);
  Serial.begin(9600);    
  Serial.println("Setup complete, waiting instructions...");
  delay(1000);
  sensor219.begin();
}

void loop(void)
{
  float busVoltage = 0;
  float current = 0; // Measure in milli amps
  float power = 0;

  busVoltage = sensor219.getBusVoltage_V();
  current = sensor219.getCurrent_mA();
  power = busVoltage * (current/1000); // Calculate the Power

  int s1cur = s1.read();
  if (busVoltage < 8.00 && s1cur < 128){
    s1.write(s1cur + 1);
    pwm = pwm + 1;
    M1.setmotor( _CW, pwm);
    M2.setmotor(_CCW, pwm);
    Serial.println("Increasing");
  }
  else if (busVoltage > 8.00 && s1cur > 0){
    s1.write(s1cur - 1);
    pwm = pwm - 1;
    M1.setmotor( _CW, pwm);
    M2.setmotor(_CCW, pwm);
    Serial.println("Decreasing");
  }
  
  Serial.print("Bus Voltage:   ");
  Serial.print(busVoltage);
  Serial.println(" V");  

  Serial.print("Servo Position: ");
  Serial.println(s1cur);
/*  
  Serial.print("Current:       ");
  Serial.print(current);
  Serial.println(" mA");
  
  Serial.print("Power:         ");
  Serial.print(power);
  Serial.println(" W");  
  
  Serial.println("");  */
  delay(50);
}


The idea behind it is that as the current drops, the motors activate and slowly get faster, whilst the servo swings to a set position.  As the current rises, the motors slow down, and the servo drifts back toward 0°.

The code works fine, as long as I keep the Motor M1(0x30,_MOTOR_A, 1000);//Motor A and equivalent for Motor B commented out.  As soon as I uncomment those lines, the whole setup hangs, and it appears to do so when trying to initialise the INA219.

Obviously this is sub-optimal, as it means I can only have the Servo working and not the motors as intended.

I'm wondering if there's something in the Wemos Library that is causing the I2C bus to crash, but my knowledge of these things isn't sufficient to know where to start looking for a solution!

All and any help is appreciated.

pylon

Quote
I've got both devices connected to an Arduino Nano, because for this project I need more I/O than the D1 mini can provide.
You know that the Nano is a 5V device while the D1 Mini is a 3.3V device, don't you?

Quote
The code works fine, as long as I keep the Motor M1(0x30,_MOTOR_A, 1000);//Motor A and equivalent for Motor B commented out.  As soon as I uncomment those lines, the whole setup hangs, and it appears to do so when trying to initialise the INA219.
Post a wiring diagram of your setup that includes the power supply!

Quote
I'm wondering if there's something in the Wemos Library that is causing the I2C bus to crash, but my knowledge of these things isn't sufficient to know where to start looking for a solution!
The motor driver variables must not be declared as global variables because the Wire library isn't ready to be activated at that time. A typical Arduino library does that stuff in a begin() method and not in the constructor so you have to move object construction to the setup() and just keep pointers to the objects.

EscapingTheRoom

You know that the Nano is a 5V device while the D1 Mini is a 3.3V device, don't you?
Yup, I'm running the power to the shield from the 3.3v out on the Nano, we're all good on that front :)

Post a wiring diagram of your setup that includes the power supply!
Happy to do this in the next day or so, but I don't have any software currently installed to do this.

I know that the connections between the devices are correct, however, because an I2C scanner script picks up both devices, and if I remove the initialisation of the motors, I get the data flowing without issue from the INA219 board and the servo moves as expected.

The motor driver variables must not be declared as global variables because the Wire library isn't ready to be activated at that time. A typical Arduino library does that stuff in a begin() method and not in the constructor so you have to move object construction to the setup() and just keep pointers to the objects.
Ah, ok, that bit I didn't know.

How would I go about setting the pointer to the object? My background is python, not C, so I'm new to all this memory management and referencing stuff!

Do I just need to move the Motor m1() calls into setup()?

Thanks for the reply!

EscapingTheRoom

Hmmm, I think I misunderstood you.

You mean that in the library I need to initialise/connect in a different way?

so for example at this part of the code I'd need to move it some somewhere else (ideally a dedicated function) and then call it from there?

Code: [Select]

Motor::Motor(uint8_t address, uint8_t motor, uint32_t freq)
{
_use_STBY_IO=false;

if(motor==_MOTOR_A)
_motor=_MOTOR_A;
else
_motor=_MOTOR_B;

Wire.begin();

_address=address;

setfreq(freq);

}

pylon

Quote
Do I just need to move the Motor m1() calls into setup()?
Yes, kind of. This shows how to do it, you have to made the rest of the changes.

Code: [Select]

Motor *M1;

void setup() {
...
  M1 = new Motor(0x30,_MOTOR_A, 1000);//Motor A
...
}

void loop() {
...
  M1->setmotor( _CW, pwm);
...
}


The alternative is to fix the library and move the initialization code into a begin() method.

EscapingTheRoom

Thanks @pylon

OK, the code now looks like this:

Code: [Select]

#include "WEMOS_Motor.h"
#include <Wire.h>
#include <Adafruit_INA219.h> // You will need to download this library
#include <Servo.h>



int pwm = 0;

//Motor shield I2C Address: 0x30
//PWM frequency: 1000Hz(1kHz)
Motor *M1; // (0x30,_MOTOR_A, 1000);//Motor A
Motor *M2; //(0x30,_MOTOR_B, 1000);//Motor B

Servo s1;
Adafruit_INA219 sensor219; // Declare and instance of INA219


void setup(void)
{
  M1 = new Motor(0x30,_MOTOR_A, 1000);//Motor A
  M2 = new Motor(0x30,_MOTOR_B, 1000);//Motor B
  s1.attach(9);
  s1.write(90);
  delay(100);
  s1.write(0);
  Serial.begin(9600);   
  Serial.println("Setup complete, waiting instructions...");
  delay(1000);

  sensor219.begin();
 
}

void loop(void)
{
  float busVoltage = 0;
  float current = 0; // Measure in milli amps
  float power = 0;

  busVoltage = sensor219.getBusVoltage_V();
  current = sensor219.getCurrent_mA();
  power = busVoltage * (current/1000); // Calculate the Power

  int s1cur = s1.read();
  if (busVoltage < 8.00 && s1cur < 128){
    s1.write(s1cur + 1);
    pwm = pwm + 1;
    M1->setmotor( _CW, pwm);
    M2->setmotor(_CCW, pwm);
    Serial.println("Increasing");
  }
  else if (busVoltage > 8.00 && s1cur > 0){
    s1.write(s1cur - 1);
    pwm = pwm - 1;
    M1->setmotor( _CW, pwm);
    M2->setmotor(_CCW, pwm);
    Serial.println("Decreasing");
  }
 
  Serial.print("Bus Voltage:   ");
  Serial.print(busVoltage);
  Serial.println(" V"); 

  Serial.print("Servo Position: ");
  Serial.println(s1cur);
/* 
  Serial.print("Current:       ");
  Serial.print(current);
  Serial.println(" mA");
 
  Serial.print("Power:         ");
  Serial.print(power);
  Serial.println(" W"); 
 
  Serial.println("");  */
  delay(50);
}


Which I *think* matches your recommendations.

Flashing this code down to the arduino *without* the shields attached (I don't have them to hand right now) results in nothing coming back over the serial line, and the on-board LED blinking as if I've flashed the blink sketch.

I'll have a chance to connect the boards up tomorrow, but would you expect the code to run anyway without the boards attached?

EscapingTheRoom

Flashing this code down to the arduino *without* the shields attached (I don't have them to hand right now) results in nothing coming back over the serial line, and the on-board LED blinking as if I've flashed the blink sketch.

I'll have a chance to connect the boards up tomorrow, but would you expect the code to run anyway without the boards attached?
Ignore me - I'd tried to be clever and made changes to the WEMOS_Motor.cpp file as well as the sketch - having reset the file, it seems to be working.

Without the drivers attached, the Arduino now outputs as expected to the serial port, I'll give it a go with the accessories attached later on tonight.

Go Up