1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-16 19:52:48 +01:00

drivers/ina2xx: Match RIOT's driver design goals

- Use standard RIOT style `ina2xx_params_t` on initialization as explained in
  [1] instead of a custom API
- Provided a default configuration via `ina2xx_params_t` as required by [1] that
  works fine for the INA219 breakout board and with an optimal resolution that
  still covers the whole range of USB high-power devices (500 mA @ 5V) with a
  comfortable safe margin.
- Changed initialization procedure to include a device reset and connectivity
  test, as required by [1]
- The calibration value is now calculated by the driver
    - This simplifies using the driver a lot
    - The user can still choose a trade-off between range and resolution that
      matches the application requirements, but now among predefined values
    - This allows the driver to easily convert the raw data into meaningful
      physical data, as the resolution of the raw data is known
- All measurements are provided as meaningful physical data as required by [1]

[1]: https://github.com/RIOT-OS/RIOT/wiki/Guide:-Writing-a-device-driver-in-RIOT
This commit is contained in:
Marian Buschsieweke 2019-04-04 11:05:26 +02:00
parent f424421f79
commit a6476bd813
No known key found for this signature in database
GPG Key ID: 61F64C6599B1539F
7 changed files with 429 additions and 186 deletions

View File

@ -1,5 +1,6 @@
/*
* 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
@ -16,30 +17,43 @@
* 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-regs.h"
#include "ina2xx_defines.h"
#include "periph/i2c.h"
#include "byteorder.h"
#define ENABLE_DEBUG (0)
#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 = { .u16 = 0 };
} tmp;
int status = 0;
status = i2c_read_regs(dev->i2c, dev->addr, reg, &tmp.c[0], 2, 0);
status = i2c_read_regs(dev->params.i2c, dev->params.addr, reg, &tmp.c[0],
2, 0);
if (status < 0) {
return status;
@ -55,12 +69,13 @@ static int ina2xx_write_reg(const ina2xx_t *dev, uint8_t reg, uint16_t in)
union {
uint8_t c[2];
uint16_t u16;
} tmp = { .u16 = 0 };
} tmp;
int status = 0;
tmp.u16 = htons(in);
status = i2c_write_regs(dev->i2c, dev->addr, reg, &tmp.c[0], 2, 0);
status = i2c_write_regs(dev->params.i2c, dev->params.addr, reg, &tmp.c[0],
2, 0);
if (status < 0) {
return status;
@ -70,22 +85,51 @@ static int ina2xx_write_reg(const ina2xx_t *dev, uint8_t reg, uint16_t in)
}
int ina2xx_init(ina2xx_t *dev, i2c_t i2c, uint8_t address)
int ina2xx_init(ina2xx_t *dev, const ina2xx_params_t *params)
{
/* write device descriptor */
dev->i2c = i2c;
dev->addr = address;
return 0;
}
uint16_t config;
int status;
if (!dev || !params) {
return -EINVAL;
}
int ina2xx_set_calibration(const ina2xx_t *dev, uint16_t calibration)
{
return ina2xx_write_reg(dev, INA2XX_REG_CALIBRATION, calibration);
}
dev->params = *params;
/* Reset device */
status = ina2xx_write_reg(dev, INA2XX_REG_CONFIGURATION, INA2XX_RESET);
if (status < 0) {
return status;
}
int ina2xx_set_config(const ina2xx_t *dev, uint16_t config)
{
return ina2xx_write_reg(dev, INA2XX_REG_CONFIGURATION, config);
/* 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)
@ -93,17 +137,70 @@ 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, int16_t *voltage)
int ina2xx_read_bus(const ina2xx_t *dev, uint16_t *voltage)
{
return ina2xx_read_reg(dev, INA2XX_REG_BUS_VOLTAGE, (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, int16_t *current)
int ina2xx_read_current(const ina2xx_t *dev, int32_t *current)
{
return ina2xx_read_reg(dev, INA2XX_REG_CURRENT, (uint16_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, int16_t *power)
int ina2xx_read_power(const ina2xx_t *dev, uint32_t *power)
{
return ina2xx_read_reg(dev, INA2XX_REG_POWER, (uint16_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

@ -1,5 +1,6 @@
/*
* 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
@ -11,14 +12,15 @@
* @{
*
* @file
* @brief Register definitions for Texas Instruments INA219/INA220
* @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_REGS_H
#define INA2XX_REGS_H
#ifndef INA2XX_DEFINES_H
#define INA2XX_DEFINES_H
#ifdef __cplusplus
@ -40,10 +42,25 @@ typedef enum ina2xx_reg {
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_REGS_H */
#endif /* INA2XX_DEFINES_H */
/** @} */

View File

@ -0,0 +1,109 @@
/*
* 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"
#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
/**@}*/
/**
* @brief Configure INA2XX devices
*/
static const ina2xx_params_t ina2xx_params[] =
{
INA2XX_PARAMS
};
#ifdef __cplusplus
}
#endif
#endif /* INA2XX_PARAMS_H */
/** @} */

View File

@ -1,5 +1,6 @@
/*
* 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
@ -9,20 +10,38 @@
/**
* @defgroup drivers_ina2xx INA2XX current/power monitor
* @ingroup drivers_sensors
* @brief Device driver for Texas Instruments INA219/INA220
* @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 INA220 - and possibly
* other devices of the INA2xx family.
* 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/INA220
* @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
@ -36,14 +55,6 @@
extern "C" {
#endif
/**
* @brief Device descriptor for INA2XX 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 */
} ina2xx_t;
/**
* @brief INA2XX possible mode settings
*/
@ -58,24 +69,6 @@ typedef enum ina2xx_mode {
INA2XX_MODE_CONTINUOUS_SHUNT_BUS = 0x0007, /**< Shunt and Bus, Continuous, default */
} ina2xx_mode_t;
/**
* @brief Shunt voltage measurement range (PGA settings)
*/
typedef enum ina2xx_range {
INA2XX_RANGE_40MV = 0x0000, /**< +/- 40 mV range */
INA2XX_RANGE_80MV = 0x0800, /**< +/- 80 mV range */
INA2XX_RANGE_160MV = 0x1000, /**< +/- 160 mV range */
INA2XX_RANGE_320MV = 0x1800, /**< +/- 320 mV range, default */
} ina2xx_range_t;
/**
* @brief Bus voltage measurement range
*/
typedef enum ina2xx_brng {
INA2XX_BRNG_16V_FSR = 0x0000, /**< 16 V bus voltage full scale range */
INA2XX_BRNG_32V_FSR = 0x2000, /**< 32 V bus voltage full scale range, default. */
} ina2xx_brng_t;
/**
* @brief Shunt ADC settings
*
@ -140,51 +133,83 @@ typedef enum ina2xx_badc {
INA2XX_BADC_AVG_128_SAMPLES = 0x0780,
} ina2xx_badc_t;
/** INA2XX reset command bit (in configuration register) */
#define INA2XX_RESET_BIT (0x8000)
/**
* @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;
/** Location of the bus voltage in the INA2XX bus voltage register */
#define INA2XX_BUS_VOLTAGE_SHIFT (3)
/**
* @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] i2c I2C bus the sensor is connected to
* @param[in] address I2C slave address of the sensor
* @param[in] params Configuration parameters to use
*
* @return 0 on success
* @return <0 on error
* @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, i2c_t i2c, uint8_t address);
int ina2xx_init(ina2xx_t *dev, const ina2xx_params_t *params);
/**
* @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 ina2xx_set_calibration(const ina2xx_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 ina2xx_set_config(const ina2xx_t *dev, uint16_t config);
/**
* @brief Read shunt voltage
* @brief Read shunt voltage in E-05 V
*
* @param[in] dev device descriptor of sensor
* @param[out] voltage measured voltage across shunt resistor
* @param[out] voltage measured voltage across shunt resistor in E-05 V
*
* @return 0 on success
* @return <0 on error
@ -192,42 +217,40 @@ int ina2xx_set_config(const ina2xx_t *dev, uint16_t config);
int ina2xx_read_shunt(const ina2xx_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.
* @brief Read bus voltage in mV
*
* @param[in] dev device descriptor of sensor
* @param[out] voltage measured bus voltage
* @param[out] voltage The measured bus voltage in mV
*
* @return 0 on success
* @return <0 on error
* @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, int16_t *voltage);
int ina2xx_read_bus(const ina2xx_t *dev, uint16_t *voltage);
/**
* @brief Read shunt current
* @brief Read shunt current in E-05 A
*
* @param[in] dev device descriptor of sensor
* @param[out] current measured current through shunt resistor
* @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, int16_t *current);
int ina2xx_read_current(const ina2xx_t *dev, int32_t *current);
/**
* @brief Read power consumption
* @brief Read power consumption in E-04 W
*
* @param[in] dev device descriptor of sensor
* @param[out] power measured power consumption
* @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, int16_t *power);
int ina2xx_read_power(const ina2xx_t *dev, uint32_t *power);
#ifdef __cplusplus
}

View File

@ -1,14 +1,6 @@
include ../Makefile.tests_common
USEMODULE += ina220
USEMODULE += xtimer
# set default device parameters in case they are undefined
TEST_INA2XX_I2C ?= I2C_DEV\(0\)
TEST_INA2XX_ADDR ?= 0x40
# export parameters
CFLAGS += -DTEST_INA2XX_I2C=$(TEST_INA2XX_I2C)
CFLAGS += -DTEST_INA2XX_ADDR=$(TEST_INA2XX_ADDR)
USEMODULE += fmt_table
USEMODULE += ina219
include $(RIOTBASE)/Makefile.include

View File

@ -1,12 +1,15 @@
# About
This is a manual test application for the INA210/INA220 current and power
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 following parameters:
- ADC resolution: 12 bit
- Sampling time: 532 us
- Calibration register: 4096
This test application will initialize the sensor with the default parameters
in @ref ina2xx_params.h
After initialization, the sensor reads the measurement values every 100ms
and prints them to the STDOUT.
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.)

View File

@ -14,88 +14,90 @@
* @brief Test application for the INA2XX sensor driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#ifndef TEST_INA2XX_I2C
#error "TEST_INA2XX_I2C not defined"
#endif
#ifndef TEST_INA2XX_ADDR
#error "TEST_INA2XX_ADDR not defined"
#endif
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include "xtimer.h"
#include "fmt.h"
#include "fmt_table.h"
#include "ina2xx.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 (INA2XX_MODE_CONTINUOUS_SHUNT_BUS | INA2XX_RANGE_320MV | \
INA2XX_BRNG_32V_FSR | INA2XX_SADC_12BIT | INA2XX_BADC_12BIT)
#define CALIBRATION (4096)
#define SLEEP_USEC (100 * 1000U)
#include "ina2xx_params.h"
int main(void)
{
ina2xx_t dev;
int16_t val;
puts("INA2XX sensor driver test application\n");
print_str("INA2XX sensor driver test application\n\n");
printf("Initializing INA2XX sensor at I2C_%i, address 0x%02x... ",
TEST_INA2XX_I2C, TEST_INA2XX_ADDR);
if (ina2xx_init(&dev, TEST_INA2XX_I2C, TEST_INA2XX_ADDR) == 0) {
puts("[OK]\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 {
puts("[Failed]");
return 1;
}
puts("Set configuration register");
if (ina2xx_set_config(&dev, CONFIG) == 0) {
puts("[OK]\n");
} else {
puts("[Failed]");
return 1;
print_str("[Failed]\n");
return EXIT_FAILURE;
}
puts("Set calibration register");
if (ina2xx_set_calibration(&dev, CALIBRATION) == 0) {
puts("[OK]\n");
} else {
puts("[Failed]");
return 1;
}
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) {
/* Read shunt resistor voltage, in millivolts */
ina2xx_read_shunt(&dev, &val);
printf("shunt: %6d", val);
uint16_t u_bus;
int16_t u_shunt;
int32_t i_shunt;
uint32_t p;
/* Read VBUS voltage, in millivolts */
ina2xx_read_bus(&dev, &val);
/* The bus voltage is found in the topmost 13 bits of the bus voltage
* register */
val = (val >> INA2XX_BUS_VOLTAGE_SHIFT);
printf("\tbus: %6d", val);
/* 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;
}
/* Read current register, the scale depends on the value of the
* calibration register */
ina2xx_read_current(&dev, &val);
printf("\tcurrent: %6d", val);
if (ina2xx_read_shunt(&dev, &u_shunt) < 0) {
print_str("Error while reading shunt voltage\n");
return EXIT_FAILURE;
}
/* Read power register, the scale depends on the value of the
* calibration register */
ina2xx_read_power(&dev, &val);
printf("\tpower: %6d\n", val);
if (ina2xx_read_current(&dev, &i_shunt) < 0) {
print_str("Error while reading current\n");
return EXIT_FAILURE;
}
xtimer_usleep(SLEEP_USEC);
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;