DIY I2C interface issue - Page 1
Forum section: electronics / beginners

author: Leopoldo
author_rank: Contributor
timestamp: December 30, 2015, 10:02:48 pm
content: Hello everybody!I'm working on a project that requires me to communicate via I2C to this device:https://www.adafruit.com/datasheets/TCS34725.pdfIt's a quite simple color sensor, except for the fact that it uses I2C, the only protocol that screws me up to this day.I'm working with an Arduino, but I'm not going to use it as my final board, as I'm going to convert the code so that it can be uploaded to a PIC micro. Can anybody explain me how to retrieve the color values?The real challenge is that, since I'm not going to use the pre-programmed functions of the bootloader, I have to create them on my own, which I did, sort of (they work, but I'm probably using them the wrong way). So far I managed to set the sensor timing, configuration and enable registers, but I can't figure out why I can't get the 3 goddamn colors.I post here the code I've written:boolean i2c_readB(byte *n){ // I get here the 8 bits of data from the sensorboolean err=0; // the function returns 1 if it doesn't get the acknowledgedigitalWrite(scl,0);pinMode(sda, INPUT);for(byte i=128; i>0; i/=2){digitalWrite(scl,1);*n=*n+(i*digitalRead(sda)); // crude way to say "bitshift"Serial.print(digitalRead(sda));digitalWrite(scl,0);}Serial.println("");digitalWrite(scl, 1);Serial.println(digitalRead(sda));if(digitalRead(sda)==0){err=0;Serial.println("ack received!");}else{Serial.println("error found!");err=1;}digitalWrite(scl, 0);pinMode(sda, OUTPUT);digitalWrite(sda, 1);return err;}The function get the value, which is correct, but the sensor does not acknowledge. Furthermore, I can't understand from the datasheet what's the I2C sequence to get the 3 colors one after the other...or in any other way, really.Thank you in advance! Let me know if you need more pieces of code!

author: rich
author_rank: Frequent Contributor
timestamp: December 31, 2015, 12:37:37 am
content: I've not used that device before, so can't offer any deep insight, but...Quote from: Leopoldo on December 30, 2015, 10:02:48 pmYour function is reading 8 bits from the device, then trying to read the ACK bit. I don't think this is how I2C works, the master is supposed to assert ACK if it is going to read more data (or NACK if its done and send STOP).I'm not sure how how fast ardruinos run without delay loops so be careful that bit banging doesn't run faster than the 400kHz that the slave device can handle.Quote from: Leopoldo on December 30, 2015, 10:02:48 pmSure is a crude way to do bit shift and it obfuscates your for loop too. Any reason not to do something more traditional such as:Code:byte x = 0;for(byte i=0; i<8; i++){digitalWrite(scl,1);x = (x << 1) | digitalRead(sda); // Assumes digitalRead can only return 0 or 1 which old code did toodigitalWrite(scl,0);}*n = x;When all the bit banging works, then for init and read sequences, the adafruit library code might be a good place to start:https://github.com/adafruit/Adafruit_TCS34725

author: jpmkm
author_rank: Contributor
timestamp: December 31, 2015, 01:05:08 am
content: Are you going to want to support *both* arduino and PIC in the future, or is it going to be strictly PIC? I'm not sure that code is going to end up being as portable as you think it will be. I understand what you are going for, but I honestly think it would be easier get it all working with the Arduino libraries, then porting that over to plib for the PIC should be fairly straightforward.

author: AlxDroidDev
author_rank: Frequent Contributor
timestamp: December 31, 2015, 06:02:35 am
content: Is there and special reason you're not using the Wire library? They already implement Wire.read and Wire.write, which makes it substantially easier to work with i2c devices.Besides, you should be using Wire.beginTransmission and Wire.endTransmission.If you're going to read values larger than 8 bits, just use Wire.requestFrom(address, number of bytes);In your case, and according to the datasheet, reading the 3 colors would be something like:Code:#include <Wire.h>#if defined(ARDUINO) && ARDUINO >= 100#include <Arduino.h>#define I2C_READWire.read#define I2C_WRITEWire.write#else#include <WProgram.h>#include <WConstants.h>#define I2C_READWire.receive#define I2C_WRITEWire.send#endifvoid readColors(uint8_t reg, uint16_t *valR, uint16_t *valG, uint16_t *valB){// READ REDWire.beginTransmission(0x29); // the i2c address of the device: page 3 of the datasheet.I2C_WRITE(0x16); // Register (base address of the desired color): page 13 of the datasheetWire.endTransmission();delay(1);Wire.requestFrom(0x29, (uint8_t)2); // request 2 bytes from the address above// Shift values to create properly formed integer*valR = ((I2C_READ() | I2C_READ() << 8));// READ GREENWire.beginTransmission(0x29);I2C_WRITE(0x18);Wire.endTransmission();delay(1); //Wire.requestFrom(0x29, (uint8_t)2);*valG = ((I2C_READ() | I2C_READ() << 8));// READ BLUEWire.beginTransmission(0x29);I2C_WRITE(0x1A);Wire.endTransmission();delay(1); //Wire.requestFrom(0x29, (uint8_t)2);// Shift values to create properly formed integer*valB = ((I2C_READ() | I2C_READ() << 8));}Please note that the code above is entirely untested, and may or may not work as is. It is intented to be a starting point for working with the Wire library.If the device allows (which I don't think it will, but it`s worth a shot) you can specify only the base address for RED and then read all the 6 bytes from there. If it works, it will make the routine a lot simpler:Code:void readColors(uint8_t reg, uint16_t *valR, uint16_t *valG, uint16_t *valB){Wire.beginTransmission(0x29); // the i2c address of the device: page 3 of the datasheet.I2C_WRITE(0x16); // Register (base address of the desired color): page 13 of the datasheetWire.endTransmission();delay(1);Wire.requestFrom(0x29, (uint8_t)6); // request 6 bytes, starting at the address above. Each 2 bytes is a color// Shift values to create properly formed integer*valR = ((I2C_READ() | I2C_READ() << 8));*valG = ((I2C_READ() | I2C_READ() << 8));*valB = ((I2C_READ() | I2C_READ() << 8));}