I2C Load Cell Intermittency

Status
Not open for further replies.

matt_0

New member
Hi all,

What I keep running into is that my I2C load cell sensor will return values that don't make any sense. Sometimes 0, sometimes 2000, sometimes 14000, etc (it should be ~800-1000 with no load). If I short the connection between SCL/SDA everything starts to work as it should. It continues to work until the Teensy is unplugged.

I'm working on using a Teensy 3.5 read data in from a load cell connected via I2C. The load cell that I am using is FX29K0-100A-0025-L. The relevant datasheet is here.

The load cell is powered off of 3.3V from the Teensy. I am using pins 18 and 19 for the standard SCL/SDA.

I'm using external 5 kOhm pull-up resistors. I've tried several different resistance values (1k, and 10k) with no real changes.

I've tried using the Wire.resetBus() function in the setup with no luck. I've found the best clock frequency (the one that works) is 100kHz. I've tried polling the sensor with the IntervalTimer at lower and higher frequencies. I've tried inserting delays many spots, but haven't found the right spot or timing I guess.

I've tried using both the Wire.h library and the i2c_t3.h library with similar results. I've never worked with I2C before, so I am hoping I am missing something simple. I'm using windows 10.

Here is the schematic of the circuit image0.jpg

Here is the code I am using within teensyduino:

Code:
#include <i2c_t3.h>

// Load Cell
int wire_in = 40; //0x28 from data sheet
uint8_t bridge_data[2] = {0}; //2 bytes to pull data from sensor
bool force_flag = false;
int force_counts = 0;

//  Teensy3.5 pins 19 SCL, 18 SDA 
//  Teensy3.5 requires external pullup resistors ~4.7kOhm
//  FX29 Red (V+), Black (V-), Yellow (SCL) (19), White (SDA) (18)

// Timer to call function at specific frequency
IntervalTimer forceDataTimer;

// RawHID Print Buffer:
byte print_buffer[64];
int buffer_count = 0;
byte f_data = 0x46; //'F'

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  delay(100);
  //I2C Interface: Load cell  
//  Wire.begin();
//  Wire.setClock(100000);
//  delay(1000);
//  Wire.beginTransmission(wire_in); //get ready to tell sensor we want data
//  Wire.write(0); //tell sensor we want data
//  Wire.endTransmission();     
//  delay(1000);  //wait for it to come alive

  Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 100000); 
  delay(1000);

  //Get force data interupt  
  forceDataTimer.begin(getForceISR, 2000); //2000us = 500hz
}

void loop() {  
  // Load Cell Main Loop
  if (force_flag) {
    print_buffer[buffer_count] = f_data;
    print_buffer[buffer_count+1] = bridge_data[0];
    print_buffer[buffer_count+2] = bridge_data[1] & 0x3f;
    buffer_count+=3;    
    force_counts = (bridge_data[0] << 8 | bridge_data[1]) & 0x3fff;     
    force_flag = false; 
  }

  if (buffer_count >= 61) {
    for (int i=buffer_count+1; i<63; i++) {
      print_buffer[i] = 0;
    }
    RawHID.send(print_buffer, 100);
//    Serial.println(force_counts);
    buffer_count = 0;
  }    
}

// Force I2C interrupt routine
void getForceISR() {  
  if (!force_flag) {
    digitalWrite(LED_BUILTIN, HIGH);
    Wire.beginTransmission(wire_in); //get ready to tell sensor we want data
    Wire.write(0); //tell sensor we want data
    Wire.endTransmission();   
    int ec = Wire.requestFrom(wire_in, 2); //request two bytes of data
    if (ec==0) {
      Serial.println("Device not responding");
    }
    else {
//      bridge_data[0] = Wire.read();
//      bridge_data[1] = Wire.read();
      Wire.read(bridge_data, Wire.available());
    }    
    force_flag = true;
    digitalWrite(LED_BUILTIN, LOW);
  }
}
 
I am a bit concerned with the lack of a delay from requesting data to reading it. The data sheet is a bit opaque on the conversion time. To sidestep that I would reverse the order of operations in getForceISR(). First read the data from the previous conversion and the send the command to start a new one. Then so long as the time between calls is greater than the conversion time, you should be safe. The upper two bits of the data returned are described as status bits but I don't see a description of them.

I don't see anything on conversion time but I do see a response time of from3ms to 8.3ms depending on sleep mode. However you put it in that. So start at 100Hz and see how fast you can push it before it breaks.
 
UhClem - Thanks for checking this out for me. The datasheet really is sparse for this sensor - had I known this going in I would've found something else!

Per your suggestion - I switched the order of operations in the getForceISR, so that I Wire.read() first and then ask for the next piece of data. I also lowered the interrupt frequency down to 100 Hz. Initially this didn't work. I could see that it was hanging in getForceISR because of the brightness of the LED. It turns out, if I reboot with teensyduino after reprogramming, the I2C sensor seems to stay stalled. No matter what I change the interval frequency too. However, if I power cycle it (unplug/plug) everything starts to work again even after several power cycles at 100hz. I was then able to push the frequency up to 1kHz without issues.

I mistakenly read the response time as the rise time of the sensor. So now looking at again, it looks like it's not meaningful to push the sensor over ~300Hz anyways (as long as it doesn't go to sleep...). Thanks for pointing this out too!
 
Status
Not open for further replies.
Back
Top