FX29 compact load cell - reading I2C data

I purchased the FX29K0-100A-0050-L compact load cell made by TE. I have it connected to the I2C bus of a BeagleBone black and can see the device on the bus. I am trying to read data with a C program and struggling to understand how to do this. The data sheet isn’t very helpful. I don’t think it says what I should write to the device to trigger a read.

I can’t find any example code in any language for how to do this. I’ve used other I2C devices (RTCs, pressure sensors, etc.) and have not had luck modifying any of that code to make this one work. I can see the bus and the device with my code. I just can’t get a reading.

Help would be greatly appreciated!

Welcome to the Technical Forum. I am going to send this off to the group to see if anyone can help on this one. I could not find anything either on this. We will get back to you soon.

1 Like

There’s some info starting on p.10 of the datasheet describing the protocol, though it does seem rather sparse.

First order of business is to ensure you’re using the right address, which should be 0x28 per p.14 and the part number. Recalling that the address changes whether one’s reading or writing though, 0x29 might be what you want for a read operation.

It may help if you could be a bit more specific about what exactly is meant by this.

Here’s some more details so you’ll see what I see.

here is how I check for the device using Linux command line.

image

And here’s what I get when I dump from 0x28 on channel 2 with no load on the load cell.

image

Here’s what I get when I dump from 0x28 on channel 2 with a 500g weight on the load cell.
There is some change but it doesn’t really make sense to me.

image

Now, switching to C code, here’s my basic code.

`

// Basic & generic includes
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
   // includes for time
#include <time.h>
#include <sys/time.h>

// includes for I2C

#include <linux/i2c-dev.h>
#include <sys/ioctl.h>


	//******  MAIN *****
int main()
{
    
	  int fd1;
	  char buf[10];
	
// Configure BeagleBone

	system("config-pin P9_19 i2c");  // reserved for I2C bus, SDA /dev/i2c-2
	system("config-pin P9_20 i2c");  // reserved for I2C bus, SCL /dev/i2c-2


    usleep(200000);
    

	
	if ((fd1 = open("/dev/i2c-1", O_RDWR)) < 0)
	
		{
	    	printf("Failed to open the bus.");
	    	exit(1);
		}
	
	if (ioctl(fd1, I2C_SLAVE, 0x28) < 0) 
		{
	    	printf("Failed to acquire bus access and/or talk to slave.\n");
	    	exit(1);
		}
	if (read(fd1, buf, 1) != 1) 
		        {
			printf("Failed to read from the i2c bus.\n");
		       } 
	        else 
		      {
			printf("%s\n",buf);
	      }
	  	}

`

Here is the output.

Current mode for P9_19 is:     i2c


Current mode for P9_20 is:     i2c

Failed to read from the i2c bus.
MODEL   = TI_AM335x_BeagleBone_Black
PROC    = arm
PRUN    =
PRU_DIR =
rm /tmp/cloud9-examples/TELoadCellExplore.o

I am curious about the comment that the read needs to come from 0X29. I didn’t find that in the documentation. It’s really not very helpful and I have contacted TE about it without any help after two days.

Thank you very much!

Part of any decent explanation of the I2C protocol (this one for example) is the idea that the LSB of the device address indicates whether the transaction is to involve a read or a write. Because that’s baked into the protocol, not every device’s documentation will mention it and it may or may not be a thing that is handled automagically by any given code library.

Something else that seems notable is that the above readouts appear to have been performed in a byte-wise fashion.
image

Not surprisingly, the datasheet indicates that a two-byte read is necessary to retrieve all the data:
image
If the controller’s hanging up the phone before the device at the other end has a chance to finish what it’s saying, the communication is not going to work well…

Personally, I find it helpful to bring an o’scope or logic analyzer to the party and observe the actual waveforms in such cases. More than once it’s cued me in to the fact that the characters on the screen had meaning other than what I thought they did.

1 Like

I don’t think i2cdump is going to be of any help here. According to the man page,

i2cdump is a small helper program to examine registers visible through the I2C bus.

The FX29 datasheet, however, does not specify any device registers. It only specifies that to start a measurement, you send a “Read_MR” command. Then, to collect the measurement, you send a “Read_DF2” command. So, I would expect something like the following would get you closer. Also, make sure you are opening the right file!

// Basic & generic includes
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
// includes for time
#include <time.h>
#include <sys/time.h>
// includes for I2C
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>

//******  MAIN *****
int main()
{
  int fd1;
  char buf[10];
	
  // Configure BeagleBone
  system("config-pin P9_19 i2c");  // reserved for I2C bus, SDA /dev/i2c-2
  system("config-pin P9_20 i2c");  // reserved for I2C bus, SCL /dev/i2c-2
  usleep(200000);
    
  if ((fd1 = open("/dev/i2c-2", O_RDWR)) < 0) // MM: i2c-1 or i2c-2?
  {
    printf("Failed to open the bus.\n");
    exit(1);
  }
	
  if (ioctl(fd1, I2C_SLAVE, 0x28) < 0) 
  {
    printf("Failed to acquire bus access and/or talk to slave.\n");
    exit(1);
  }

  if (read(fd1, buf, 0) != 0) // MM: I assume this will return 0 on success...
  {
    printf("Read_MR Command Failed.\n");
    exit(1);
  } 
  usleep(1000); // MM: This may be unnecessary...
  
  if(read(fd1, buf, 2) != 2)
  {
    printf("Read_DF2 Command Failed.\n");
    exit(1);
  } 
  else 
  {
    printf("%x%x\n",buf[1], buf[0]); // MM: start by printing in hex. A string would be useless. 
  }

  return 0;
}

This seems to work a bit better. However, the output I am reading back does not match the load on the cell. It’s a compact load cell and getting the load to balance on the ‘coin’ surface of the load cell is a bit tricky in the lab. Nevertheless, it’s not really close most of the time. It could have to do with LSB and MSB being off somehow.

1 Like

Unfortunately we don’t have a logic analyzer (we’re a very small startup) but our scope does have an I2C decoder. We haven’t used it before so we’ll give it a try.

@rick_1976 I have been able to connect our scope and put it in I2C mode. When I run the C program, the scope decodes the device address, 0X28, every time and displays that value on screen. Very cool. But it hasn’t been able to decode the rest of the packet unfortunately. I’m working to do that manually. Very cool though! Thanks for the suggestion.

@Matt_Mielke, I am using a slightly modified version of what you shared, to change some delays, etc., and I am now getting readings back from the load cell. However, the no-load or 0% output indicated on page 8 of the specifications document is not what I am reading. I’m reading below that value - 0x390 to 0x395. This is with nothing on the sensor at all.

I use the difference between the 1,000 counts at 0% and what I read to ‘zero’ my readings.

I have made a small 3D-printed mount for the load cell. I placed a 500gm lab weight used to calibrate a lab scale onto the sensor with one edge on the sensor and the other on a shim. (see photo) So, I would expect 1/2 the weight to be measured by the load cell. The reading 0x43C. When adjusted for the difference from 1,000 counts at 0%, this calculates to 538g. Twice what I would have expected.

I have also put a lab bottle of water, weighing 982gm on the sensor supported in once place by the sensor and another place by a fixed shim of the same height as the sensor. (see photos) I would expect the sensor to measure 1/2 of the 982 gm but it doesn’t. The reading is 0x43B or 223g. Multiplying by 2 gives ~447g. Way off. I could see it possibly being off a little by the geometry of the bottle contact points but not this much.

I don’t see anything in the documentation that indicates this is a non-linear sensor or not sensitive at low masses.

I realize this may be beyond the scope of this forum but TE hasn’t been much help. They’ve just referred me to projects using the load cell (their product) on Github. A bit frustrating.

It’s a real shame because this little device has a lot of promise for our product.


So, let’s say at zero you’re reading 0x393 (91510). We expect to see 0x3E8 (100010). So to ‘zero’ the load cell, your measurements need to be incremented by 1000 - 915 = 85.

With the lab weight you’re reading 0x43C (108410). So after ‘zeroing’, the adjusted measurement is 1084 + 85 = 1169.

Using the equation on page 8 of the datasheet:

1169 = \frac{14000}{50 \text{ lbf}} * \text{FORCE} + 1000
\text{FORCE} = 0.604 \text{ lbf}

Converting to Newtons, we get \text{FORCE} = 2.687 \text{ N}.

Finally, converting to mass:

m = \frac{F}{g} = \frac{2.687 \text{ N}}{9.807\frac{\text{m}}{\text{s}^2}} = 0.274 \text{ kg}

That’s about what you’re expecting, right?

I’m not sure about the lab bottle… Have you tried anything else of equivalent mass? Maybe something more rigid?

1 Like

@Matt_Mielke, I think you hit the nail on the head. I completely forgot about converting from lbf to mass. So once I did that and adjusted for the offset, it’s closer. With a temporary two-point mount, it’s not precise enough to know what proportion of the force is on the load cell and what proportion is on the other point, so simply multiplying by 2 would not necessarily give the correct answer. But now that I can confidently read the load cell, I can work on the mounting we need in the device.

If I could get two of these devices with different I2C addresses, I would be willing to add a second one to improve accuracy.

We are using this to measure the amount of ambient-temperature water in a vessel. The vessel will ‘float’ in its mounts, which have four ball-bearing side points that keep it upright and allow it to move up and down as water is added.

I think the only reason the zero count value should change is because of how the load is applied to the disk. Page 13 shows a potential shift of +/- 0.35%FS depending on how the load is applied. For the 50 lbs unit, this can be as much as 79 grams. The difference I have measured for the lab weight falls in this range (547gm vs. 500g). In our application, this is nominally 79ml of water, which is a big difference. Once fixed and adjusted, if it doesn’t change, we should be ok.

Thank you for your help. We are a startup and very small, so there is no one else here to ask about this. This forum has been a lifesaver. Digikey has been my go-to forever, so thank you all so much!

Glad to hear you can move forward on the project @walterc! We’re always glad to be of assistance.

Hi walterc,

Regarding your point about adding a second load cell with a different address, it looks like this is an option, but these are not normally stocked by distributors. One could do a special order for parts with another address, but there would likely be some lead time and possibly minimum order quantities (MOQs) for such parts.

At least for a short-term solution to this, one could use an I2C bus switch, such as the TCA9543A to allow for communicating with two I2C devices with the same address on the same I2C Master bus.

image

If you want to try this without having to spin up a circuit board, the MIKROE-4240 breaks out the pins of a TCA9543A to headers for easy connection and prototyping.

image

2 Likes