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: Calibrating INA219 for different shunt resistor

Part Number: INA219

Hi,

I am trying to monitor voltage and current of 5 different devices using 5 different INA219 sensors, but the currents are off a bit and the currents fluctuate when they shouldn't.

shunt resistor value: 0.01 ohm

calibration value: 409

max expected current total throughout the board: 12 A

max expected on each device 5 A

Computing System: Raspberry Pi

Attached is the code:

myPowerMonitor.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <endian.h>
#include <string.h>
#include <time.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>


#define CONFIG_REG          0
#define SHUNT_REG           1
#define BUS_REG             2
#define POWER_REG           3
#define CURRENT_REG         4
#define CALIBRATION_REG     5


#define INA_ADDRESS_1         0x40
#define INA_ADDRESS_2         0x41
#define INA_ADDRESS_3         0x42 //change this depending what address you have
#define INA_ADDRESS_4         0x43
#define INA_ADDRESS_5         0x44


int interval = 60;
int i2c_bus = 1;

int i2c_address_1 = INA_ADDRESS_1;
int i2c_address_2 = INA_ADDRESS_2;
int i2c_address_3 = INA_ADDRESS_3;
int i2c_address_4 = INA_ADDRESS_4;
int i2c_address_5 = INA_ADDRESS_5;

int handle;

int i2c_read( void *buf, int len )
{
    int rc = 0;

    if ( read( handle, buf, len ) != len )
    {
        printf( "I2C read failed: %s\n", strerror( errno ) );
        rc = -1;
    }

    return 0;
}


int i2c_write( void *buf, int len )
{
    int rc = 0;

    if ( write( handle, buf, len ) != len )
    {
        printf( "I2C write failed: %s\n", strerror( errno ) );
        rc = -1;
    }

    return rc;
}

int register_read( unsigned char reg, unsigned short *data )
{
    int rc = -1;
    unsigned char bite[ 4 ];

    bite[ 0 ] = reg;
    if ( i2c_write( bite, 1 ) == 0 )
    {
        if ( i2c_read( bite, 2 ) == 0 )
        {
            *data = ( bite[ 0 ] << 8 ) | bite[ 1 ];
            rc = 0;
        }
    }

    return rc;
}

int register_write( unsigned char reg, unsigned short data )
{
    int rc = -1;
    unsigned char bite[ 4 ];

    bite[ 0 ] = reg;
    bite[ 1 ] = ( data >> 8 ) & 0xFF;
    bite[ 2 ] = ( data & 0xFF );


    if ( i2c_write( bite, 3 ) == 0 )
    {
        rc = 0;
    }

    return rc;
}



int get_voltage( float *mv )
{
    short bus;

    if ( register_read( BUS_REG, (unsigned short*)&bus ) != 0 )
    {
        return -1;
    }

    *mv = ( float )( ( bus & 0xFFF8 ) >> 1 );
    return 0;
}


int get_current( float *ma )
{
    short shunt;

    if ( register_read( SHUNT_REG, &shunt ) != 0 )
    {
        return -1;
    }

    *ma = (float)shunt;
    return 0;
}


void show_current( void )
{
    float ma;

    if ( get_current( &ma ) )
    {
        fprintf( stderr, "Error reading current\n" );
        return;
    }

}




void show_voltage( void )
{
    float mv;

    if ( get_voltage( &mv ) )
    {
        fprintf( stderr, "Error reading voltage\n" );
        return;
    }
    printf( "%4.0f\n", mv );
}


void show_voltage_current( void )
{
    float mv, ma;

    if ( get_current( &ma ) || get_voltage( &mv ) )
    {
        fprintf( stderr, "Error reading voltage/current\n" );
        return;
    }


    else
    {
        printf( "Load Voltage: %g  Current: %4.1fmA\n", (mv/1000), (ma-7) );

    }
}


int main( int argc, char *argv[] )
{
    char filename[ 20 ];
    register_write(CALIBRATION_REG, 409);


    snprintf( filename, 19, "/dev/i2c-%d", i2c_bus );
    handle = open( filename, O_RDWR );
    if ( handle < 0 )
    {
        fprintf( stderr, "Error opening bus %d: %s\n", i2c_bus, strerror( errno ) );
        exit( 1 );
    }

    while(1)
    {



    if ( ioctl( handle,  I2C_SLAVE, i2c_address_1 ) < 0 )

    {
        fprintf( stderr, "Error setting address %02X: %s\n", i2c_address_1, strerror( errno ) );
        exit( 1 );
    }

    {

        printf("+5:    ");
        show_voltage_current();
        sleep(1);
    }


    if ( ioctl( handle,  I2C_SLAVE, i2c_address_2 ) < 0 )
    {
        fprintf( stderr, "Error setting address %02X: %s\n", i2c_address_2, strerror( errno ) );
        exit( 1 );
    }

    {   printf("+5:    ");


        show_voltage_current();
        sleep(1);
    }

        if ( ioctl( handle,  I2C_SLAVE, i2c_address_3 ) < 0 )
    {
        fprintf( stderr, "Error setting address %02X: %s\n", i2c_address_3, strerror( errno ) );
        exit( 1 );
    }

    {   printf("-5:    ");


        show_voltage_current();
        sleep(1);
    }


    if ( ioctl( handle,  I2C_SLAVE, i2c_address_4 ) < 0 )
    {
        fprintf( stderr, "Error setting address %02X: %s\n", i2c_address_4, strerror( errno ) );
        exit( 1 );
    }

    {   printf("+12:   ");


        show_voltage_current();
        sleep(1);
    }

    if ( ioctl( handle,  I2C_SLAVE, i2c_address_5 ) < 0 )
    {
        fprintf( stderr, "Error setting address %02X: %s\n", i2c_address_5, strerror( errno ) );
        exit( 1 );
    }

    {

        printf("+5     ");

        show_voltage_current();
        sleep(1);
        printf("\n");
    }

    }



    return 0;
}

  • Hi Shideh,

    Can you share a schematic/layout of your system? Bad current readings can be related to layout issues. 

    For the digital section:

    We have a training video that discusses how to program the digital output current shunt monitors for direct current and power readouts. Refer to Video 15.

    Also, you can take a look at the following C code for application reference. 

  • Hi, thanks for your reply. The video didn't help much. It was just the same information on the datasheet. As for the driver, I'm using i2c accessing the voltage and current in the code, it's just not accurate and it doesn't take my calibration into account, so I was wondering if my calibration is wrong.
  • Hi shideh,

    Your Max Expected current should be 5A, as you will be programming each device individually. With a Rshunt of 0.01ohms, Max Expected Current of 5A and a Current LSB of 1mA/bit my calibration register is 1000(Hex). Using my EVM GUI.  Which Current LSB value you used to obtain the  Calibration Register value?

  • Hi, so no matter what value I put for my calibration register, it doesn't change anything.
    I have this in my main:
    register_write(CALIBRATION_REG, 0x1000);
    maybe the way I'm writing my code is wrong
  • Hi Shideh,

    I thought the problem was with the device settings. Unfortunately, I do not have expertise on coding but please review the I2C sample code I sent you on my first reply. Lots of our customers use it for their application and it works to communicate with our device.