Browse Source

drivers/ina220: Add driver for INA220 current and power sensor.

dev/timer
Joakim Gebart 8 years ago
parent
commit
5ea9eaf386
  1. 3
      drivers/Makefile.include
  2. 3
      drivers/ina220/Makefile
  3. 109
      drivers/ina220/ina220.c
  4. 50
      drivers/ina220/include/ina220-regs.h
  5. 227
      drivers/include/ina220.h
  6. 22
      tests/driver_ina220/Makefile
  7. 11
      tests/driver_ina220/README.md
  8. 106
      tests/driver_ina220/main.c

3
drivers/Makefile.include

@ -40,3 +40,6 @@ endif
ifneq (,$(filter mpu9150,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mpu9150/include
endif
ifneq (,$(filter ina220,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ina220/include
endif

3
drivers/ina220/Makefile

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

109
drivers/ina220/ina220.c

@ -0,0 +1,109 @@
/*
* 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 driver_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 Gebart <joakim.gebart@eistec.se>
*
* @}
*/
#include <stdint.h>
#include "ina220.h"
#include "ina220-regs.h"
#include "periph/i2c.h"
#include "byteorder.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/** @brief Read one 16 bit register from a INA220 device and swap byte order, if necessary. */
static int ina220_read_reg(ina220_t *dev, uint8_t reg, uint16_t *out)
{
union {
char c[2];
uint16_t u16;
} tmp = { .u16 = 0 };
int status = 0;
status = i2c_read_regs(dev->i2c, dev->addr, reg, &tmp.c[0], 2);
if (status != 2) {
return -1;
}
*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(ina220_t *dev, uint8_t reg, uint16_t in)
{
union {
char 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);
if (status != 2) {
return -1;
}
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(ina220_t *dev, uint16_t calibration)
{
return ina220_write_reg(dev, INA220_REG_CALIBRATION, calibration);
}
int ina220_set_config(ina220_t *dev, uint16_t config)
{
return ina220_write_reg(dev, INA220_REG_CONFIGURATION, config);
}
int ina220_read_shunt(ina220_t *dev, int16_t *voltage)
{
return ina220_read_reg(dev, INA220_REG_SHUNT_VOLTAGE, (uint16_t *)voltage);
}
int ina220_read_bus(ina220_t *dev, int16_t *voltage)
{
return ina220_read_reg(dev, INA220_REG_BUS_VOLTAGE, (uint16_t *)voltage);
}
int ina220_read_current(ina220_t *dev, int16_t *current)
{
return ina220_read_reg(dev, INA220_REG_CURRENT, (uint16_t *)current);
}
int ina220_read_power(ina220_t *dev, int16_t *power)
{
return ina220_read_reg(dev, INA220_REG_POWER, (uint16_t *)power);
}

50
drivers/ina220/include/ina220-regs.h

@ -0,0 +1,50 @@
/*
* 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 driver_ina220
* @{
*
* @file
* @brief Register definitions for Texas Instruments INA220 High or Low
* Side, Bi-Directional CURRENT/POWER MONITOR with Two-Wire
* Interface
*
* @author Joakim Gebart <joakim.gebart@eistec.se>
*/
#ifndef INA220_REGS_H
#define INA220_REGS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief INA220 register addresses
*
* All registers in the INA220 are 16 bit wide and transmitted MSB first.
*/
typedef enum ina220_reg {
INA220_REG_CONFIGURATION = 0x00, /**< Configuration register (read/write) */
INA220_REG_SHUNT_VOLTAGE = 0x01, /**< Shunt voltage register (read only) */
INA220_REG_BUS_VOLTAGE = 0x02, /**< Bus voltage register (read only) */
INA220_REG_POWER = 0x03, /**< Power register (read only) */
INA220_REG_CURRENT = 0x04, /**< Current register (read only) */
INA220_REG_CALIBRATION = 0x05, /**< Calibration register (read/write) */
} ina220_reg_t;
#ifdef __cplusplus
}
#endif
#endif /* __L3G4200D_REGS_H */
/** @} */

227
drivers/include/ina220.h

@ -0,0 +1,227 @@
/*
* 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 driver_ina220 INA220 current/power monitor
* @ingroup drivers
* @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 Gebart <joakim.gebart@eistec.se>
*/
#ifndef INA220_H
#define INA220_H
#include <stdint.h>
#include "periph/i2c.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Device descriptor for INA220 sensors
*/
typedef struct {
i2c_t i2c; /**< I2C device the sensor is connected to */
uint8_t addr; /**< the slave address of the sensor on the I2C bus */
} ina220_t;
/** @brief INA220 possible mode settings */
typedef enum ina220_mode {
INA220_MODE_POWERDOWN = 0x0000, /**< Power down */
INA220_MODE_TRIGGER_SHUNT_ONLY = 0x0001, /**< Shunt Voltage, Triggered */
INA220_MODE_TRIGGER_BUS_ONLY = 0x0002, /**< Bus Voltage, Triggered */
INA220_MODE_TRIGGER_SHUNT_BUS = 0x0003, /**< Shunt and Bus, Triggered */
INA220_MODE_ADC_DISABLE = 0x0004, /**< ADC Off (disabled) */
INA220_MODE_CONTINUOUS_SHUNT_ONLY = 0x0005, /**< Shunt Voltage, Continuous */
INA220_MODE_CONTINUOUS_BUS_ONLY = 0x0006, /**< Bus Voltage, Continuous */
INA220_MODE_CONTINUOUS_SHUNT_BUS = 0x0007, /**< Shunt and Bus, Continuous, default */
} ina220_mode_t;
/** @brief Shunt voltage measurement range (PGA settings) */
typedef enum ina220_range {
INA220_RANGE_40MV = 0x0000, /**< +/- 40 mV range */
INA220_RANGE_80MV = 0x0800, /**< +/- 80 mV range */
INA220_RANGE_160MV = 0x1000, /**< +/- 160 mV range */
INA220_RANGE_320MV = 0x1800, /**< +/- 320 mV range, default */
} ina220_range_t;
/** @brief Bus voltage measurement range */
typedef enum ina220_brng {
INA220_BRNG_16V_FSR = 0x0000, /**< 16 V bus voltage full scale range */
INA220_BRNG_32V_FSR = 0x0200, /**< 32 V bus voltage full scale range, default. */
} ina220_brng_t;
/**
* @brief Shunt ADC settings
*
* @see Table 5 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 5 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(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(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(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(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(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(ina220_t *dev, int16_t *power);
#ifdef __cplusplus
}
#endif
#endif /* INA220_H */
/** @} */

22
tests/driver_ina220/Makefile

@ -0,0 +1,22 @@
APPLICATION = driver_ina220
include ../Makefile.tests_common
FEATURES_REQUIRED = periph_i2c
USEMODULE += ina220
USEMODULE += vtimer
ifneq (,$(TEST_INA220_I2C))
CFLAGS += -DTEST_INA220_I2C=$(TEST_INA220_I2C)
else
# set arbitrary default
CFLAGS += -DTEST_INA220_I2C=I2C_0
endif
ifneq (,$(TEST_INA220_ADDR))
CFLAGS += -DTEST_INA220_ADDR=$(TEST_INA220_ADDR)
else
# set arbitrary default
CFLAGS += -DTEST_INA220_ADDR=0x40
endif
include $(RIOTBASE)/Makefile.include

11
tests/driver_ina220/README.md

@ -0,0 +1,11 @@
# 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.

106
tests/driver_ina220/main.c

@ -0,0 +1,106 @@
/*
* 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 Gebart <joakim.gebart@eistec.se>
*
* @}
*/
#ifndef TEST_INA220_I2C
#error "TEST_INA220_I2C not defined"
#endif
#ifndef TEST_INA220_ADDR
#error "TEST_INA220_ADDR not defined"
#endif
#include <stdio.h>
#include "vtimer.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 (100 * 1000U)
int main(void)
{
ina220_t dev;
int16_t val;
puts("INA220 sensor driver test application\n");
printf("Initializing I2C_%i... ", TEST_INA220_I2C);
if (i2c_init_master(TEST_INA220_I2C, I2C_SPEED_FAST) < 0) {
return -1;
}
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);
vtimer_usleep(SLEEP);
}
return 0;
}
Loading…
Cancel
Save