From a6476bd813e59c28601efff95480370ae1dc3032 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Thu, 4 Apr 2019 11:05:26 +0200 Subject: [PATCH] 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 --- drivers/ina2xx/ina2xx.c | 147 +++++++++++--- .../{ina2xx-regs.h => ina2xx_defines.h} | 25 ++- drivers/ina2xx/include/ina2xx_params.h | 109 +++++++++++ drivers/include/ina2xx.h | 181 ++++++++++-------- tests/driver_ina2xx/Makefile | 12 +- tests/driver_ina2xx/README.md | 17 +- tests/driver_ina2xx/main.c | 124 ++++++------ 7 files changed, 429 insertions(+), 186 deletions(-) rename drivers/ina2xx/include/{ina2xx-regs.h => ina2xx_defines.h} (60%) create mode 100644 drivers/ina2xx/include/ina2xx_params.h diff --git a/drivers/ina2xx/ina2xx.c b/drivers/ina2xx/ina2xx.c index 4ac1830fbc..5b05c9d228 100644 --- a/drivers/ina2xx/ina2xx.c +++ b/drivers/ina2xx/ina2xx.c @@ -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 + * @author Marian Buschsieweke * * @} */ +#include #include #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; } diff --git a/drivers/ina2xx/include/ina2xx-regs.h b/drivers/ina2xx/include/ina2xx_defines.h similarity index 60% rename from drivers/ina2xx/include/ina2xx-regs.h rename to drivers/ina2xx/include/ina2xx_defines.h index d064d9d61c..88289f567e 100644 --- a/drivers/ina2xx/include/ina2xx-regs.h +++ b/drivers/ina2xx/include/ina2xx_defines.h @@ -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 + * @author Marian Buschsieweke */ -#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 */ /** @} */ diff --git a/drivers/ina2xx/include/ina2xx_params.h b/drivers/ina2xx/include/ina2xx_params.h new file mode 100644 index 0000000000..d26ea8991d --- /dev/null +++ b/drivers/ina2xx/include/ina2xx_params.h @@ -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 + */ + +#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 */ +/** @} */ diff --git a/drivers/include/ina2xx.h b/drivers/include/ina2xx.h index 8b774ddd1a..8a1b7a55c6 100644 --- a/drivers/include/ina2xx.h +++ b/drivers/include/ina2xx.h @@ -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 + * @author Marian Buschsieweke */ #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 } diff --git a/tests/driver_ina2xx/Makefile b/tests/driver_ina2xx/Makefile index 0321a1a38a..88dd18f1ca 100644 --- a/tests/driver_ina2xx/Makefile +++ b/tests/driver_ina2xx/Makefile @@ -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 diff --git a/tests/driver_ina2xx/README.md b/tests/driver_ina2xx/README.md index c352947b97..13c9a3eb7b 100644 --- a/tests/driver_ina2xx/README.md +++ b/tests/driver_ina2xx/README.md @@ -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.) diff --git a/tests/driver_ina2xx/main.c b/tests/driver_ina2xx/main.c index 0d048a6fe7..97ef83a5e0 100644 --- a/tests/driver_ina2xx/main.c +++ b/tests/driver_ina2xx/main.c @@ -14,88 +14,90 @@ * @brief Test application for the INA2XX sensor driver * * @author Joakim Nohlgård + * @author Marian Buschsieweke * * @} */ -#ifndef TEST_INA2XX_I2C -#error "TEST_INA2XX_I2C not defined" -#endif -#ifndef TEST_INA2XX_ADDR -#error "TEST_INA2XX_ADDR not defined" -#endif +#include +#include -#include - -#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;