This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

INA219: Can I measure less than 1mA precisely with INA219? If so, how?

Part Number: INA219

I am using an INA219 current/power monitor to measure the output of a small PV panel under low-light conditions over a period of several days. The short-circuit current (from a multimeter) is never above a mA for the size of panel I am looking to test. The INA I am using is on an Adafruit breakout board, and I am controlling it using an I2C interface to a Particle Electron. I have been using the Adafruit code library available on the Particle IDE for my purposes, which works well for larger panels with a bigger output, but there is no function that will allow me to change the settings to make the desired measurements.

My primary question is: Is it possible to make the measurements  required with reasonable precision (down to a uA if possible, but 5uA is acceptable) using the INA219?

If it is, I could do with some help with the implementation,

What I have done so far:

The library I have been using includes functions to change the input range of the INA, the options included are 32V/2A (default), 32V/1A, and 16V/400mA. I have tried adapting one of these functions to work for 100mV/1mA, the code for which I have included below. When testing it, I initially got better numbers (bigger, so implying that I had succeeded in changing the gain), but these no longer made any sense in context - as the output should be in mA, but the output readings were now much too big. I thought this was to do with the "ina219_currentdivider_mA" value which was then at 20, but changing it to a larger number returns to the original problem of the readings not registering such a small current (for some reason the output the library code gives is limited to two decimal places, I'm not sure why, if anyone could explain that as well I would be grateful). 

For background, I have a basic grasp of C++ language and a theoretical understanding of things like I2C and bit-wise communication, but am not very well equipped for low-level programming of these things, can anyone point me to a good resource about them that would help me be a little less dependent on libraries?

void Adafruit_INA219::setCalibration_100mV_1mA(void) 
{ //declare variables float VBUS_MAX; float VSHUNT_MAX; float RSHUNT; float MaxPossible_I; float MaxExpected_I; float MinimumLSB; float MaximumLSB; float CurrentLSB; uint32_t Cal; float PowerLSB; float Max_Current; float Max_Current_Before_Overflow; float Max_ShuntVoltage; float Max_ShuntVoltage_Before_Overflow; float MaximumPower; VBUS_MAX = 0.05; //in V VSHUNT_MAX = 0.1; //(Assumes Gain 1, 40mV) RSHUNT = 18; //(Resistor value in ohms) // 1. Determine max possible current MaxPossible_I = VSHUNT_MAX / RSHUNT; //0.005A = 5mA // 2. Determine max expected current MaxExpected_I = 0.001; //1mA // 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit) MinimumLSB = MaxExpected_I/32767; //3.05 x 10^-8 = 0.03uA MaximumLSB = MaxExpected_I/4096; //2.44 x 10^-7 = 0.24uA // 4. Choose an LSB between the min and max values // (Preferrably a roundish number close to MinLSB) CurrentLSB = 0.00000004; //(0.04uA per bit) // 5. Compute the calibration register Cal = (String(0.04096 / (CurrentLSB * RSHUNT))).toFloat(); //This is a hotch-potched version of "trunc()" because the IDE was not compiling "trunc()" ina219_calValue = Cal; // 6. Calculate the power LSB PowerLSB = 20 * CurrentLSB; // 7. Compute the maximum current and shunt voltage values before overflow Max_Current = CurrentLSB * 32767; if(Max_Current > MaxPossible_I){ Max_Current_Before_Overflow = MaxPossible_I; } else { Max_Current_Before_Overflow = Max_Current; } Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT; if(Max_ShuntVoltage >= VSHUNT_MAX) { Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX; } else{ Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage; } Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX; // 8. Compute the Maximum Power MaximumPower = Max_Current_Before_Overflow * VBUS_MAX; // Set multipliers to convert raw current/power values ina219_currentDivider_mA = 33333; // Current LSB = 0.03uA per bit (1000/0.03 = ) ina219_powerDivider_mW = 1; // Power LSB = 1mW per bit // Set Calibration register to 'Cal' calculated above wireWriteRegister(INA219_REG_CALIBRATION, ina219_calValue); // Set Config register to take into account the settings above uint16_t config = INA219_CONFIG_BVOLTAGERANGE_16V | INA219_CONFIG_GAIN_1_40MV | INA219_CONFIG_BADCRES_12BIT | INA219_CONFIG_SADCRES_12BIT_1S_532US | INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; wireWriteRegister(INA219_REG_CONFIG, config); }

float Adafruit_INA219::getCurrent_mA() {
float valueDec = getCurrent_raw();
valueDec /= ina219_currentDivider_mA;
return valueDec;
}


  • Hi,

    Each input for the current sense amplifier has a bias current of 20uA, so that generates an error which is significantly larger than the current measurement required. This is generally an issue with most current sense amplifiers. In order to measure currents this low you require an opamp, set with a given gain to match you current range with the ADC range of the arduino.

    Measuring down to 1mA should be possible. I noticed in your code, however, you mention a 18Ohm shunt resistor. Is this correct?

  • Hi, thank you for your response. Yes I am currently using an 18 ohm shunt resistor, the thought being that with a larger resistor there would be a larger and more measureable voltage drop across it at these low currents, although I can see that this might be a tradeoff with reducing the current further.
    I assume by using an op-amp, you are suggesting a transimpedance amplifier setup. Can you suggest a way in which that sort of setup would also allow voltage measurement in the same way as the INA does, or would I have to have another system or sensor for that?

  • Your assumption is correct, however due to the bias inputs on the amplifier itself, there will be a voltage generated across that 18Ohm resistor. This is where it becomes a problem, because bias currents are so much bigger than the current to be measured, the readings become inaccurate, there is a voltage developed across the shunt resistor even before any current from your circuit starts flowing.

    As to the opamp, I was simply suggesting a non inverting amplifier of suitable gain.

    Guessing by the code above, the voltage developed across the 18Ohm resistor at a 5mA current will be 90mV, then a gain of 50 seems adequate to interface with the arduino ADC, which is referenced at 5V.

    I will make an educated choice by suggesting the OPA335, which is a low offset, rail to rail device with low input bias current. There might be other devices but you will have to open a new thread on the precision amplifiers section of the forum for further advice as I can only cover current sense amplifiers.