Skip to content

Add ADS131m0x support for load cells#838

Merged
dalegaard merged 2 commits intoKalicoCrew:mainfrom
garethky:pr-sensor-ads131m02
Mar 23, 2026
Merged

Add ADS131m0x support for load cells#838
dalegaard merged 2 commits intoKalicoCrew:mainfrom
garethky:pr-sensor-ads131m02

Conversation

@garethky
Copy link
Copy Markdown
Contributor

@garethky garethky commented Feb 19, 2026

This adds support for the ADS131M02 and ADS131M04. These share a general architecture so they can have a single MCU driver.

The main difference between the variants is the frame size. Each frame is composed of 24 bit words. Each frame is 2 words (status & crc) + 1 word for each channel:

M02: [STATUS, CHANNEL0, CHANNEL1, CRC]
M04: [STATUS, CHANNEL0, CHANNEL1, CHANNEL2, CHANNEL3, CRC]

All writes to registers require sending a complete frame and reading back a complete frame. The register addresses are the same across all models in the sensor family (02, 04, 06 & 08). TI designed it so we don't need separate code for each one.

The 04 variant can simultaneously sample 4 channels. The goal with that chip is to support under-bed load cells where a reading would be taken independently from each load cell. In the commercial world there is a piece of hardware called a "Summing Box" that electrically sums multiple load cells together to make large scales (think for semi trucks).

Basic summing box support is in this PR that fuses multiple sensor channels into a single LoadCell. The MCU side code for the sensor also sums the values and passes the sum to the load_cell_probe for triggering. More advanced features, like taring of individual channels is left for another future PR.

Checklist

  • pr title makes sense
  • added a test case if possible
  • if new feature, added to the readme
  • ci is happy and green

Copy link
Copy Markdown
Contributor

@dalegaard dalegaard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have done quick review, but not reviewed/commented on anything saying TODO.

adc->sb.data[adc->sb.data_count + 1] = counts >> 8;
adc->sb.data[adc->sb.data_count + 2] = counts >> 16;
adc->sb.data[adc->sb.data_count + 3] = counts >> 24;
adc->sb.data_count += BYTES_PER_SAMPLE;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the sensor data is 24 bits, can't we just send 3 bytes and do sign handling on the host? It seems like one byte would always be zero here? counts at the call site looks to only fill 3 bytes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually an optimization: Python doesn't have a 24bit type that can be used with struct.unpack (because c doesn't have a 24 bit datatype).

Early on when I tried to get the sensors to go fast I discovered that manually bit shifting in python to create each int was one of the major performance bottlenecks. Switching to stuct.unpack moved this into python's c routines and is a huge speedup.

This improvement was folded into FixedFrequencyReader and now any data sent over the BulkSensor mechanism must be amenable to struct.unpack.

@garethky garethky force-pushed the pr-sensor-ads131m02 branch 3 times, most recently from b70c306 to be1b3b0 Compare March 1, 2026 03:20
@garethky garethky changed the title Add ads131m02 support for load cells Add ADS131m0x support for load cells Mar 1, 2026
ADC Sensors can sample more than a single channel if multiple physical load cells are connected. The LoadCell instance will sum those discrete readings to give a single weight value. This is similar to a "summing box" in a real world phyiscal load cell setup.

The data for the additional channels is re-broadcast so it can be charted in debugging tools.

TODO:
* Display individual channel data in commands like LOAD_CELL_READ and LOAD_CELL_DIAGNOSTIC
@garethky garethky force-pushed the pr-sensor-ads131m02 branch 2 times, most recently from c9a380c to f5c63aa Compare March 18, 2026 22:42
@garethky garethky marked this pull request as ready for review March 18, 2026 22:51
Copy link
Copy Markdown
Contributor

@dalegaard dalegaard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks very nice. Will get it tested on my board asap!

@garethky garethky force-pushed the pr-sensor-ads131m02 branch from f5c63aa to 285b2f3 Compare March 19, 2026 20:24
# GAIN register (0x04): PGAGAIN0[2:0] at bits 2:0, PGAGAIN1[2:0] at bits 6:4
self._write_and_verify_reg(GAIN1_REG, self._gain_register_value())
self.reactor.delay_for_ms(50.0)
status = self._read_reg(STATUS_REG)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading the status here is just done to aid in debugging. But nothing about it is verified or used. This could be removed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While not actually used, I like having this status output. It should prefix with the sensor type and name though, like the other logging statements.

super().__init__(
config,
sensor_type="ads131m02",
sample_rate_options={
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sample rate options are duplicated. these can be pulled back up into the base class.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to the constants area

@garethky garethky force-pushed the pr-sensor-ads131m02 branch 3 times, most recently from 5780c9d to ed0b8c3 Compare March 20, 2026 23:22
Copy link
Copy Markdown
Contributor

@dalegaard dalegaard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to work well, just a few tiny changes and then we'll get this merged!

# GAIN register (0x04): PGAGAIN0[2:0] at bits 2:0, PGAGAIN1[2:0] at bits 6:4
self._write_and_verify_reg(GAIN1_REG, self._gain_register_value())
self.reactor.delay_for_ms(50.0)
status = self._read_reg(STATUS_REG)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While not actually used, I like having this status output. It should prefix with the sensor type and name though, like the other logging statements.

* Support for configuring one or more channels to be summed.
* Configure the sample rate and gain
* Enable high perfomrance mode by default
* Check for unexpected device resets and CRC data errors while sampling

Signed-off-by: Gareth Farrington <gareth@waves.ky>
@garethky garethky force-pushed the pr-sensor-ads131m02 branch from ed0b8c3 to 6e10bcd Compare March 23, 2026 21:11
@dalegaard dalegaard merged commit 8f9b61f into KalicoCrew:main Mar 23, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants