
8 changed files with 531 additions and 0 deletions
@ -0,0 +1,3 @@
|
||||
MODULE = ina220
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -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); |
||||
} |
@ -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 */ |
||||
/** @} */ |
@ -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 */ |
||||
/** @} */ |
@ -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 |
@ -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. |
@ -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…
Reference in new issue