Merge pull request #11350 from maribu/ina2xx

drivers/ina220: Changed to comply with RIOT's driver design goals & SAUL adaption
This commit is contained in:
Marian Buschsieweke 2019-11-22 23:36:50 +01:00 committed by GitHub
commit 16ee7aed32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 971 additions and 525 deletions

View File

@ -219,7 +219,11 @@ ifneq (,$(filter hts221,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif
ifneq (,$(filter ina220,$(USEMODULE)))
ifneq (,$(filter ina2%,$(USEMODULE)))
USEMODULE += ina2xx
endif
ifneq (,$(filter ina2xx,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif

View File

@ -114,8 +114,8 @@ ifneq (,$(filter hts221,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hts221/include
endif
ifneq (,$(filter ina220,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ina220/include
ifneq (,$(filter ina2xx,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ina2xx/include
endif
ifneq (,$(filter ina3221,$(USEMODULE)))

View File

@ -1,109 +0,0 @@
/*
* Copyright (C) 2015 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ina220
* @{
*
* @file
* @brief Device driver implementation for Texas Instruments INA220 High
* or Low Side, Bi-Directional CURRENT/POWER MONITOR with Two-Wire
* Interface
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*
* @}
*/
#include <stdint.h>
#include "ina220.h"
#include "ina220-regs.h"
#include "periph/i2c.h"
#include "byteorder.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/** @brief Read one 16 bit register from a INA220 device and swap byte order, if necessary. */
static int ina220_read_reg(const ina220_t *dev, uint8_t reg, uint16_t *out)
{
union {
uint8_t c[2];
uint16_t u16;
} tmp = { .u16 = 0 };
int status = 0;
status = i2c_read_regs(dev->i2c, dev->addr, reg, &tmp.c[0], 2, 0);
if (status < 0) {
return status;
}
*out = ntohs(tmp.u16);
return 0;
}
/** @brief Write one 16 bit register to a INA220 device and swap byte order, if necessary. */
static int ina220_write_reg(const ina220_t *dev, uint8_t reg, uint16_t in)
{
union {
uint8_t c[2];
uint16_t u16;
} tmp = { .u16 = 0 };
int status = 0;
tmp.u16 = htons(in);
status = i2c_write_regs(dev->i2c, dev->addr, reg, &tmp.c[0], 2, 0);
if (status < 0) {
return status;
}
return 0;
}
int ina220_init(ina220_t *dev, i2c_t i2c, uint8_t address)
{
/* write device descriptor */
dev->i2c = i2c;
dev->addr = address;
return 0;
}
int ina220_set_calibration(const ina220_t *dev, uint16_t calibration)
{
return ina220_write_reg(dev, INA220_REG_CALIBRATION, calibration);
}
int ina220_set_config(const ina220_t *dev, uint16_t config)
{
return ina220_write_reg(dev, INA220_REG_CONFIGURATION, config);
}
int ina220_read_shunt(const ina220_t *dev, int16_t *voltage)
{
return ina220_read_reg(dev, INA220_REG_SHUNT_VOLTAGE, (uint16_t *)voltage);
}
int ina220_read_bus(const ina220_t *dev, int16_t *voltage)
{
return ina220_read_reg(dev, INA220_REG_BUS_VOLTAGE, (uint16_t *)voltage);
}
int ina220_read_current(const ina220_t *dev, int16_t *current)
{
return ina220_read_reg(dev, INA220_REG_CURRENT, (uint16_t *)current);
}
int ina220_read_power(const ina220_t *dev, int16_t *power)
{
return ina220_read_reg(dev, INA220_REG_POWER, (uint16_t *)power);
}

View File

@ -1,50 +0,0 @@
/*
* Copyright (C) 2015 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ina220
* @{
*
* @file
* @brief Register definitions for Texas Instruments INA220 High or Low
* Side, Bi-Directional CURRENT/POWER MONITOR with Two-Wire
* Interface
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef INA220_REGS_H
#define INA220_REGS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief INA220 register addresses
*
* All registers in the INA220 are 16 bit wide and transmitted MSB first.
*/
typedef enum ina220_reg {
INA220_REG_CONFIGURATION = 0x00, /**< Configuration register (read/write) */
INA220_REG_SHUNT_VOLTAGE = 0x01, /**< Shunt voltage register (read only) */
INA220_REG_BUS_VOLTAGE = 0x02, /**< Bus voltage register (read only) */
INA220_REG_POWER = 0x03, /**< Power register (read only) */
INA220_REG_CURRENT = 0x04, /**< Current register (read only) */
INA220_REG_CALIBRATION = 0x05, /**< Calibration register (read/write) */
} ina220_reg_t;
#ifdef __cplusplus
}
#endif
#endif /* INA220_REGS_H */
/** @} */

View File

@ -1,3 +1,3 @@
MODULE = ina220
MODULE = ina2xx
include $(RIOTBASE)/Makefile.base

206
drivers/ina2xx/ina2xx.c Normal file
View File

@ -0,0 +1,206 @@
/*
* Copyright (C) 2015 Eistec AB
* 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ina2xx
* @{
*
* @file
* @brief Device driver implementation for Texas Instruments INA2XX High
* or Low Side, Bi-Directional CURRENT/POWER MONITOR with Two-Wire
* Interface
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <errno.h>
#include <stdint.h>
#include "ina2xx.h"
#include "ina2xx_defines.h"
#include "periph/i2c.h"
#include "byteorder.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/*
* The value in the current register is obtained by:
*
* I = (V_shunt * C) / 4096
*
* Where V_shunt is the value in the shunt voltage register and C is the
* value programmed (upon driver initialization) into the calibration register
*/
#define CURRENT_QUOTIENT (4096LU)
/** @brief Read one 16 bit register from a INA2XX device and swap byte order, if necessary. */
static int ina2xx_read_reg(const ina2xx_t *dev, uint8_t reg, uint16_t *out)
{
union {
uint8_t c[2];
uint16_t u16;
} tmp;
int status = 0;
status = i2c_read_regs(dev->params.i2c, dev->params.addr, reg, &tmp.c[0],
2, 0);
if (status < 0) {
return status;
}
*out = ntohs(tmp.u16);
return 0;
}
/** @brief Write one 16 bit register to a INA2XX device and swap byte order, if necessary. */
static int ina2xx_write_reg(const ina2xx_t *dev, uint8_t reg, uint16_t in)
{
union {
uint8_t c[2];
uint16_t u16;
} tmp;
int status = 0;
tmp.u16 = htons(in);
status = i2c_write_regs(dev->params.i2c, dev->params.addr, reg, &tmp.c[0],
2, 0);
if (status < 0) {
return status;
}
return 0;
}
int ina2xx_init(ina2xx_t *dev, const ina2xx_params_t *params)
{
uint16_t config;
int status;
if (!dev || !params) {
return -EINVAL;
}
dev->params = *params;
/* Reset device */
status = ina2xx_write_reg(dev, INA2XX_REG_CONFIGURATION, INA2XX_RESET);
if (status < 0) {
return status;
}
/* Check if default config is preset after reset */
status = ina2xx_read_reg(dev, INA2XX_REG_CONFIGURATION, &config);
if (status < 0) {
return status;
}
if (config != INA2XX_DEFCONFIG) {
DEBUG("[ina2xx]: Reset did't restore default config. Wrong device?\n");
return -ENODEV;
}
status = ina2xx_write_reg(dev, INA2XX_REG_CONFIGURATION, params->config);
if (status < 0) {
return status;
}
/* Set calibration register based on the shunt resistor.
* ==> Current will be in mA
* Multiply by 100
* ==> Current will be in mA
*/
uint32_t calib = (100 * CURRENT_QUOTIENT) / params->rshunt_mohm;
/* Divide by 2^i_range to reduce the resolution by factor 2^i_range */
calib >>= params->i_range;
if (calib > UINT16_MAX) {
return -ERANGE;
}
return ina2xx_write_reg(dev, INA2XX_REG_CALIBRATION, (uint16_t)calib);
}
int ina2xx_read_shunt(const ina2xx_t *dev, int16_t *voltage)
{
return ina2xx_read_reg(dev, INA2XX_REG_SHUNT_VOLTAGE, (uint16_t *)voltage);
}
int ina2xx_read_bus(const ina2xx_t *dev, uint16_t *voltage)
{
uint16_t tmp;
int status = ina2xx_read_reg(dev, INA2XX_REG_BUS_VOLTAGE, &tmp);
if (status < 0) {
return status;
}
/* The voltage given by bits 15-3 in steps of 4 mV
* ==> Take bits 15-3, shift 3 bits right, multiply by 4
* ==> Same as: Take bits 15-3, shift 3 bits right, shift 2 bits left
* ==> Same as: Take bits 15-3, shift 1 bit right
*/
*voltage = (tmp & ~0x7) >> 1;
if (tmp & INA2XX_VBUS_OVF) {
return -EDOM;
}
return (tmp & INA2XX_VBUS_CNVR) ? 1 : 0;
}
int ina2xx_read_current(const ina2xx_t *dev, int32_t *current)
{
int16_t tmp;
int status = ina2xx_read_reg(dev, INA2XX_REG_CURRENT, (uint16_t *)&tmp);
if (status < 0) {
return status;
}
/*
* The calibration is chosen according to the selected value in
* dev->params.i_range, so that tmp * 2^i_range gives us the
* current in E-05 A. We can thus simple use a left shift to convert
* the current into E-05 A.
*/
*current = ((int32_t)tmp) << dev->params.i_range;
return 0;
}
int ina2xx_read_power(const ina2xx_t *dev, uint32_t *power)
{
int status;
uint16_t tmp;
status = ina2xx_read_reg(dev, INA2XX_REG_POWER, &tmp);
if (status < 0) {
return status;
}
/*
* The resolution of the raw power value depends only on the resolution
* of the raw current value, as the bus voltage has a resolution of 4 mV
* regardless of configuration and calibration values. The product of
* bus voltage and raw current value is divided by 5000, this results in
* the following resolutions:
*
* Res current | res power
* 0.01 mA | 0.2 mW
* 0.02 mA | 0.4 mW
* 0.04 mA | 0.8 mW
* ...
*
* ==> multiply by 2^(1 + i_range) to get power in E-04W
*/
*power = ((uint32_t)tmp) << (1 + dev->params.i_range);
return 0;
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ina2xx
* @{
*
* @file
* @brief SAUL adaption of the INA2XX driver
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "phydat.h"
#include "saul.h"
#include "ina2xx.h"
static int read_current(const void *_dev, phydat_t *res)
{
ina2xx_t *dev = (ina2xx_t *)_dev;
int32_t current;
if (ina2xx_read_current(dev, &current) == 0) {
res->scale = -5;
res->unit = UNIT_A;
phydat_fit(res, &current, 1);
return 1;
}
return -ECANCELED;
}
static int read_power(const void *_dev, phydat_t *res)
{
ina2xx_t *dev = (ina2xx_t *)_dev;
uint32_t power;
if (ina2xx_read_power(dev, &power) == 0) {
res->unit = UNIT_W;
res->scale = -4;
phydat_fit(res, (int32_t *)&power, 1);
return 1;
}
return -ECANCELED;
}
static int read_voltage(const void *_dev, phydat_t *res)
{
ina2xx_t *dev = (ina2xx_t *)_dev;
if (ina2xx_read_bus(dev, (uint16_t *)&res->val[0]) >= 0) {
res->unit = UNIT_V;
res->scale = -3;
return 1;
}
return -ECANCELED;
}
const saul_driver_t ina2xx_saul_current_driver = {
.read = read_current,
.write = saul_notsup,
.type = SAUL_SENSE_CURRENT
};
const saul_driver_t ina2xx_saul_power_driver = {
.read = read_power,
.write = saul_notsup,
.type = SAUL_SENSE_POWER
};
const saul_driver_t ina2xx_saul_voltage_driver = {
.read = read_voltage,
.write = saul_notsup,
.type = SAUL_SENSE_VOLTAGE
};

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2015 Eistec AB
* 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ina2xx
* @{
*
* @file
* @brief Various definitions for Texas Instruments INA219/INA220
* Bi-Directional CURRENT/POWER MONITOR with Two-Wire Interface
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef INA2XX_DEFINES_H
#define INA2XX_DEFINES_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief INA2XX register addresses
*
* All registers in the INA2XX are 16 bit wide and transmitted MSB first.
*/
typedef enum ina2xx_reg {
INA2XX_REG_CONFIGURATION = 0x00, /**< Configuration register (read/write) */
INA2XX_REG_SHUNT_VOLTAGE = 0x01, /**< Shunt voltage register (read only) */
INA2XX_REG_BUS_VOLTAGE = 0x02, /**< Bus voltage register (read only) */
INA2XX_REG_POWER = 0x03, /**< Power register (read only) */
INA2XX_REG_CURRENT = 0x04, /**< Current register (read only) */
INA2XX_REG_CALIBRATION = 0x05, /**< Calibration register (read/write) */
} ina2xx_reg_t;
/**
* @name Flags in the INA2XX Bus Voltage Register
* @{
*/
#define INA2XX_VBUS_CNVR (0x2) /**< Unread value in power register ready */
#define INA2XX_VBUS_OVF (0x1) /**< Math overflow during conversion */
/** @} */
/**
* @name Special configuration register values
* @{
*/
#define INA2XX_RESET (0x8000)/**< Write to config reg to reset device */
#define INA2XX_DEFCONFIG (0x399f)/**< Default config after reset */
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* INA2XX_DEFINES_H */
/** @} */

View File

@ -0,0 +1,128 @@
/*
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ina2xx
*
* @{
* @file
* @brief Default configuration for INA2xx power/current monitors
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef INA2XX_PARAMS_H
#define INA2XX_PARAMS_H
#include "board.h"
#include "ina2xx.h"
#include "saul_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Set default configuration parameters for the INA2XX
* @{
*/
#ifndef INA2XX_PARAM_I2C
/**
* @brief Default to first I2C device
*/
#define INA2XX_PARAM_I2C (I2C_DEV(0))
#endif
#ifndef INA2XX_PARAM_ADDR
/**
* @brief Default to address 0x40, which is active if A0 and A1 are connected
* to GND
*
* On the popular INA219 breakout board this is the default address if solder
* jumpers remain open.
*/
#define INA2XX_PARAM_ADDR (0x40)
#endif
#ifndef INA2XX_PARAM_CONFIG
/**
* @brief Default to an optimal configuration for current/power measurements
* of USB high-power devices using the popular INA219 break out board
* with 128 samples averaged
*
* | Setting | Value |
* |:------------------- |:--------------------------------------------- |
* | Mode | Continuous shunt and bus voltage measurements |
* | Shunt ADC Setting | 128 Samples, 68.10 ms per conversion |
* | Bus ADC Setting | 128 Samples, 68.10 ms per conversion |
* | Shunt Voltage Range | ±80mV |
* | Bus Voltage Range | 16V |
*/
#define INA2XX_PARAM_CONFIG (INA2XX_MODE_CONTINUOUS_SHUNT_BUS | \
INA2XX_SADC_AVG_128_SAMPLES | \
INA2XX_BADC_AVG_128_SAMPLES | \
INA2XX_SHUNT_RANGE_80MV | \
INA2XX_BUS_RANGE_16V)
#endif
#ifndef INA2XX_PARAM_RSHUNT_MOHM
/**
* @brief Default to 100 mΩ as shunt resistor
*
* This is the value used in the popular INA219 breakout board.
*/
#define INA2XX_PARAM_RSHUNT_MOHM (100)
#endif
#ifndef INA2XX_PARAM_I_RANGE
/**
* @brief Default to a current range of ±655.36mA
*
* This is the highest resolution suitable to measure USB high-power devices
* (up to 500 mA).
*/
#define INA2XX_PARAM_I_RANGE (INA2XX_CURRENT_RANGE_655_MA)
#endif
#ifndef INA2XX_PARAMS
#define INA2XX_PARAMS { .i2c = INA2XX_PARAM_I2C, \
.addr = INA2XX_PARAM_ADDR, \
.config = INA2XX_PARAM_CONFIG, \
.rshunt_mohm = INA2XX_PARAM_RSHUNT_MOHM, \
.i_range = INA2XX_PARAM_I_RANGE }
#endif
/**@}*/
/**
* @name Set default SAUL info for the INA2XX
* @{
*/
#ifndef INA2XX_SAULINFO
#define INA2XX_SAULINFO { .name = "INA2XX current" }, \
{ .name = "INA2XX power" }, \
{ .name = "INA2XX voltage" }
#endif
/**@}*/
/**
* @brief Configure INA2XX devices
*/
static const ina2xx_params_t ina2xx_params[] =
{
INA2XX_PARAMS
};
/**
* @brief Allocate and configure entries to the SAUL registry
*/
static const saul_reg_info_t ina2xx_saul_info[] =
{
INA2XX_SAULINFO
};
#ifdef __cplusplus
}
#endif
#endif /* INA2XX_PARAMS_H */
/** @} */

View File

@ -1,233 +0,0 @@
/*
* Copyright (C) 2015 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_ina220 INA220 current/power monitor
* @ingroup drivers_sensors
* @brief Device driver for Texas Instruments INA220 High or Low Side,
* Bi-Directional CURRENT/POWER MONITOR with Two-Wire Interface
* @{
*
* @file
* @brief Device driver interface for Texas Instruments INA220 High or Low
* Side, Bi-Directional CURRENT/POWER MONITOR with Two-Wire
* Interface
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef INA220_H
#define INA220_H
#include <stdint.h>
#include "periph/i2c.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Device descriptor for INA220 sensors
*/
typedef struct {
i2c_t i2c; /**< I2C device the sensor is connected to */
uint8_t addr; /**< the slave address of the sensor on the I2C bus */
} ina220_t;
/**
* @brief INA220 possible mode settings
*/
typedef enum ina220_mode {
INA220_MODE_POWERDOWN = 0x0000, /**< Power down */
INA220_MODE_TRIGGER_SHUNT_ONLY = 0x0001, /**< Shunt Voltage, Triggered */
INA220_MODE_TRIGGER_BUS_ONLY = 0x0002, /**< Bus Voltage, Triggered */
INA220_MODE_TRIGGER_SHUNT_BUS = 0x0003, /**< Shunt and Bus, Triggered */
INA220_MODE_ADC_DISABLE = 0x0004, /**< ADC Off (disabled) */
INA220_MODE_CONTINUOUS_SHUNT_ONLY = 0x0005, /**< Shunt Voltage, Continuous */
INA220_MODE_CONTINUOUS_BUS_ONLY = 0x0006, /**< Bus Voltage, Continuous */
INA220_MODE_CONTINUOUS_SHUNT_BUS = 0x0007, /**< Shunt and Bus, Continuous, default */
} ina220_mode_t;
/**
* @brief Shunt voltage measurement range (PGA settings)
*/
typedef enum ina220_range {
INA220_RANGE_40MV = 0x0000, /**< +/- 40 mV range */
INA220_RANGE_80MV = 0x0800, /**< +/- 80 mV range */
INA220_RANGE_160MV = 0x1000, /**< +/- 160 mV range */
INA220_RANGE_320MV = 0x1800, /**< +/- 320 mV range, default */
} ina220_range_t;
/**
* @brief Bus voltage measurement range
*/
typedef enum ina220_brng {
INA220_BRNG_16V_FSR = 0x0000, /**< 16 V bus voltage full scale range */
INA220_BRNG_32V_FSR = 0x2000, /**< 32 V bus voltage full scale range, default. */
} ina220_brng_t;
/**
* @brief Shunt ADC settings
*
* @see Table 4 in INA220 data sheet
*/
typedef enum ina220_sadc {
/** 9 bit resolution, 84 us conversion time */
INA220_SADC_9BIT = 0x0000,
/** 10 bit resolution, 148 us conversion time */
INA220_SADC_10BIT = 0x0008,
/** 11 bit resolution, 276 us conversion time */
INA220_SADC_11BIT = 0x0010,
/** 12 bit resolution, 532 us conversion time, default */
INA220_SADC_12BIT = 0x0018,
/** 12 bit resolution, 532 us conversion time, same as INA220_SADC_12BIT */
INA220_SADC_AVG_1_SAMPLE = 0x0040,
/** 2 sample average, 1.06 ms conversion time */
INA220_SADC_AVG_2_SAMPLES = 0x0048,
/** 4 sample average, 2.13 ms conversion time */
INA220_SADC_AVG_4_SAMPLES = 0x0050,
/** 8 sample average, 4.26 ms conversion time */
INA220_SADC_AVG_8_SAMPLES = 0x0058,
/** 16 sample average, 8.51 ms conversion time */
INA220_SADC_AVG_16_SAMPLES = 0x0060,
/** 32 sample average, 17.02 ms conversion time */
INA220_SADC_AVG_32_SAMPLES = 0x0068,
/** 64 sample average, 34.05 ms conversion time */
INA220_SADC_AVG_64_SAMPLES = 0x0070,
/** 128 sample average, 68.10 ms conversion time */
INA220_SADC_AVG_128_SAMPLES = 0x0078,
} ina220_sadc_t;
/**
* @brief Bus ADC settings
*
* @see Table 4 in INA220 data sheet
*/
typedef enum ina220_badc {
/** 9 bit resolution, 84 us conversion time */
INA220_BADC_9BIT = 0x0000,
/** 10 bit resolution, 148 us conversion time */
INA220_BADC_10BIT = 0x0080,
/** 11 bit resolution, 276 us conversion time */
INA220_BADC_11BIT = 0x0100,
/** 12 bit resolution, 532 us conversion time, default */
INA220_BADC_12BIT = 0x0180,
/** 12 bit resolution, 532 us conversion time, same as INA220_BADC_12BIT */
INA220_BADC_AVG_1_SAMPLE = 0x0400,
/** 2 sample average, 1.06 ms conversion time */
INA220_BADC_AVG_2_SAMPLES = 0x0480,
/** 4 sample average, 2.13 ms conversion time */
INA220_BADC_AVG_4_SAMPLES = 0x0500,
/** 8 sample average, 4.26 ms conversion time */
INA220_BADC_AVG_8_SAMPLES = 0x0580,
/** 16 sample average, 8.51 ms conversion time */
INA220_BADC_AVG_16_SAMPLES = 0x0600,
/** 32 sample average, 17.02 ms conversion time */
INA220_BADC_AVG_32_SAMPLES = 0x0680,
/** 64 sample average, 34.05 ms conversion time */
INA220_BADC_AVG_64_SAMPLES = 0x0700,
/** 128 sample average, 68.10 ms conversion time */
INA220_BADC_AVG_128_SAMPLES = 0x0780,
} ina220_badc_t;
/** INA220 reset command bit (in configuration register) */
#define INA220_RESET_BIT (0x8000)
/** Location of the bus voltage in the INA220 bus voltage register */
#define INA220_BUS_VOLTAGE_SHIFT (3)
/**
* @brief Initialize a current sensor
*
* @param[out] dev device descriptor of sensor to initialize
* @param[in] i2c I2C bus the sensor is connected to
* @param[in] address I2C slave address of the sensor
*
* @return 0 on success
* @return <0 on error
*/
int ina220_init(ina220_t *dev, i2c_t i2c, uint8_t address);
/**
* @brief Write to calibration register
*
* @param[in] dev device descriptor of sensor to configure
* @param[in] calibration calibration register settings, see data sheet
*
* @return 0 on success
* @return <0 on error
*/
int ina220_set_calibration(const ina220_t *dev, uint16_t calibration);
/**
* @brief Write to configuration register
*
* @param[in] dev device descriptor of sensor to configure
* @param[in] config configuration register settings, see data sheet
*
* @return 0 on success
* @return <0 on error
*/
int ina220_set_config(const ina220_t *dev, uint16_t config);
/**
* @brief Read shunt voltage
*
* @param[in] dev device descriptor of sensor
* @param[out] voltage measured voltage across shunt resistor
*
* @return 0 on success
* @return <0 on error
*/
int ina220_read_shunt(const ina220_t *dev, int16_t *voltage);
/**
* @brief Read bus voltage register
*
* The bus voltage can be found in the most significant bits of the bus voltage
* register, the lower three bits are flags/reserved.
*
* See the device data sheet for details.
*
* @param[in] dev device descriptor of sensor
* @param[out] voltage measured bus voltage
*
* @return 0 on success
* @return <0 on error
*/
int ina220_read_bus(const ina220_t *dev, int16_t *voltage);
/**
* @brief Read shunt current
*
* @param[in] dev device descriptor of sensor
* @param[out] current measured current through shunt resistor
*
* @return 0 on success
* @return <0 on error
*/
int ina220_read_current(const ina220_t *dev, int16_t *current);
/**
* @brief Read power consumption
*
* @param[in] dev device descriptor of sensor
* @param[out] power measured power consumption
*
* @return 0 on success
* @return <0 on error
*/
int ina220_read_power(const ina220_t *dev, int16_t *power);
#ifdef __cplusplus
}
#endif
#endif /* INA220_H */
/** @} */

260
drivers/include/ina2xx.h Normal file
View File

@ -0,0 +1,260 @@
/*
* Copyright (C) 2015 Eistec AB
* 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_ina2xx INA2XX current/power monitor
* @ingroup drivers_sensors
* @brief Device driver for Texas Instruments INA219/INA2XX
* Bi-Directional CURRENT/POWER MONITOR with Two-Wire Interface
*
* # Supported Hardware
* This driver currently supports the INA219 and the INA2XX - and possibly
* other devices of the INA2xx family. The popular INA219 breakout boards are
* supported out of the box.
*
* # Choosing the Right Shunt Resistor
* The shunt resistor should generate a voltage drop of at least 40 mV and of
* at most 320 mV at maximum current (add some safety margin to the maximum
* current). E.g. when the expected maximum current is 500 mA and we add a
* safety margin of 33 mA, a 75 mΩ shunt resistor would cause a drop of 40 mV
* at about 533 mA, and a 600 mΩ shunt resistor would cause a drop of 320 mV.
* So every shunt resistor between 75 mΩ and 600 mΩ would result in a decent
* resolution, but shunt resistors that almost max out one of the selectable
* shunt voltage ranges (40 mV, 80 mV, 160 mV and 320 mV) would be ideal.
* Often the voltage drop should be as low as possible, therefore the lowest
* reasonable shunt resistor has to be chosen in that case.
*
* The popular INA219 breakout boards have a shunt resistor of 100 mΩ, which
* allows to measure a current of up to 400 mA at PGA = /1, and of up two 3.2 A
* at PGA = /8.
*
* @{
*
* @file
* @brief Device driver interface for Texas Instruments INA219/INA2XX
* Bi-Directional CURRENT/POWER MONITOR with Two-Wire Interface
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef INA2XX_H
#define INA2XX_H
#include <stdint.h>
#include "periph/i2c.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief INA2XX possible mode settings
*/
typedef enum ina2xx_mode {
INA2XX_MODE_POWERDOWN = 0x0000, /**< Power down */
INA2XX_MODE_TRIGGER_SHUNT_ONLY = 0x0001, /**< Shunt Voltage, Triggered */
INA2XX_MODE_TRIGGER_BUS_ONLY = 0x0002, /**< Bus Voltage, Triggered */
INA2XX_MODE_TRIGGER_SHUNT_BUS = 0x0003, /**< Shunt and Bus, Triggered */
INA2XX_MODE_ADC_DISABLE = 0x0004, /**< ADC Off (disabled) */
INA2XX_MODE_CONTINUOUS_SHUNT_ONLY = 0x0005, /**< Shunt Voltage, Continuous */
INA2XX_MODE_CONTINUOUS_BUS_ONLY = 0x0006, /**< Bus Voltage, Continuous */
INA2XX_MODE_CONTINUOUS_SHUNT_BUS = 0x0007, /**< Shunt and Bus, Continuous, default */
} ina2xx_mode_t;
/**
* @brief Shunt ADC settings
*
* @see Table 4 in INA2XX data sheet
*/
typedef enum ina2xx_sadc {
/** 9 bit resolution, 84 us conversion time */
INA2XX_SADC_9BIT = 0x0000,
/** 10 bit resolution, 148 us conversion time */
INA2XX_SADC_10BIT = 0x0008,
/** 11 bit resolution, 276 us conversion time */
INA2XX_SADC_11BIT = 0x0010,
/** 12 bit resolution, 532 us conversion time, default */
INA2XX_SADC_12BIT = 0x0018,
/** 12 bit resolution, 532 us conversion time, same as INA2XX_SADC_12BIT */
INA2XX_SADC_AVG_1_SAMPLE = 0x0040,
/** 2 sample average, 1.06 ms conversion time */
INA2XX_SADC_AVG_2_SAMPLES = 0x0048,
/** 4 sample average, 2.13 ms conversion time */
INA2XX_SADC_AVG_4_SAMPLES = 0x0050,
/** 8 sample average, 4.26 ms conversion time */
INA2XX_SADC_AVG_8_SAMPLES = 0x0058,
/** 16 sample average, 8.51 ms conversion time */
INA2XX_SADC_AVG_16_SAMPLES = 0x0060,
/** 32 sample average, 17.02 ms conversion time */
INA2XX_SADC_AVG_32_SAMPLES = 0x0068,
/** 64 sample average, 34.05 ms conversion time */
INA2XX_SADC_AVG_64_SAMPLES = 0x0070,
/** 128 sample average, 68.10 ms conversion time */
INA2XX_SADC_AVG_128_SAMPLES = 0x0078,
} ina2xx_sadc_t;
/**
* @brief Bus ADC settings
*
* @see Table 4 in INA2XX data sheet
*/
typedef enum ina2xx_badc {
/** 9 bit resolution, 84 us conversion time */
INA2XX_BADC_9BIT = 0x0000,
/** 10 bit resolution, 148 us conversion time */
INA2XX_BADC_10BIT = 0x0080,
/** 11 bit resolution, 276 us conversion time */
INA2XX_BADC_11BIT = 0x0100,
/** 12 bit resolution, 532 us conversion time, default */
INA2XX_BADC_12BIT = 0x0180,
/** 12 bit resolution, 532 us conversion time, same as INA2XX_BADC_12BIT */
INA2XX_BADC_AVG_1_SAMPLE = 0x0400,
/** 2 sample average, 1.06 ms conversion time */
INA2XX_BADC_AVG_2_SAMPLES = 0x0480,
/** 4 sample average, 2.13 ms conversion time */
INA2XX_BADC_AVG_4_SAMPLES = 0x0500,
/** 8 sample average, 4.26 ms conversion time */
INA2XX_BADC_AVG_8_SAMPLES = 0x0580,
/** 16 sample average, 8.51 ms conversion time */
INA2XX_BADC_AVG_16_SAMPLES = 0x0600,
/** 32 sample average, 17.02 ms conversion time */
INA2XX_BADC_AVG_32_SAMPLES = 0x0680,
/** 64 sample average, 34.05 ms conversion time */
INA2XX_BADC_AVG_64_SAMPLES = 0x0700,
/** 128 sample average, 68.10 ms conversion time */
INA2XX_BADC_AVG_128_SAMPLES = 0x0780,
} ina2xx_badc_t;
/**
* @brief Shunt voltage measurement range (PGA settings)
*/
typedef enum ina2xx_pga {
INA2XX_SHUNT_RANGE_40MV = 0x0000, /**< +/- 40 mV range */
INA2XX_SHUNT_RANGE_80MV = 0x0800, /**< +/- 80 mV range */
INA2XX_SHUNT_RANGE_160MV = 0x1000, /**< +/- 160 mV range */
INA2XX_SHUNT_RANGE_320MV = 0x1800, /**< +/- 320 mV range, default */
} ina2xx_pga_t;
/**
* @brief Bus voltage measurement range
*/
typedef enum ina2xx_brng {
INA2XX_BUS_RANGE_16V = 0x0000, /**< 16 V bus voltage full scale range */
INA2XX_BUS_RANGE_32V = 0x2000, /**< 32 V bus voltage full scale range, default. */
} ina2xx_brng_t;
/**
* @brief Current measurement range
* @warning Choosing a low range and a small shunt resistor can cause
* @ref ina2xx_init to fail. But for high resolution measurements of
* low currents a "big" shunt resistor (e.g. 100 mΩ) should be chosen
* anyway.
*
* Choosing the lowest sufficient range for your use case will result in the
* optimal resolution
*/
typedef enum ina2xx_i_range {
INA2XX_CURRENT_RANGE_327_MA, /**< ±327.68 mA, 0.01mA resolution */
INA2XX_CURRENT_RANGE_655_MA, /**< ±655.36 mA, 0.02mA resolution */
INA2XX_CURRENT_RANGE_1310_MA, /**< ±1310.72 mA, 0.04mA resolution */
INA2XX_CURRENT_RANGE_2621_MA, /**< ±2621.44 mA, 0.08mA resolution */
INA2XX_CURRENT_RANGE_5242_MA, /**< ±5242.88 mA, 0.16mA resolution */
INA2XX_CURRENT_RANGE_10485_MA, /**< ±10485.76 mA, 0.32mA resolution */
} ina2xx_i_range_t;
/**
* @brief Configuration parameters of the INA2xx driver
*/
typedef struct {
i2c_t i2c; /**< I2C device the sensor is connected to */
uint8_t addr; /**< I2C address of the sensr */
uint16_t config; /**< Configuration to apply */
uint16_t rshunt_mohm; /**< Size of the shunt resistor in mΩ */
ina2xx_i_range_t i_range; /**< Range of the measured current */
} ina2xx_params_t;
/**
* @brief Device descriptor for INA2XX sensors
*/
typedef struct {
ina2xx_params_t params; /**< Configuration parameters of the driver */
} ina2xx_t;
/**
* @brief Initialize a current sensor
*
* @param[out] dev device descriptor of sensor to initialize
* @param[in] params Configuration parameters to use
*
* @return `0` on success, `<0` on error.
* @retval 0 Success
* @retval -ENODEV Device seems not to be an INA2XX device
* @retval -EINVAL @p dev or @p params is NULL
* @retval -ERANGE @p params contained invalid setting: Increase
* current range
* @retval <0 Failure, error of @ref i2c_read_regs or
* @ref i2c_write_regs passed through
*/
int ina2xx_init(ina2xx_t *dev, const ina2xx_params_t *params);
/**
* @brief Read shunt voltage in E-05 V
*
* @param[in] dev device descriptor of sensor
* @param[out] voltage measured voltage across shunt resistor in E-05 V
*
* @return 0 on success
* @return <0 on error
*/
int ina2xx_read_shunt(const ina2xx_t *dev, int16_t *voltage);
/**
* @brief Read bus voltage in mV
*
* @param[in] dev device descriptor of sensor
* @param[out] voltage The measured bus voltage in mV
*
* @return `<0` on error, `>= 0` on success
* @retval 0 Success, no new power value available
* @retval 1 Success, new value for @ref ina2xx_read_power ready
* @retval -EDOM Overflow during power/current calculations.
* @retval <0 Error code of @ref i2c_read_regs passed through
*/
int ina2xx_read_bus(const ina2xx_t *dev, uint16_t *voltage);
/**
* @brief Read shunt current in E-05 A
*
* @param[in] dev device descriptor of sensor
* @param[out] current measured current through shunt resistor in E-05 A
*
* @return 0 on success
* @return <0 on error
*/
int ina2xx_read_current(const ina2xx_t *dev, int32_t *current);
/**
* @brief Read power consumption in E-04 W
*
* @param[in] dev device descriptor of sensor
* @param[out] power measured power consumption in E-04 W
*
* @return 0 on success
* @return <0 on error
*/
int ina2xx_read_power(const ina2xx_t *dev, uint32_t *power);
#ifdef __cplusplus
}
#endif
#endif /* INA2XX_H */
/** @} */

View File

@ -105,7 +105,7 @@ enum {
SAUL_SENSE_CAPACITANCE = 0x97, /**< sensor: capacitance */
SAUL_SENSE_VOLTAGE = 0x98, /**< sensor: voltage */
SAUL_SENSE_PH = 0x99, /**< sensor: pH */
SAUL_SENSE_POWER = 0x9A, /**< sensor: (electrical) power */
SAUL_SENSE_POWER = 0x9a, /**< sensor: power */
SAUL_CLASS_ANY = 0xff /**< any device - wildcard */
/* extend this list as needed... */
};

View File

@ -124,6 +124,10 @@ PSEUDOMODULES += cc1101
PSEUDOMODULES += mpu9150
PSEUDOMODULES += mpu9250
# include variants of INA2xx drivers as pseudo modules
PSEUDOMODULES += ina219
PSEUDOMODULES += ina220
# include variants of mrf24j40 drivers as pseudo modules
PSEUDOMODULES += mrf24j40m%

View File

@ -422,6 +422,10 @@ void auto_init(void)
extern void auto_init_hts221(void);
auto_init_hts221();
#endif
#ifdef MODULE_INA2XX
extern void auto_init_ina2xx(void);
auto_init_ina2xx();
#endif
#ifdef MODULE_INA3221
extern void auto_init_ina3221(void);
auto_init_ina3221();

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
/*
* @ingroup sys_auto_init_saul
* @{
*
* @file
* @brief Auto initialization for INA2XX power/current monitors
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#ifdef MODULE_INA2XX
#include "assert.h"
#include "log.h"
#include "saul_reg.h"
#include "ina2xx_params.h"
#include "ina2xx.h"
/**
* @brief Define the number of configured sensors
*/
#define INA2XX_NUM ARRAY_SIZE(ina2xx_params)
/**
* @brief Allocate memory for the device descriptors
*/
static ina2xx_t ina2xx_devs[INA2XX_NUM];
/**
* @brief Memory for the SAUL registry entries
*/
static saul_reg_t saul_entries[INA2XX_NUM * 3];
/**
* @brief Define the number of saul info
*/
#define INA2XX_INFO_NUM ARRAY_SIZE(ina2xx_saul_info)
/**
* @name Import SAUL endpoints
* @{
*/
extern const saul_driver_t ina2xx_saul_current_driver;
extern const saul_driver_t ina2xx_saul_power_driver;
extern const saul_driver_t ina2xx_saul_voltage_driver;
/** @} */
void auto_init_ina2xx(void)
{
assert(INA2XX_INFO_NUM == 3 * INA2XX_NUM);
for (unsigned int i = 0; i < INA2XX_NUM; i++) {
LOG_DEBUG("[auto_init_saul] initializing ina2xx #%u\n", i);
if (ina2xx_init(&ina2xx_devs[i], &ina2xx_params[i])) {
LOG_ERROR("[auto_init_saul] error initializing ina2xx #%u\n", i);
continue;
}
for (unsigned int j = 0; j < 3; j++) {
saul_entries[i * 3 + j].dev = &(ina2xx_devs[i]);
saul_entries[i * 3 + j].name = ina2xx_saul_info[3 * i + j].name;
saul_entries[i * 3 + j].driver = &ina2xx_saul_power_driver;
saul_reg_add(&(saul_entries[i * 3 + j]));
}
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_INA2XX */

View File

@ -1,14 +0,0 @@
include ../Makefile.tests_common
USEMODULE += ina220
USEMODULE += xtimer
# set default device parameters in case they are undefined
TEST_INA220_I2C ?= I2C_DEV\(0\)
TEST_INA220_ADDR ?= 0x40
# export parameters
CFLAGS += -DTEST_INA220_I2C=$(TEST_INA220_I2C)
CFLAGS += -DTEST_INA220_ADDR=$(TEST_INA220_ADDR)
include $(RIOTBASE)/Makefile.include

View File

@ -1,11 +0,0 @@
# About
This is a manual test application for the INA220 current and power monitor driver.
# Usage
This test application will initialize the sensor with the following parameters:
- ADC resolution: 12 bit
- Sampling time: 532 us
- Calibration register: 4096
After initialization, the sensor reads the measurement values every 100ms
and prints them to the STDOUT.

View File

@ -1,102 +0,0 @@
/*
* Copyright (C) 2015 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for the INA220 sensor driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*
* @}
*/
#ifndef TEST_INA220_I2C
#error "TEST_INA220_I2C not defined"
#endif
#ifndef TEST_INA220_ADDR
#error "TEST_INA220_ADDR not defined"
#endif
#include <stdio.h>
#include "xtimer.h"
#include "ina220.h"
/* Use the following configuration:
*
* - Continuous measurements, both shunt and bus voltage
* - +/- 320 mV Vshunt range
* - 32 V maximum bus voltage
* - 12 bit ADC resolution, no hardware averaging
*/
#define CONFIG (INA220_MODE_CONTINUOUS_SHUNT_BUS | INA220_RANGE_320MV | \
INA220_BRNG_32V_FSR | INA220_SADC_12BIT | INA220_BADC_12BIT)
#define CALIBRATION (4096)
#define SLEEP_USEC (100 * 1000U)
int main(void)
{
ina220_t dev;
int16_t val;
puts("INA220 sensor driver test application\n");
printf("Initializing INA220 sensor at I2C_%i, address 0x%02x... ",
TEST_INA220_I2C, TEST_INA220_ADDR);
if (ina220_init(&dev, TEST_INA220_I2C, TEST_INA220_ADDR) == 0) {
puts("[OK]\n");
} else {
puts("[Failed]");
return 1;
}
puts("Set configuration register");
if (ina220_set_config(&dev, CONFIG) == 0) {
puts("[OK]\n");
} else {
puts("[Failed]");
return 1;
}
puts("Set calibration register");
if (ina220_set_calibration(&dev, CALIBRATION) == 0) {
puts("[OK]\n");
} else {
puts("[Failed]");
return 1;
}
while (1) {
/* Read shunt resistor voltage, in millivolts */
ina220_read_shunt(&dev, &val);
printf("shunt: %6d", val);
/* Read VBUS voltage, in millivolts */
ina220_read_bus(&dev, &val);
/* The bus voltage is found in the topmost 13 bits of the bus voltage
* register */
val = (val >> INA220_BUS_VOLTAGE_SHIFT);
printf("\tbus: %6d", val);
/* Read current register, the scale depends on the value of the
* calibration register */
ina220_read_current(&dev, &val);
printf("\tcurrent: %6d", val);
/* Read power register, the scale depends on the value of the
* calibration register */
ina220_read_power(&dev, &val);
printf("\tpower: %6d\n", val);
xtimer_usleep(SLEEP_USEC);
}
return 0;
}

View File

@ -0,0 +1,6 @@
include ../Makefile.tests_common
USEMODULE += fmt_table
USEMODULE += ina219
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,15 @@
# About
This is a manual test application for the INA219/INA220 current and power
monitor driver.
# Usage
This test application will initialize the sensor with the default parameters
in @ref ina2xx_params.h
After initialization, the application will print a table of the devices
measurement data. If the I2C interface is fast enough, one row corresponds to
one measurement of the device. (The sensor indicates when a new measurement is
available via flags, this flags are read until the measurement is done. The
duration of one measurement depends on the sensor settings and is between
84µs and 68.1ms. Please note that blocking stdio might very well be the
bottleneck causing the test to miss measurements.)

104
tests/driver_ina2xx/main.c Normal file
View File

@ -0,0 +1,104 @@
/*
* Copyright (C) 2015 Eistec AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for the INA2XX sensor driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <errno.h>
#include <stdlib.h>
#include "fmt.h"
#include "fmt_table.h"
#include "ina2xx.h"
#include "ina2xx_params.h"
int main(void)
{
ina2xx_t dev;
print_str("INA2XX sensor driver test application\n\n");
print_str("Initializing INA2XX sensor at I2C_");
print_s32_dec(ina2xx_params[0].i2c);
print_str(", address 0x");
print_u32_hex(ina2xx_params[0].addr);
print_str("\n");
if (ina2xx_init(&dev, &ina2xx_params[0]) == 0) {
print_str("[OK]\n");
} else {
print_str("[Failed]\n");
return EXIT_FAILURE;
}
const char *line = "+------------+--------------+----------+--------+\n";
print_str(line);
print_str("| U_Bus [mV] | U_Shunt [µV] | I [µA] | P [µW] |\n");
print_str(line);
while (1) {
uint16_t u_bus;
int16_t u_shunt;
int32_t i_shunt;
uint32_t p;
/* Read bus voltage until flag indicates new value is present */
switch (ina2xx_read_bus(&dev, &u_bus)){
case 0:
/* No measurement available yet */
continue;
case 1:
/* New measurement available, continue */
break;
case -EDOM:
print_str("[WARNING]: INA2xx detected math overflow ==> data "
"will be incorrect\n");
break;
default:
/* Error */
print_str("Error while reading bus voltage\n");
return EXIT_FAILURE;
}
if (ina2xx_read_shunt(&dev, &u_shunt) < 0) {
print_str("Error while reading shunt voltage\n");
return EXIT_FAILURE;
}
if (ina2xx_read_current(&dev, &i_shunt) < 0) {
print_str("Error while reading current\n");
return EXIT_FAILURE;
}
if (ina2xx_read_power(&dev, &p) < 0) {
print_str("Error while reading power\n");
return EXIT_FAILURE;
}
print_str("| ");
print_col_u32_dec(u_bus, 10);
print_str(" | ");
print_col_s32_dec(10 * (int32_t)u_shunt, 12);
print_str(" | ");
print_col_s32_dec(10 * i_shunt, 8);
print_str(" | ");
print_col_u32_dec(100 * p, 6);
print_str(" |\n");
}
return 0;
}