Trouble interfacing two i2c sensors to Arduino Mega, but not Arduino Uno.

Hi there,

I've been trying to get two TSL2561 LUX sensors (i2c) on my Arduino Mega with not much success. The first sensor is connected to SCL and SDA on the board itself and the second is connected to A4 and A5 via a CC3000 WiFi Shield. The connection to SCL/SDA works no problem but the latter does not.

The peculiar thing is that if I place the CC3000 on an Arduino Uno, both sensors work without issue. This makes me think its a hardware issue, but maybe there are differences between the two that I do not know of? I've checked the connections many, many times and it all looks fine. I've included the Fritzing diagram for the setup for completeness.

Code:

//Sensor Libraries
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.h>

//LCD Screen Library
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

//WiFi Connection Libraries
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>

//MQTT Libraries
#include <PubSubClient.h>

#include <Time.h>


//Wi-Fi Shield Details
// These are the interrupt and control pins
#define ADAFRUIT_CC3000_IRQ   3  // MUST be an interrupt pin!
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10
// Use hardware SPI for the remaining pins
// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
                                         SPI_CLOCK_DIVIDER); // you can change this clock speed but DI

//Wi-Fi Credentials
#define WLAN_SSID       ""        // cannot be longer than 32 characters!
#define WLAN_PASS       ""
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY   WLAN_SEC_WPA2

Adafruit_CC3000_Client client;

// MQTT / Broker Information
#define MQTT_Broker     "10.0.1.4"

IPAddress ip(10,0,1,2);
IPAddress server(10,0,1,4);

void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
}

PubSubClient mqttclient("10.0.1.4", 1883, callback, client);

//Sensor Setup
//Light
//The final number, in this case 1, must be unique
//tslwin addr is grounded. tslroom addr is floating
Adafruit_TSL2561_Unified tslroom = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 1);
Adafruit_TSL2561_Unified tslwin = Adafruit_TSL2561_Unified(TSL2561_ADDR_LOW, 2);

//Temperature
#define DHTPIN A2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

//PIR Sensor
int inputPin = 2;               // choose the input pin (for PIR sensor)
int pirState = LOW;             // we start, assuming no motion detected
int val = 0;                    // variable for reading the pin status

//Timer for motion detection
int timer = 0;

//LCD Display Setup
//String sendData(String command, const int timeout, boolean debug);
//Software SPI (slower updates, more flexible pin options):
// pin 9 - serial clock out (SCLK)
// pin 8 - Serial data out (DIN)
// pin 7 - Data/Command select (D/C)
// pin 6 - LCD chip select (CS)
// pin 4 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(9, 8, 7, 6, 4);

//Buffer definition
#define MAX_OUT_CHARS 16
char buffer[MAX_OUT_CHARS + 1];



void setup(void)
{
  Serial.begin(115200);
  //Initialise Display
  display.begin();
  display.setContrast(50);
  display.display();
  delay(2000);
  display.clearDisplay();

  
  //BEGIN NETWORK CONNECTION
  Serial.println(F("\nInitialising the CC3000 ..."));
  if (!cc3000.begin())
  {
    Serial.println(F("Unable to initialise the CC3000! Check your wiring?"));
    while(1);
  }
  /* Delete any old connection data on the module */
  Serial.println(F("\nDeleting old connection profiles"));
  if (!cc3000.deleteProfiles()) {
    Serial.println(F("Failed!"));
    while(1);
  }
  /* Attempt to connect to an access point */
  Serial.print(F("\nAttempting to connect to ")); Serial.println(WLAN_SSID);
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    Serial.println(F("Failed!"));
    while(1);
  }
  Serial.println(F("Connected!"));
  /* Wait for DHCP to complete */
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP())
  {
    delay(100); 
  }  

//END CONNECTION INFORMATION (Close connection below)


//Call configure sensors
  dht.begin();
  display.println("Initialising Sensors...");
  Serial.println("Initialising Sensors...");
  configureSensor();

  //setSyncProvider(getNtpTime);
  Serial.println("Time: ");
  Serial.println(hour());
  Serial.println(minute());
  Serial.println(second());

  
//Connect to Broker
  Serial.println("Attempting to connect to broker...");
  mqttclient.connect(MQTT_Broker);
  if (mqttclient.connect(MQTT_Broker)) {
    Serial.println("Connected to broker!");
  }
  else {
    Serial.println("Failed to connect to broker!");
  }
}

void loop(void)
{
  mqttclient.connect(MQTT_Broker);

  delay(2000);
  display.clearDisplay();
  val = digitalRead(inputPin);  // read input value

  //Sensor Setup
  char buf[16];
  
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature(false); //false = C, true = F
 
  //Light Sensor int to String, to char array

  sensors_event_t eventroom;
  tslroom.getEvent(&eventroom);
  float lightroom = eventroom.light;
  char* strLightRoom = dtostrf(lightroom, 5, 0, buf);
  Serial.print(strLightRoom);
  mqttclient.publish("lightroom", strLightRoom);
  display.print("LUX R: ");
  display.println(strLightRoom);

  sensors_event_t eventwin;
  tslwin.getEvent(&eventwin);
  float lightwin = eventwin.light;
  String strLightWin = dtostrf(lightwin, 5, 0, buf);
  String payload = "{\"DeskSensor\":{\"Temperature C\":";
   payload += strLightWin;
   payload += ",\"timestamp \":";
   payload += hourFormat12();
   payload += "}}";
  Serial.print(strLightWin);
  mqttclient.publish("lightwin", (char*) payload.c_str());
  display.print("LUX W: ");
  display.println(strLightWin);

  //Humidity Sensor int to String, to char array
  char* strHumidity = dtostrf(humidity, 5, 1, buf);
  Serial.println(strHumidity);
  mqttclient.publish("hum", strHumidity);
  display.print("Hum: ");
  display.print(strHumidity);
  display.println("%");

  //Temperature Sensor int to String, to char array
  char* strTemp = dtostrf(temperature, 5, 1, buf);
  Serial.println(strTemp);
  mqttclient.publish("temp", strTemp);
  display.print("Temp: ");
  display.print(strTemp);
  display.println("C");
    if (val == HIGH) {            // check if the input is HIGH
      if (pirState == LOW) {
        // we have just turned on
        Serial.println("Motion detected!");
        // We only want to print on the output change, not state
        pirState = HIGH;
        timer = 0;
      }
    } else {
      if (pirState == HIGH){
        // we have just turned of
        Serial.println("Motion ended!");
        // We only want to print on the output change, not state
        pirState = LOW;
      }
    }
    timer++;
    sprintf(buffer,"Timer at: %d", timer);
    Serial.print(buffer);
    mqttclient.publish("motion", "Motion Detected");
    display.println(buffer);
    if (timer >= 15){
      Serial.println("USER LEFT!");
      display.println("USER LEFT!");
    }
  display.display();
}

void configureSensor(void)
{
  tslroom.enableAutoRange(true);
  tslroom.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS);
  tslwin.enableAutoRange(true);
  tslwin.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS);
  
}

Note:

  • TSL2561 in the diagram is missing the INT pin, but this doesn't matter as it is not in use.
  • Diagram shows Arduino Uno because the project was initially based on it and has been migrated to the Mega. The only differences that this make is that the SDA and SCL pins that originally connect through the CC3000 to the Arduino are left hanging and the connect is instead made to the SDA and SCL pins on the Mega itself.

Any assistance would be much appreciated!

Cheers!

A4 and A5 are the i2c pins on the Uno, but not on a Mega. On the mega, the i2c pins are D20 and D21.

One of the sensors is connected to D20 and D21, its the other that isn't working.

I've just realised that the uno i was using is the R3 variation, which has dedicated SDA SCL inputs. My Mega is not an R3. Does this mean that I can only interface one i2c device to it via D20, D21?

I've just realised where I've gone wrong. I understood that I could setup the sensors by changing the Addr pin, but I thought it was just a way for the Arduino to distinguish between multiple units connecting to the board and not necessarily through the same i2c port. That makes a whole lot more sense.

I'm still only getting one output with both of the i2c sensors going through D20, D21. Any ideas? Different library for the mega vs uno maybe??

Do the sensors have different I2C addresses? Sometimes there are 1 or 2 or 3 address lines that are user settable so the same part can have 2, 4, or 8 different base addresses to respond to.
If they are the same address, then who knows which one is really responding.
If they are different, does the code address them both?

The sensors do have different I2C addresses. I specify this in the program here:

Adafruit_TSL2561_Unified tslroom = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 1);
Adafruit_TSL2561_Unified tslwin = Adafruit_TSL2561_Unified(TSL2561_ADDR_LOW, 2);

With the TSL2561, the i2c address can be changed as seen in the library (Adafruit_TSL2561_Unified) header file:

// I2C address options
#define TSL2561_ADDR_LOW          (0x29)
#define TSL2561_ADDR_FLOAT        (0x39)    // Default address (pin left floating)
#define TSL2561_ADDR_HIGH         (0x49)

Since the setup works on the Uno, its unlikely to be an addressing problem, no? Does the Mega behave differently to the Uno in this fashion?

Tried the setup on a Mega R3 instead of an R2 and it works.

There shouldn't be any difference on the i2c on the Mega R3 and R2, except the R3 model has D20 and D21 duplicated on the SDA and SCL pins.

The Due has two i2c buses, one on D20/21 and the other on SDA1/SCL1.