I2c Wire.endTransmission() only executed when FTDI cable is shaken around

Hi,

I'm currently using an Arduino Fio and attempting to communicate with an ADC over I2C. When I run my code, it hangs at Wire.endTransmission() in the setup. However, I noticed that when I shook the FTDI cable, it stopped hanging, and I was able to get conversion results. My FTDI cable is fitted with male header pins and is put directly into the holes on the Fio.

Is there any way I can get the entire setup to be done smoothly? I have tried using an alternative I2C library (DssCircuits.com is for sale | HugeDomains), and obtained the same results. I also tried sending each byte in a Wire.write command, instead of all together in an array. I also tried casting the message as a byte array (i.e. Wire.write((uint8_t*)&adc_setup, 3)), but to no avail.

Interestingly, the Wire.endTransmission(adc_stop) in the loop does not hang the program. adc_stop is a boolean false, used to prevent the sending of the stop signal. However, even when I try to do the same in setup, it still does not work.

Initially, I thought it was the hard reset button that did the trick. However, I am now quite sure it is not the hard reset button, as I held the FTDI cable firmly against the Fio and pressed the reset button - it only restarted the sketch (which still froze). I suppose that the first few times when I pressed the reset button it jiggled the FTDI cable slightly.

And yes, my Fio was turned on.

Any advice would be much appreciated!

#include <I2C.h>
#include <Wire.h>

const byte  adc_address = B0100000;     // I2C Address of ADC Chip
const byte  adc_config_add = B00000010; // Internal address of configuration register
const byte  adc_conver_add = B01110000; // Address pointer for conversion result register in command mode
const byte  adc_config_MSB = B00001111; // Most significant byte of configuration register, select channels 8 to 5
const byte  adc_config_LSB = B11111011; // Least significant byte of configuration register, select channels 4 to 1
                                        // Enable filtering on SDA/SCL lines, busy output, and active high for busy pin
const boolean adc_stop = false;         // Stop parameter for endTransmission that sends a restart and keeps connection active

byte adc_setup[] = {byte(adc_config_add), byte(adc_config_MSB), byte(adc_config_LSB)};   // Array to store setup data to write to ADC
//byte adc_setup[] = {byte(adc_config_MSB), byte(adc_config_LSB)};   // Array to store setup data to write to ADC configuration register

unsigned int adc_data[10];              // Array to store ADC values for 10 bits (8 channels)

int soft_reset_count = 0;

void setup() {

  //Start Serial port
  Serial.begin(9600);                   // start serial for output
  Serial.println("Serial port has been opened");

  //Send settings to ADC I2C device
  Wire.begin();                         // Join i2c bus (address optional for master)
  I2c.pullup(0);                        // Disable internal pullups
  Wire.beginTransmission(adc_address);  // Transmit to ADC
  Serial.println("Transmission to ADC has been initiated");
  Wire.write(adc_setup, 3);             // Send config options
  Wire.write((uint8_t*)&adc_setup, 3);             // Send config options
  for (int i = 0; i < 3; i++) {
    Serial.println(adc_setup[i], BIN);  // Display configuration register address and messages sent
  }
  //  Wire.write(byte(adc_config_add));   // Send configuration register address and messages as separate bytes
  //  Wire.write(byte(adc_config_MSB));
  //  Wire.write(byte(adc_config_add));
  Serial.println("Wire.write of configuration data has been executed");
  Wire.endTransmission(adc_stop);               // Stop transmitting
  //  I2c.write(byte(adc_address), byte(adc_config_add), (uint8_t*)&adc_setup, 2);  // Use alternate I2c library to configure ADC
  Serial.println("ADC has been configured");
}

void loop() {
  get_adc();                            // read data from adc

  // Test print data received from ADC
  for (int i = 0; i < 10; i++)
  {
    Serial.print(adc_data[i], BIN);     // print the character in binary
    Serial.print(",");                  // print comma
  }
  Serial.println("");                   // print carriage return
  delay(500);
}

// Function to get data from ADC
void get_adc() {
  unsigned char hi_lo_byte;             // Keep track of high or low byte, 1 for high byte, 0 for low byte
  hi_lo_byte = 1;                       // First byte will be a high byte
  unsigned char data_values_rcvd = 0;   // keep track of how many chars received
  unsigned char adc_buffer;

  Wire.beginTransmission(adc_address);  // Transmit to ADC
  Wire.write(adc_conver_add);           // Write to address pointer to read from conversion result register in command mode
  Wire.endTransmission(adc_stop);       // Transmit bytes queued by byte() and issue restart so connection remains active
  Serial.println("Conversion result register address sent");
  while (Wire.available()) {
    if (hi_lo_byte) {                  // Its a high byte
      adc_buffer = Wire.read() << 8;  // receive high byte and shift left 8
      // Extract MSB to B6 of sample and put in data array in position dependent on channel
      adc_data[0] += (B1 & (adc_buffer >> 3)) >> data_values_rcvd;
      adc_data[1] += (B1 & (adc_buffer >> 2)) >> data_values_rcvd;
      adc_data[2] += (B1 & (adc_buffer >> 1)) >> data_values_rcvd;
      adc_data[3] += (B1 & (adc_buffer)) >> data_values_rcvd;
      hi_lo_byte = 0;                 // next byte will be a low byte
    }
    else {
      adc_buffer = Wire.read();       // receive low byte
      // Extract B5 to B0 of sample and put in data array in position dependent on channel
      adc_data[4] += (B1 & (adc_buffer >> 7)) >> data_values_rcvd;
      adc_data[5] += (B1 & (adc_buffer >> 6)) >> data_values_rcvd;
      adc_data[6] += (B1 & (adc_buffer >> 5)) >> data_values_rcvd;
      adc_data[7] += (B1 & (adc_buffer >> 4)) >> data_values_rcvd;
      adc_data[8] += (B1 & (adc_buffer >> 3)) >> data_values_rcvd;
      adc_data[9] += (B1 & (adc_buffer >> 2)) >> data_values_rcvd;
      data_values_rcvd++;             // Increase counter for number of channels that have been read from
      hi_lo_byte = 1;                 // next byte will be a high byte
    }
  }
}

void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers
{
  asm volatile ("  jmp 0");
}

What is the I2C library, is that something special for the Fio ?

Do you know that you send the 3 config bytes two times ? I think the second one is not okay, that means you are sending illegal data to the ADC.

Did you write in your post which ADC it is ?

Shifting a value 8 bits to the left and putting that value in a byte means that the resulting byte is always zero.

It is not okay to read data, without Wire.requestFrom().

A I2C bus could hang at Wire.endTransmission() if for example SDA or SCL is shortcut to GND or SDA is shortcut to SCL or the sensor is not powered.

Hello, thanks a lot for the feedback! I've corrected those issues and it does not hang any more. I did still have to jiggle the FTDI cable to make it work, but when I checked the SDA and SCL lines with a scope the signals were getting sent. I suspect it was just a connection issue.