In this article, we are going to learn INA219 interfacing with STM32 microcontroller. For STM32, CubeMX IDE will be used. Using a suitable Shunt resistor we can configure the sensor for the different current ranges. Here in this article, we will learn in detail. So let’s started.

Disclaimer: Electricity is always dangerous. Proper skill is required to work with electricity. Do work at your own risk. The author will not be responsible for any misuse or harmful act or any mistake you make. The contents of this website are unique and copyright protected. Kindly don’t do any nonsensical act copying and claiming it as yours. Most of the articles published here are kept open-source to help you. Take the knowledge for free and use it, but if you are interested you can buy the ready resources offered here. If you need any help or guidance feel free to comment below, the author will try to help you. Also, there can be affiliation links in the article. Which will not affect you anyway, but allows the author with some commission. So please don’t take it otherwise. Thanks.

Table of Contents

Advertisements

INA219:

The INA219 is a current shunt and power monitor with an I2C- or SMBus-compatible interface. The device monitors both shunt voltage drop and bus supply voltage, with programmable conversion times and filtering

INA219 interfacing with STM32

When you need to monitor the voltage, current & power, or Energy of a circuit output or any line or point. then INA219 is a good choice for your embedded system. Using a suitable Shunt resistor we can configure the sensor for the different current ranges. Here in this article, we will learn in detail.

First thing first, INA219 works with the I2C protocol only. So whenever you are planning to interface this IC, you must have this feature in your microcontroller. Most of the microcontrollers nowadays have this feature. And there are lots of examples for Arduino. But there were very few for STM32. So in this project, I’ll explain for STM32 only.

Configuration of INA219:

Before we use it, we have to understand the right configuration of the IC. According to the datasheet, we have to configure the IC like the circuit posted above. Now, there are other parameters, we need to keep in mind.

Shunt voltage: 40mV, 80mV, 160mV & 320mV: This is not what you need to fix, but this is a range of the scale of the measurement. That means you can calculate your shunt resistor for your full A range (say 8A) and the maximum voltage at your rated current should be within the ranges noted here.

Voltage range: 16V or 32V: There are two ranges of the sensing voltage. And you need to select the right one for your purpose. This means the IC will configure the internal registers for either 16V or 32V. So, you have to select the range carefully.

Configuring CubeMx:

You can use different STM ICs but here, I’m using STM32F407VET6 for my purpose. First, initialize the basic settings like RCC and SYS, and then from Connectivity, select the I2C option.

INA219 interfacing with STM32

Then set up the clock and save the project. Now open the main.c from Core>>Scr.

Including INA219 library:

Now, you have to include the .h files in the user include section. Create these two files and save them in the project folder (Core>>Inc (.h) & >>Scr(.c)).

Here in this code, I have multiple INA219 ICs onboard. So, I configured it in a way so that I can read/write to anyone I need to.

ina219.h file:

 

#ifndef _LIB_ADAFRUIT_INA219_
#define _LIB_ADAFRUIT_INA219_




/**************************************************************************/
/*! 
 @brief  default I2C address
 */
/**************************************************************************/
#define INA219_ADDRESS                         (0x40)    // 1000000 (A0+A1=GND)

/**************************************************************************/
/*! 
 @brief  read
 */
/**************************************************************************/
#define INA219_READ                            (0x01)

/*=========================================================================
 CONFIG REGISTER (R/W)
 -----------------------------------------------------------------------*/

/**************************************************************************/
/*! 
 @brief  config register address
 */
/**************************************************************************/
#define INA219_REG_CONFIG                      (0x00)
/*---------------------------------------------------------------------*/

/**************************************************************************/
/*! 
 @brief  reset bit
 */
/**************************************************************************/
#define INA219_CONFIG_RESET                    (0x8000)  // Reset Bit

/**************************************************************************/
/*! 
 @brief  mask for bus voltage range
 */
/**************************************************************************/
#define INA219_CONFIG_BVOLTAGERANGE_MASK       (0x2000)  // Bus Voltage Range Mask

/**************************************************************************/
/*! 
 @brief  bus voltage range values
 */
/**************************************************************************/
enum {
	INA219_CONFIG_BVOLTAGERANGE_16V = (0x0000),  // 0-16V Range
	INA219_CONFIG_BVOLTAGERANGE_32V = (0x2000),  // 0-32V Range
};

/**************************************************************************/
/*! 
 @brief  mask for gain bits
 */
/**************************************************************************/
#define INA219_CONFIG_GAIN_MASK                (0x1800)  // Gain Mask

/**************************************************************************/
/*! 
 @brief  values for gain bits
 */
/**************************************************************************/
enum {
	INA219_CONFIG_GAIN_1_40MV = (0x0000),  // Gain 1, 40mV Range
	INA219_CONFIG_GAIN_2_80MV = (0x0800),  // Gain 2, 80mV Range
	INA219_CONFIG_GAIN_4_160MV = (0x1000),  // Gain 4, 160mV Range
	INA219_CONFIG_GAIN_8_320MV = (0x1800),  // Gain 8, 320mV Range
};

/**************************************************************************/
/*! 
 @brief  mask for bus ADC resolution bits
 */
/**************************************************************************/
#define INA219_CONFIG_BADCRES_MASK             (0x0780)  // Bus ADC Resolution Mask

/**************************************************************************/
/*! 
 @brief  values for bus ADC resolution
 */
/**************************************************************************/
enum {
	INA219_CONFIG_BADCRES_9BIT = (0x0000),  // 9-bit bus res = 0..511
	INA219_CONFIG_BADCRES_10BIT = (0x0080),  // 10-bit bus res = 0..1023
	INA219_CONFIG_BADCRES_11BIT = (0x0100),  // 11-bit bus res = 0..2047
	INA219_CONFIG_BADCRES_12BIT = (0x0180),  // 12-bit bus res = 0..4097
};

/**************************************************************************/
/*! 
 @brief  mask for shunt ADC resolution bits
 */
/**************************************************************************/
#define INA219_CONFIG_SADCRES_MASK             (0x0078)  // Shunt ADC Resolution and Averaging Mask

/**************************************************************************/
/*! 
 @brief  values for shunt ADC resolution
 */
/**************************************************************************/
enum {
	INA219_CONFIG_SADCRES_9BIT_1S_84US = (0x0000),  // 1 x 9-bit shunt sample
	INA219_CONFIG_SADCRES_10BIT_1S_148US = (0x0008),  // 1 x 10-bit shunt sample
	INA219_CONFIG_SADCRES_11BIT_1S_276US = (0x0010),  // 1 x 11-bit shunt sample
	INA219_CONFIG_SADCRES_12BIT_1S_532US = (0x0018),  // 1 x 12-bit shunt sample
	INA219_CONFIG_SADCRES_12BIT_2S_1060US = (0x0048),// 2 x 12-bit shunt samples averaged together
	INA219_CONFIG_SADCRES_12BIT_4S_2130US = (0x0050), // 4 x 12-bit shunt samples averaged together
	INA219_CONFIG_SADCRES_12BIT_8S_4260US = (0x0058), // 8 x 12-bit shunt samples averaged together
	INA219_CONFIG_SADCRES_12BIT_16S_8510US = (0x0060), // 16 x 12-bit shunt samples averaged together
	INA219_CONFIG_SADCRES_12BIT_32S_17MS = (0x0068), // 32 x 12-bit shunt samples averaged together
	INA219_CONFIG_SADCRES_12BIT_64S_34MS = (0x0070), // 64 x 12-bit shunt samples averaged together
	INA219_CONFIG_SADCRES_12BIT_128S_69MS = (0x0078), // 128 x 12-bit shunt samples averaged together
};

/**************************************************************************/
/*! 
 @brief  mask for operating mode bits
 */
/**************************************************************************/
#define INA219_CONFIG_MODE_MASK                (0x0007)  // Operating Mode Mask

/**************************************************************************/
/*! 
 @brief  values for operating mode
 */
/**************************************************************************/
enum {
	INA219_CONFIG_MODE_POWERDOWN = (0x0000),
	INA219_CONFIG_MODE_SVOLT_TRIGGERED = (0x0001),
	INA219_CONFIG_MODE_BVOLT_TRIGGERED = (0x0002),
	INA219_CONFIG_MODE_SANDBVOLT_TRIGGERED = (0x0003),
	INA219_CONFIG_MODE_ADCOFF = (0x0004),
	INA219_CONFIG_MODE_SVOLT_CONTINUOUS = (0x0005),
	INA219_CONFIG_MODE_BVOLT_CONTINUOUS = (0x0006),
	INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS = (0x0007),
};
/*=========================================================================*/

/**************************************************************************/
/*! 
 @brief  shunt voltage register
 */
/**************************************************************************/
#define INA219_REG_SHUNTVOLTAGE                (0x01)
/*=========================================================================*/

/**************************************************************************/
/*! 
 @brief  bus voltage register
 */
/**************************************************************************/
#define INA219_REG_BUSVOLTAGE                  (0x02)
/*=========================================================================*/

/**************************************************************************/
/*! 
 @brief  power register
 */
/**************************************************************************/
#define INA219_REG_POWER                       (0x03)
/*=========================================================================*/

/**************************************************************************/
/*! 
 @brief  current register
 */
/**************************************************************************/
#define INA219_REG_CURRENT                     (0x04)
/*=========================================================================*/

/**************************************************************************/
/*! 
 @brief  calibration register
 */
/**************************************************************************/
#define INA219_REG_CALIBRATION                 (0x05)
/*=========================================================================*/

/**************************************************************************/
/*! 
 @brief  Class that stores state and functions for interacting with INA219 current/power monitor IC
 */
/**************************************************************************/
void setCalibration_32V_2A(void);
void setCalibration_32V_1A(void);
void setCalibration_16V_400mA(void);
float getBusVoltage_V(void);
float getShuntVoltage_mV(void);
float getCurrent_mA(void);
float getPower_mW(void);

void wireWriteRegister(uint8_t reg, uint16_t value);
void wireReadRegister(uint8_t reg, uint16_t *value);
int16_t getBusVoltage_raw(void);
int16_t getShuntVoltage_raw(void);
int16_t getCurrent_raw(void);
int16_t getPower_raw(void);
int contMeasureInit(uint8_t reg);
float convertMeasure(int rawValue);
int contMeasureUpdate(void);
int getNSamples(void);
#endif

ina219.c file:

 

#include <stdint.h>
#include <string.h>
#include "ina219.h"

#include "stm32F4xx_hal.h"


extern I2C_HandleTypeDef hi2c2;



// The following multipliers are used to convert raw current and power
// values to mA and mW, taking into account the current config settings
uint32_t ina219_currentDivider_mA;
uint32_t ina219_powerMultiplier_mW;

uint32_t ina219_calValue;

#define BUFFERLEN 4096
int16_t contBuffer[BUFFERLEN];
unsigned int bufferPos;

/* Holds currently type of continuous measurement (voltage, power, current).
 * Used to avoid floating point numbers prolification */
int measureType;

/**************************************************************************/
/*! 
 @brief  Sends a single command byte over I2C
 */
/**************************************************************************/
uint8_t adrs_219 = 0x41; // you can call this from main function when necessary especially when using multiple INA219 on board
void wireWriteRegister (uint8_t reg, uint16_t value)
{
	uint8_t i2c_temp[2];
	i2c_temp[0] = value>>8;
	i2c_temp[1] = value;
	HAL_I2C_Mem_Write(&hi2c2, adrs_219<<1, (uint16_t)reg, 1, i2c_temp, 2, 0xffffffff);
	HAL_Delay(1);
}

/**************************************************************************/
/*! 
 @brief  Reads a 16 bit values over I2C
 */
/**************************************************************************/
void wireReadRegister(uint8_t reg, uint16_t *value)
{
	uint8_t i2c_temp[2];
	HAL_I2C_Mem_Read(&hi2c2, adrs_219<<1, (uint16_t)reg, 1,i2c_temp, 2, 0xffffffff);
	HAL_Delay(1);
	*value = ((uint16_t)i2c_temp[0]<<8 )|(uint16_t)i2c_temp[1];
}

/**************************************************************************/
/*! 
 @brief  Configures to INA219 to be able to measure up to 32V and 2A
 of current.  Each unit of current corresponds to 100uA, and
 each unit of power corresponds to 2mW. Counter overflow
 occurs at 3.2A.

 @note   These calculations assume a 0.1 ohm resistor is present
 */
/**************************************************************************/
void setCalibration_32V_2A(void) {
	// By default we use a pretty huge range for the input voltage,
	// which probably isn't the most appropriate choice for system
	// that don't use a lot of power.  But all of the calculations
	// are shown below if you want to change the settings.  You will
	// also need to change any relevant register settings, such as
	// setting the VBUS_MAX to 16V instead of 32V, etc.

	// VBUS_MAX = 32V             (Assumes 32V, can also be set to 16V)
	// VSHUNT_MAX = 0.32          (Assumes Gain 8, 320mV, can also be 0.16, 0.08, 0.04)
	// RSHUNT = 0.1               (Resistor value in ohms)

	// 1. Determine max possible current
	// MaxPossible_I = VSHUNT_MAX / RSHUNT
	// MaxPossible_I = 3.2A

	// 2. Determine max expected current
	// MaxExpected_I = 2.0A

	// 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
	// MinimumLSB = MaxExpected_I/32767
	// MinimumLSB = 0.000061              (61uA per bit)
	// MaximumLSB = MaxExpected_I/4096
	// MaximumLSB = 0,000488              (488uA per bit)

	// 4. Choose an LSB between the min and max values
	//    (Preferrably a roundish number close to MinLSB)
	// CurrentLSB = 0.0001 (100uA per bit)

	// 5. Compute the calibration register
	// Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
	// Cal = 4096 (0x1000)

	// ina219_calValue = 4096;
	ina219_calValue = 5120;  // Rsh=0.04R,

	// 6. Calculate the power LSB
	// PowerLSB = 20 * CurrentLSB
	// PowerLSB = 0.002 (2mW per bit)

	// 7. Compute the maximum current and shunt voltage values before overflow
	//
	// Max_Current = Current_LSB * 32767
	// Max_Current = 3.2767A before overflow
	//
	// If Max_Current > Max_Possible_I then
	//    Max_Current_Before_Overflow = MaxPossible_I
	// Else
	//    Max_Current_Before_Overflow = Max_Current
	// End If
	//
	// Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
	// Max_ShuntVoltage = 0.32V
	//
	// If Max_ShuntVoltage >= VSHUNT_MAX
	//    Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
	// Else
	//    Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
	// End If

	// 8. Compute the Maximum Power
	// MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
	// MaximumPower = 3.2 * 32V
	// MaximumPower = 102.4W

	// Set multipliers to convert raw current/power values
	ina219_currentDivider_mA = 6; // Current LSB = 100uA per bit (1000/100 = 10)
	ina219_powerMultiplier_mW = 3;     // Power LSB = 1mW per bit (2/1)

	// 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_32V
			| INA219_CONFIG_GAIN_8_320MV | INA219_CONFIG_BADCRES_12BIT
			| INA219_CONFIG_SADCRES_12BIT_1S_532US
			| INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;
	wireWriteRegister(INA219_REG_CONFIG, config);
}

/**************************************************************************/
/*! 
 @brief  Configures to INA219 to be able to measure up to 32V and 1A
 of current.  Each unit of current corresponds to 40uA, and each
 unit of power corresponds to 800�W. Counter overflow occurs at
 1.3A.

 @note   These calculations assume a 0.1 ohm resistor is present
 */
/**************************************************************************/
void setCalibration_32V_1A(void) {
	// By default we use a pretty huge range for the input voltage,
	// which probably isn't the most appropriate choice for system
	// that don't use a lot of power.  But all of the calculations
	// are shown below if you want to change the settings.  You will
	// also need to change any relevant register settings, such as
	// setting the VBUS_MAX to 16V instead of 32V, etc.

	// VBUS_MAX = 32V		(Assumes 32V, can also be set to 16V)
	// VSHUNT_MAX = 0.32	(Assumes Gain 8, 320mV, can also be 0.16, 0.08, 0.04)
	// RSHUNT = 0.1			(Resistor value in ohms)

	// 1. Determine max possible current
	// MaxPossible_I = VSHUNT_MAX / RSHUNT
	// MaxPossible_I = 3.2A

	// 2. Determine max expected current
	// MaxExpected_I = 1.0A

	// 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
	// MinimumLSB = MaxExpected_I/32767
	// MinimumLSB = 0.0000305             (30.5�A per bit)
	// MaximumLSB = MaxExpected_I/4096
	// MaximumLSB = 0.000244              (244�A per bit)

	// 4. Choose an LSB between the min and max values
	//    (Preferrably a roundish number close to MinLSB)
	// CurrentLSB = 0.0000400 (40�A per bit)

	// 5. Compute the calibration register
	// Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
	// Cal = 10240 (0x2800)

	ina219_calValue = 10240;

	// 6. Calculate the power LSB
	// PowerLSB = 20 * CurrentLSB
	// PowerLSB = 0.0008 (800�W per bit)

	// 7. Compute the maximum current and shunt voltage values before overflow
	//
	// Max_Current = Current_LSB * 32767
	// Max_Current = 1.31068A before overflow
	//
	// If Max_Current > Max_Possible_I then
	//    Max_Current_Before_Overflow = MaxPossible_I
	// Else
	//    Max_Current_Before_Overflow = Max_Current
	// End If
	//
	// ... In this case, we're good though since Max_Current is less than MaxPossible_I
	//
	// Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
	// Max_ShuntVoltage = 0.131068V
	//
	// If Max_ShuntVoltage >= VSHUNT_MAX
	//    Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
	// Else
	//    Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
	// End If

	// 8. Compute the Maximum Power
	// MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
	// MaximumPower = 1.31068 * 32V
	// MaximumPower = 41.94176W

	// Set multipliers to convert raw current/power values
	ina219_currentDivider_mA = 25;  // Current LSB = 40uA per bit (1000/40 = 25)
	ina219_powerMultiplier_mW = 1;         // Power LSB = 800mW 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_32V
			| INA219_CONFIG_GAIN_8_320MV | INA219_CONFIG_BADCRES_12BIT
			| INA219_CONFIG_SADCRES_12BIT_1S_532US
			| INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;
	wireWriteRegister(INA219_REG_CONFIG, config);
}

/**************************************************************************/
/*! 
 @brief set device to alibration which uses the highest precision for
 current measurement (0.1mA), at the expense of
 only supporting 16V at 400mA max.
 */
/**************************************************************************/
void setCalibration_16V_400mA(void) {

	// Calibration which uses the highest precision for
	// current measurement (0.1mA), at the expense of
	// only supporting 16V at 400mA max.

	// VBUS_MAX = 16V
	// VSHUNT_MAX = 0.04          (Assumes Gain 1, 40mV)
	// RSHUNT = 0.1               (Resistor value in ohms)

	// 1. Determine max possible current
	// MaxPossible_I = VSHUNT_MAX / RSHUNT
	// MaxPossible_I = 0.4A

	// 2. Determine max expected current
	// MaxExpected_I = 0.4A

	// 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
	// MinimumLSB = MaxExpected_I/32767
	// MinimumLSB = 0.0000122              (12uA per bit)
	// MaximumLSB = MaxExpected_I/4096
	// MaximumLSB = 0.0000977              (98uA per bit)

	// 4. Choose an LSB between the min and max values
	//    (Preferrably a roundish number close to MinLSB)
	// CurrentLSB = 0.00005 (50uA per bit)

	// 5. Compute the calibration register
	// Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
	// Cal = 8192 (0x2000)

	ina219_calValue = 8192;

	// 6. Calculate the power LSB
	// PowerLSB = 20 * CurrentLSB
	// PowerLSB = 0.001 (1mW per bit)

	// 7. Compute the maximum current and shunt voltage values before overflow
	//
	// Max_Current = Current_LSB * 32767
	// Max_Current = 1.63835A before overflow
	//
	// If Max_Current > Max_Possible_I then
	//    Max_Current_Before_Overflow = MaxPossible_I
	// Else
	//    Max_Current_Before_Overflow = Max_Current
	// End If
	//
	// Max_Current_Before_Overflow = MaxPossible_I
	// Max_Current_Before_Overflow = 0.4
	//
	// Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
	// Max_ShuntVoltage = 0.04V
	//
	// If Max_ShuntVoltage >= VSHUNT_MAX
	//    Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
	// Else
	//    Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
	// End If
	//
	// Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
	// Max_ShuntVoltage_Before_Overflow = 0.04V

	// 8. Compute the Maximum Power
	// MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
	// MaximumPower = 0.4 * 16V
	// MaximumPower = 6.4W

	// Set multipliers to convert raw current/power values
	ina219_currentDivider_mA = 20;  // Current LSB = 50uA per bit (1000/50 = 20)
	ina219_powerMultiplier_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);
}

/**************************************************************************/
/*! 
 @brief  Gets the raw bus voltage (16-bit signed integer, so +-32767)
 @return the raw bus voltage reading
 */
/**************************************************************************/
int16_t getBusVoltage_raw() {
	uint16_t value;
	wireReadRegister(INA219_REG_BUSVOLTAGE, &value);

	// Shift to the right 3 to drop CNVR and OVF and multiply by LSB
	return (int16_t) ((value >> 3) * 4);
}

/**************************************************************************/
/*! 
 @brief  Gets the raw shunt voltage (16-bit signed integer, so +-32767)
 @return the raw shunt voltage reading
 */
/**************************************************************************/
int16_t getShuntVoltage_raw() {
	uint16_t value;
	wireReadRegister(INA219_REG_SHUNTVOLTAGE, &value);
	return (int16_t) value;
}

/**************************************************************************/
/*! 
 @brief  Gets the raw current value (16-bit signed integer, so +-32767)
 @return the raw current reading
 */
/**************************************************************************/
int16_t getCurrent_raw() {
	uint16_t value;

	// Sometimes a sharp load will reset the INA219, which will
	// reset the cal register, meaning CURRENT and POWER will
	// not be available ... avoid this by always setting a cal
	// value even if it's an unfortunate extra step
	wireWriteRegister(INA219_REG_CALIBRATION, ina219_calValue);

	// Now we can safely read the CURRENT register!
	wireReadRegister(INA219_REG_CURRENT, &value);

	return (int16_t) value;
}

/**************************************************************************/
/*! 
 @brief  Gets the raw power value (16-bit signed integer, so +-32767)
 @return raw power reading
 */
/**************************************************************************/
int16_t getPower_raw() {
	uint16_t value;

	// Sometimes a sharp load will reset the INA219, which will
	// reset the cal register, meaning CURRENT and POWER will
	// not be available ... avoid this by always setting a cal
	// value even if it's an unfortunate extra step
	wireWriteRegister(INA219_REG_CALIBRATION, ina219_calValue);

	// Now we can safely read the POWER register!
	wireReadRegister(INA219_REG_POWER, &value);

	return (int16_t) value;
}

/**************************************************************************/
/*! 
 @brief  Gets the shunt voltage in mV (so +-327mV)
 @return the shunt voltage converted to millivolts
 */
/**************************************************************************/
float getShuntVoltage_mV() {
	int16_t value;
	value = getShuntVoltage_raw();
	return value * 0.01;
}

/**************************************************************************/
/*! 
 @brief  Gets the shunt voltage in volts
 @return the bus voltage converted to volts
 */
/**************************************************************************/
float getBusVoltage_V() {
	int16_t value = getBusVoltage_raw();
	return value * 0.001;
}

/**************************************************************************/
/*! 
 @brief  Gets the current value in mA, taking into account the
 config settings and current LSB
 @return the current reading convereted to milliamps
 */
/**************************************************************************/
float getCurrent_mA() {
	float valueDec = getCurrent_raw();
	valueDec /= ina219_currentDivider_mA;
	return valueDec;
}

/**************************************************************************/
/*! 
 @brief  Gets the power value in mW, taking into account the
 config settings and current LSB
 @return power reading converted to milliwatts
 */
/**************************************************************************/
float getPower_mW() {
	float valueDec = getPower_raw();
	valueDec *= ina219_powerMultiplier_mW;
	return valueDec;
}

/* Initialize continuous measurement.
 * Sets register pointer to desired measurement type (current, bus voltage, shunt voltage, power).
 * @param reg Device register
 */
int contMeasureInit(uint8_t reg) {
	HAL_StatusTypeDef status;
	measureType = reg;

	/* Set register pointer to desired register */
	status = HAL_I2C_Master_Transmit(&hi2c2, adrs_219 << 1, &reg, 1,
			0xffffffff);
	if (status != HAL_OK)
		while (1)
			;

	bufferPos = 0;
	memset(contBuffer, 0, sizeof(contBuffer));

	return 0;
}

/* Updates measurement buffers. To be called periodically by application.
 * @retval Current buffer position
 */
int contMeasureUpdate(void) {
	HAL_StatusTypeDef status;
	uint8_t measure[2];

	status = HAL_I2C_Master_Receive(&hi2c2, adrs_219 << 1,
			(uint8_t*) &measure, 2, 0xffffffff);
	if (status != HAL_OK)
		while (1)
			;

	/* Change endinanness */
	if (bufferPos < BUFFERLEN)
		contBuffer[bufferPos++] = ina219_powerMultiplier_mW
				* (((uint16_t) measure[0] << 8) | (uint16_t) measure[1]);

	return bufferPos;
}

/** Converts a given integer raw measure in actual floating point one
 * @param rawValue Raw value as obtained from continuous measurement buffer
 * @retval Actual floating point value of given raw measurement
 */
float convertMeasure(int rawValue) {
	float val = rawValue;

	switch (measureType) {
	case INA219_REG_SHUNTVOLTAGE:
		val *= 0.01f;
		break;

	case INA219_REG_BUSVOLTAGE:
		val *= 0.001f;
		break;

	case INA219_REG_POWER:
		val *= ina219_powerMultiplier_mW;
		break;

	case INA219_REG_CURRENT:
		val /= ina219_currentDivider_mA;
		break;

	default:
		val = -1;
	}

	return val;
}

/** Returns the number of samples that have been acquired during continous measurement
 * @retval Numner of samples acquired
 */
int getNSamples(void) {
	return bufferPos;
}

Now in the main section, put this (with your other codes if needed).

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ina219.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c2;
DMA_HandleTypeDef hdma_i2c2_rx;

/* USER CODE BEGIN PV */
extern int adrs_219;

/* USER CODE END PV */

/* USER CODE BEGIN 0 */
uint32_t ina_curr = 0;
uint32_t ina_vol = 0;
uint32_t ina_pwr = 0;
uint8_t cnt = 0;
uint8_t channel=0;
/* USER CODE END 0 */

Now, in the main(void) section pass these to configure the configuration of your INA for the first time.

  /* USER CODE BEGIN 2 */
	adrs_219 = 0x40;
	setCalibration_32V_2A();
	adrs_219 = 0x41;
	setCalibration_32V_2A();
	adrs_219 = 0x44;
	setCalibration_32V_2A();
  /* USER CODE END 2 */

Here in my hardware, there were 3 INA219 ICs so I configured them one by one. If you have only one, you can configure only one. But the address is important here. I think you know that the INA219 address is 7-bit size.

Now in the while(1) loop, you can read from any one of your IC.

                        adrs_219 = 0x40;
			ina_curr = getCurrent_mA();
			ina_vol = getBusVoltage_V();
			ina_pwr = getPower_mW();

or

                        adrs_219 = 0x41;
			ina_curr = getCurrent_mA();
			ina_vol = getBusVoltage_V();
			ina_pwr = getPower_mW();

And it’s all done. Now, let’s debug the code if it is error-free. My one was error free. so do yours should be.

Debugging:

I had a big hardware here with this sensor IC, which I debugged with connecting loads and supplies. For this, I use STLink programmer v2. You can use one you have or collecting one.

Conclusion:

I hope now you can use this code/library for your own project with STM32. The explanation is given in the comments section of each line where necessary. Hope this will help you. Thanks.

You can also read my other articles here:

For Professional Designs or Help:

Loading

Also let me know what you want to get as the next article, comment below!


MKDas

Mithun K. Das; B. Sc. in EEE from KUET; Head of R&D @ M's Lab Engineering Solution. "This is my personal blog. I post articles on different subjects related to electronics in the easiest way so that everything becomes easy for all, especially for beginners. If you have any questions, feel free to ask through the contact us page." Thanks.

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published.

%d bloggers like this: