I have a frustratingly simple problem. I’m using the Particle Electron and there are two i2c buses (Wire and Wire1). I have two TCS34725 color sensors (one on each bus). I’m trying to read from the first sensor and then the second. When I run the code below, I get the same value printed for both sensor 1 and 2. More specifically both serial prints (sensor 1 and sensor 2) return the value read on sensor 1 (Wire)
Some notes:
Sensor 1 and sensor 2 are identical functions apart from Wire being changed to Wire1
If I break off the sensor function into it’s own program I can toggle between Wire and Wire1 and the sensors read as expected. It’s only the combination that seems to give me problems
I am re-initializing the sensor every read. I did that in a final attempt of “well if this doesn’t work”, once I figure out the issue, I’ll move it to setup.
I scanned the i2c ports to double check the address of the TCS34725 is the same on both buses
We have a spun board so I know the wiring is correct
I’ve included the code below. I’d appreciate any help!
#include <application.h>
#include <spark_wiring_i2c.h>
// TCS34725 I2C address is 0x29(41)
#define Addr 0x29
void setup()
{
Particle.disconnect();
// Initialise Serial Communication, set baud rate = 9600
Serial.begin(9600);
}
void sensor1()
{
unsigned int data[8];
int red = 0, green = 0, blue = 0, cData = 0;
// Initialise I2C communication as MASTER
Wire.begin();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select Wait Time register
Wire.write(0x83);
// Set wait time = 2.4 ms
Wire.write(0xFF);
// Stop I2C Transmission
Wire.endTransmission();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select Atime register
Wire.write(0x81);
// Atime = 700 ms, max count = 65536
Wire.write(0x00);
// Stop I2C Transmission on the device
Wire.endTransmission();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select control register
Wire.write(0x8F);
// AGAIN = 1x
Wire.write(0x00);
// Stop I2C Transmission
Wire.endTransmission();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select enable register
Wire.write(0x80);
// Power ON, RGBC enable, wait time disable
Wire.write(0x03);
// Stop I2C Transmission
Wire.endTransmission();
delay(800);
// Start I2C Transmission on the device
Wire.beginTransmission(Addr);
// Select data register
Wire.write(0x94);
// Stop I2C Transmission on the device
Wire.endTransmission();
// Request 8 byte of data from the device
Wire.requestFrom(Addr, 8);
// Read 8 bytes of data
// cData lsb, cData msb, red lsb, red msb, green lsb, green msb, blue lsb, blue msb
if (Wire.available() == 8)
{
data[0] = Wire.read();
data[1] = Wire.read();
data[2] = Wire.read();
data[3] = Wire.read();
data[4] = Wire.read();
data[5] = Wire.read();
data[6] = Wire.read();
data[7] = Wire.read();
}
Wire.endTransmission();
// Convert the data
cData = (data[1] * 256) + data[0];
red = (data[3] * 256) + data[2];
green = (data[5] * 256) + data[4];
blue = (data[7] * 256) + data[6];
Serial.println(cData);
Serial.println(red);
Serial.println(green);
Serial.println(blue);
Serial.println("Wire");
}
void sensor2()
{
unsigned int data[8];
int red = 0, green = 0, blue = 0, cData = 0;
// Initialise I2C communication as MASTER
Wire1.begin();
// Start I2C Transmission
Wire1.beginTransmission(Addr);
// Select Wait Time register
Wire1.write(0x83);
// Set wait time = 2.4 ms
Wire1.write(0xFF);
// Stop I2C Transmission
Wire1.endTransmission();
// Start I2C Transmission
Wire1.beginTransmission(Addr);
// Select Atime register
Wire1.write(0x81);
// Atime = 700 ms, max count = 65536
Wire1.write(0x00);
// Stop I2C Transmission on the device
Wire1.endTransmission();
// Start I2C Transmission
Wire1.beginTransmission(Addr);
// Select control register
Wire1.write(0x8F);
// AGAIN = 1x
Wire1.write(0x00);
// Stop I2C Transmission
Wire1.endTransmission();
// Start I2C Transmission
Wire1.beginTransmission(Addr);
// Select enable register
Wire1.write(0x80);
// Power ON, RGBC enable, wait time disable
Wire1.write(0x03);
// Stop I2C Transmission
Wire1.endTransmission();
delay(800);
// Start I2C Transmission on the device
Wire1.beginTransmission(Addr);
// Select data register
Wire1.write(0x94);
// Stop I2C Transmission on the device
Wire1.endTransmission();
// Request 8 byte of data from the device
Wire1.requestFrom(Addr, 8);
// Read 8 bytes of data
// cData lsb, cData msb, red lsb, red msb, green lsb, green msb, blue lsb, blue msb
if (Wire1.available() == 8)
{
data[0] = Wire1.read();
data[1] = Wire1.read();
data[2] = Wire1.read();
data[3] = Wire1.read();
data[4] = Wire1.read();
data[5] = Wire1.read();
data[6] = Wire1.read();
data[7] = Wire1.read();
}
Wire1.endTransmission();
// Convert the data
cData = (data[1] * 256) + data[0];
red = (data[3] * 256) + data[2];
green = (data[5] * 256) + data[4];
blue = (data[7] * 256) + data[6];
Serial.println(cData);
Serial.println(red);
Serial.println(green);
Serial.println(blue);
Serial.println("Wire1");
}
void loop()
{
//sensor1();
sensor2();
sensor1();//This one works... sensor2 doesn't
while(Serial.read()!=116){}
}
I had been using 0.6.2 I recompiled with 0.7.0-rc3 still having the same problem. Just as sanity on how I did this at the bottom of the IDE I clicked the tag and changed from 0.6.2 to 0.7.0-rc3. When I flashed my code the Electron blinked magenta for a bit (updating firmware) then ran as expected.
I also commented out #include <spark_wiring_i2c.h> as that should be covered in <application.h> (at least it didn’t give me any compile or additional run issues )
I added an error check on the endTransmission if(Wire.endTransmission()!=0){Serial.println("error");} before //Convert the data to see if something wasn’t getting properly terminated… no issues there.
@ScruffR
Okay I downloaded the binaries from the link you provided and ran the following from the command line (including tinker)
Then I recompiled my program with the appropriate tag 0.7.0-rc.3 (selected in the IDE) and flashed… now “Wire1” doesn’t work even when separated out into its own program. When I say doesn’t work I mean that previously if I separated Wire and Wire1 into separate programs, they would read from the appropriate (respective) sensor. Now Wire and Wire1 read from the same sensor (the one previously assigned to Wire) regardless of whether they are separated into their own program.
These pins are used via the Wire object.
SCL => D1
SDA => D0
Additionally on the Electron, there is an alternate pin location for the I2C interface, which can be used via the Wire1 object. This alternate location is mapped as follows:
SCL => C5
SDA => C4
Note: Because there are multiple I2C locations available, be sure to use the same Wire or Wire1 object with all associated functions. I.e.,Do NOT use Wire.begin() with Wire1.write();Do use Wire1.begin() with Wire1.transfer();
This suggests to me that there is something looming over this issue. You don't see that warning anywhere in the Serial discussion, for example.
I’d read that - but might still be wrong - as: “Don’t be surprised that Wire.write() won’t work if you initialised with Wire1.begin(), since that switched the HW interface over to the alternative pins so you won’t have it attached to the Wire pins (unless you switch it back with Wire.begin())”
I’m going to go with that you can’t use both Wire and Wire1 in the same program. The reason is likely that both sets of pins are connected to the same I2C block in the STM32F205 processor I2C1.
Here’s my test circuit. There are two DS75 I2C temperature sensors, connected to Wire (D0/D1) and Wire1 (C4/C5).
@ScruffR@BulldogLowell@rickkas7 First off thanks for the feedback. Good to know that I’m not crazy for something that seemed super simple.
So here’s my problem, our group has already spun a board so updating the hardware isn’t an easy option. It’s a pretty big deal for us to change our board at this point (we’re small and on a tight budget). Is there anyone at Particle I could possibly DM to find out definitively whether the hardware can or cannot support writing to Wire and Wire1 in the same program?
…unfortunately if the Particle hardware can’t support it, we’ll have to bite the bullet. I’d just really like to know for sure before I try and broach that conversation. Please feel free to DM me and thank you again for your help!
Here is the relevant code in firmware/hal/src/stm32f2xx/i2c_hal.c and the comment seems very definitive:
void HAL_I2C_Begin(HAL_I2C_Interface i2c, I2C_Mode mode, uint8_t address, void* reserved)
{
STM32_Pin_Info* PIN_MAP = HAL_Pin_Map();
#if PLATFORM_ID == 10
/*
* On Electron both I2C_INTERFACE1 and I2C_INTERFACE2 use the same peripheral - I2C1,
* but on different pins. We cannot enable both of them at the same time.
*/
if (i2c == HAL_I2C_INTERFACE1 || i2c == HAL_I2C_INTERFACE2) {
HAL_I2C_Interface dependent = (i2c == HAL_I2C_INTERFACE1 ? HAL_I2C_INTERFACE2 : HAL_I2C_INTERFACE1);
if (HAL_I2C_Is_Enabled(dependent, NULL) == true) {
// Unfortunately we cannot return an error code here
return;
}
}
#endif
Wire.begin();
Wire.write(x);
Wire.end(); // can't see the end() call in any of the tests above
Wire1.begin();
Wire1.write(y);
Wire1.end(); // can't see the end() call in any of the tests above
Okay, it works! Looks like you need both Wire.end (which as I understand it releases the pins and allows them to be used for subsequent I/O) and to reassign the Pins before the next Wire1.begin. I pasted the working function below for others future reference!
Thanks again for the help!
void sensor1()
{
unsigned int data[8];
int red = 0, green = 0, blue = 0, cData = 0;
// Initialise I2C communication as MASTER
Wire.begin();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select Wait Time register
Wire.write(0x83);
// Set wait time = 2.4 ms
Wire.write(0xFF);
// Stop I2C Transmission
Wire.endTransmission();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select Atime register
Wire.write(0x81);
// Atime = 700 ms, max count = 65536
Wire.write(0x00);
// Stop I2C Transmission on the device
Wire.endTransmission();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select control register
Wire.write(0x8F);
// AGAIN = 1x
Wire.write(0x00);
// Stop I2C Transmission
Wire.endTransmission();
// Start I2C Transmission
Wire.beginTransmission(Addr);
// Select enable register
Wire.write(0x80);
// Power ON, RGBC enable, wait time disable
Wire.write(0x03);
// Stop I2C Transmission
Wire.endTransmission();
delay(800);
// Start I2C Transmission on the device
Wire.beginTransmission(Addr);
// Select data register
Wire.write(0x94);
// Stop I2C Transmission on the device
Wire.endTransmission();
// Request 8 byte of data from the device
Wire.requestFrom(Addr, 8);
// Read 8 bytes of data
// cData lsb, cData msb, red lsb, red msb, green lsb, green msb, blue lsb, blue msb
if (Wire.available() == 8)
{
data[0] = Wire.read();
data[1] = Wire.read();
data[2] = Wire.read();
data[3] = Wire.read();
data[4] = Wire.read();
data[5] = Wire.read();
data[6] = Wire.read();
data[7] = Wire.read();
}
if(Wire.endTransmission()!=0){Serial.println("error");}
Wire.end();
while(Wire.isEnabled()==TRUE){Serial.println("Wire hasn't been released"); Serial.println(Wire.isEnabled()); delay(10000);}
pinMode(C4, INPUT);
pinMode(C5, INPUT);
pinMode(D0, INPUT);
pinMode(D1, INPUT);
// Convert the data
cData = (data[1] * 256) + data[0];
red = (data[3] * 256) + data[2];
green = (data[5] * 256) + data[4];
blue = (data[7] * 256) + data[6];
Serial.println(cData);
Serial.println(red);
Serial.println(green);
Serial.println(blue);
Serial.println("Wire");
}