diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 3400e2a63d..67ccb63137 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -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 diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 77617c8fb6..9580832c97 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -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))) diff --git a/drivers/ina220/ina220.c b/drivers/ina220/ina220.c deleted file mode 100644 index bb9134895e..0000000000 --- a/drivers/ina220/ina220.c +++ /dev/null @@ -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 - * - * @} - */ - -#include - -#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); -} diff --git a/drivers/ina220/include/ina220-regs.h b/drivers/ina220/include/ina220-regs.h deleted file mode 100644 index b9cbab740c..0000000000 --- a/drivers/ina220/include/ina220-regs.h +++ /dev/null @@ -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 - */ - -#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 */ -/** @} */ diff --git a/drivers/ina220/Makefile b/drivers/ina2xx/Makefile similarity index 68% rename from drivers/ina220/Makefile rename to drivers/ina2xx/Makefile index f0f0efca36..661721f916 100644 --- a/drivers/ina220/Makefile +++ b/drivers/ina2xx/Makefile @@ -1,3 +1,3 @@ -MODULE = ina220 +MODULE = ina2xx include $(RIOTBASE)/Makefile.base diff --git a/drivers/ina2xx/ina2xx.c b/drivers/ina2xx/ina2xx.c new file mode 100644 index 0000000000..5b05c9d228 --- /dev/null +++ b/drivers/ina2xx/ina2xx.c @@ -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 + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include + +#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; +} diff --git a/drivers/ina2xx/ina2xx_saul.c b/drivers/ina2xx/ina2xx_saul.c new file mode 100644 index 0000000000..b92c57e414 --- /dev/null +++ b/drivers/ina2xx/ina2xx_saul.c @@ -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 + * + * @} + */ + +#include +#include +#include + +#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, ¤t) == 0) { + res->scale = -5; + res->unit = UNIT_A; + phydat_fit(res, ¤t, 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 +}; diff --git a/drivers/ina2xx/include/ina2xx_defines.h b/drivers/ina2xx/include/ina2xx_defines.h new file mode 100644 index 0000000000..88289f567e --- /dev/null +++ b/drivers/ina2xx/include/ina2xx_defines.h @@ -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 + * @author Marian Buschsieweke + */ + +#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 */ +/** @} */ diff --git a/drivers/ina2xx/include/ina2xx_params.h b/drivers/ina2xx/include/ina2xx_params.h new file mode 100644 index 0000000000..0311c7fbdf --- /dev/null +++ b/drivers/ina2xx/include/ina2xx_params.h @@ -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 + */ + +#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 */ +/** @} */ diff --git a/drivers/include/ina220.h b/drivers/include/ina220.h deleted file mode 100644 index 803e84d883..0000000000 --- a/drivers/include/ina220.h +++ /dev/null @@ -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 - */ - -#ifndef INA220_H -#define INA220_H - -#include - -#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 */ -/** @} */ diff --git a/drivers/include/ina2xx.h b/drivers/include/ina2xx.h new file mode 100644 index 0000000000..8a1b7a55c6 --- /dev/null +++ b/drivers/include/ina2xx.h @@ -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 + * @author Marian Buschsieweke + */ + +#ifndef INA2XX_H +#define INA2XX_H + +#include + +#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 */ +/** @} */ diff --git a/drivers/include/saul.h b/drivers/include/saul.h index a5e6b55d3a..c8afbcd3fa 100644 --- a/drivers/include/saul.h +++ b/drivers/include/saul.h @@ -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... */ }; diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 0e2121767b..f6b7c6b123 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -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% diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 0a4ed3febc..0e09305184 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -422,10 +422,14 @@ 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(); - #endif +#endif #ifdef MODULE_IO1_XPLAINED extern void auto_init_io1_xplained(void); auto_init_io1_xplained(); diff --git a/sys/auto_init/saul/auto_init_ina2xx.c b/sys/auto_init/saul/auto_init_ina2xx.c new file mode 100644 index 0000000000..ad72810766 --- /dev/null +++ b/sys/auto_init/saul/auto_init_ina2xx.c @@ -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 + * + * @} + */ + +#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 */ diff --git a/tests/driver_ina220/Makefile b/tests/driver_ina220/Makefile deleted file mode 100644 index 276de9c03a..0000000000 --- a/tests/driver_ina220/Makefile +++ /dev/null @@ -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 diff --git a/tests/driver_ina220/README.md b/tests/driver_ina220/README.md deleted file mode 100644 index e922443dcd..0000000000 --- a/tests/driver_ina220/README.md +++ /dev/null @@ -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. diff --git a/tests/driver_ina220/main.c b/tests/driver_ina220/main.c deleted file mode 100644 index 74252d4aba..0000000000 --- a/tests/driver_ina220/main.c +++ /dev/null @@ -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 - * - * @} - */ - -#ifndef TEST_INA220_I2C -#error "TEST_INA220_I2C not defined" -#endif -#ifndef TEST_INA220_ADDR -#error "TEST_INA220_ADDR not defined" -#endif - -#include - -#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; -} diff --git a/tests/driver_ina2xx/Makefile b/tests/driver_ina2xx/Makefile new file mode 100644 index 0000000000..88dd18f1ca --- /dev/null +++ b/tests/driver_ina2xx/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.tests_common + +USEMODULE += fmt_table +USEMODULE += ina219 + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_ina2xx/README.md b/tests/driver_ina2xx/README.md new file mode 100644 index 0000000000..13c9a3eb7b --- /dev/null +++ b/tests/driver_ina2xx/README.md @@ -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.) diff --git a/tests/driver_ina2xx/main.c b/tests/driver_ina2xx/main.c new file mode 100644 index 0000000000..97ef83a5e0 --- /dev/null +++ b/tests/driver_ina2xx/main.c @@ -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 + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include + +#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; +}