I am sampling a Kipp and Zonen net radiometer sensor that outputs a +/- 25 mV signal.
I am operating the ADS1115 16-bit A/D converter in 16x gain (+/- 256 mV full scale range), differential mode across channels AN0-AN1.
In this mode, the sensor datasheet specifies 0.0078125 mV/count.
My expectation is that I would get a this resolution across the narrower full scale range.
However, what I get is different, the resolution is 16 counts. For example, when varying the input with a trimmer, the minimum change in output is 16 counts. Is this the expected behavior (resolution is simply gain * LSB, so 16 counts for 16x gain mode? I was expecting the full 16-bit range across the +/-256 mV at 0.0078125 mV/count resolution, but in practice the resolution is 16x higher than this, at 0.125mV /count.
Schematics attached are the radiometer measurement circuit (esp32_ads1115_nrlite2_sch.png) and the trimmer measurement circuit with 0.500V voltage reference on a 20:1 voltage divider (esp32_ads1115_vref_trimmer_sch.png)
#include "Arduino.h"
#include "Wire.h"
#define I2Caddress 0x48
// Running average
//unsigned int readings[20] = {0};
unsigned char readCnt = 0;
void setup()
{
Serial.begin(115200);
// Join the I2C bus as a master (call this only once)
Wire.begin();
Serial.println("Setup completed.");
}
void loop()
{
// Step 1: Point to Config register - set to continuous conversion
Wire.beginTransmission(I2Caddress);
// Point to Config Register
Wire.write(0b00000001);
// Write the MSB + LSB of Config Register
// MSB: Bits 15:8
// Bit 15 0=No effect, 1=Begin Single Conversion (in power down mode)
// Bits 14:12 How to configure A0 to A3 (comparator or single ended)
// 000 : AINP = AIN0 and AINN = AIN1 (default)
// 001 : AINP = AIN0 and AINN = AIN3
// 010 : AINP = AIN1 and AINN = AIN3
// 011 : AINP = AIN2 and AINN = AIN3
// 100 : AINP = AIN0 and AINN = GND
// 101 : AINP = AIN1 and AINN = GND
// 110 : AINP = AIN2 and AINN = GND
// 111 : AINP = AIN3 and AINN = GND
// Bits 11:9 Programmable Gain 000=6.144v 001=4.096v 010=2.048v .... 111=0.256v
// 000 : FSR = ±6.144 V
// 001 : FSR = ±4.096 V
// 010 : FSR = ±2.048 V (default)
// 011 : FSR = ±1.024 V
// 100 : FSR = ±0.512 V
// 101 : FSR = ±0.256 V
// 110 : FSR = ±0.256 V
// 111 : FSR = ±0.256 V
// Bits 8 0=Continuous conversion mode, 1=Power down single shot
Wire.write(0b01001100);
// LSB: Bits 7:0
// Bits 7:5 Data Rate (Samples per second) 000=8, 001=16, 010=32, 011=64,
// 100=128, 101=250, 110=475, 111=860
// Bit 4 Comparator Mode 0=Traditional, 1=Window
// Bit 3 Comparator Polarity 0=low, 1=high
// Bit 2 Latching 0=No, 1=Yes
// Bits 1:0 Comparator # before Alert pin goes high
// 00=1, 01=2, 10=4, 11=Disable this feature
Wire.write(0b00000011);
// Send the above bytes as an I2C WRITE to the module
Wire.endTransmission();
// ====================================
// Step 2: Set the pointer to the conversion register
Wire.beginTransmission(I2Caddress);
//Point to Conversion register (read only , where we get our results from)
Wire.write(0b00000000);
// Send the above byte(s) as a WRITE
Wire.endTransmission();
// =======================================
// Step 3: Request the 2 converted bytes (MSB plus LSB)
Wire.requestFrom(I2Caddress, 2);
// Read two bytes and convert to full 16-bit int
uint16_t convertedValue;
// Read the the first byte (MSB) and shift it 8 places to the left then read
// the second byte (LSB) into the last byte of this integer
convertedValue = (Wire.read() << 8 | Wire.read());
Serial.println(convertedValue);
//Serial.print("\t"); //Serial.println(totalReadings / 20);
delay(250);
}

