SELKIELogger  1.0.0
I2C-INA219.c
1 /*
2  * Copyright (C) 2023 Swansea University
3  *
4  * This file is part of the SELKIELogger suite of tools.
5  *
6  * SELKIELogger is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * SELKIELogger is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this SELKIELogger product.
18  * If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <math.h>
22 #include <stdint.h>
23 #include <unistd.h>
24 
25 #include <i2c/smbus.h>
26 #include <linux/i2c-dev.h>
27 #include <sys/ioctl.h>
28 
29 #include "I2C-INA219.h"
30 #include "I2CConnection.h"
31 
40 bool i2c_ina219_configure(const int busHandle, const int devAddr) {
41  if (ioctl(busHandle, I2C_SLAVE, devAddr) < 0) { return false; }
42 
43  if (i2c_smbus_write_word_data(busHandle, INA219_REG_CONFIG, INA219_CONFIG_DEF | INA219_CONFIG_RESET) < 0) {
44  return false;
45  }
46 
47  if (i2c_smbus_write_word_data(busHandle, INA219_REG_CALIBRATION, i2c_swapbytes(4096)) < 0) { return false; }
48  usleep(500);
49  return true;
50 }
51 
59 uint16_t i2c_ina219_read_configuration(const int busHandle, const int devAddr) {
60  if (ioctl(busHandle, I2C_SLAVE, devAddr) < 0) { return false; }
61 
62  int32_t res = i2c_smbus_read_word_data(busHandle, INA219_REG_CONFIG);
63  if (res < 0) { return -1; }
64  return ((uint16_t)i2c_swapbytes(res));
65 }
66 
77 float i2c_ina219_read_shuntVoltage(const int busHandle, const int devAddr, const void *opts) {
78  if (ioctl(busHandle, I2C_SLAVE, devAddr) < 0) { return NAN; }
79  if (!i2c_ina219_configure(busHandle, devAddr)) { return NAN; }
80 
81  int32_t res = i2c_smbus_read_word_data(busHandle, INA219_REG_SHUNT);
82  if (res < 0) { return NAN; }
83 
84  uint16_t sres = i2c_swapbytes(res);
85  float shuntV = 0;
86  if ((sres & 0x8000)) {
87  uint16_t t = (sres & 0x7FFF) + 1;
88  shuntV = ~t * 1E-2;
89  } else {
90  shuntV = (sres & 0x7FFF) * 1E-2;
91  }
92 
93  if (shuntV > 320.0 || shuntV < -320.0) { return NAN; }
94  if (opts) {
96  float t = shuntV * o->scale + o->offset;
97  if ((t < o->min) || (t > o->max)) { return NAN; }
98  return t;
99  }
100  return shuntV; // If no options supplied, return unscaled value
101 }
102 
115 float i2c_ina219_read_busVoltage(const int busHandle, const int devAddr, const void *opts) {
116  if (ioctl(busHandle, I2C_SLAVE, devAddr) < 0) { return NAN; }
117  if (!i2c_ina219_configure(busHandle, devAddr)) { return NAN; }
118 
119  int32_t res = i2c_smbus_read_word_data(busHandle, INA219_REG_BUS);
120  if (res < 0) { return NAN; }
121 
122  uint16_t sres = i2c_swapbytes(res);
123  uint8_t flags = (sres & 0x03);
124  if ((flags & 0x01) || !(flags & 0x02)) { return NAN; }
125 
126  float busV = (sres >> 3) * 4E-3;
127  if (opts) {
129  float t = busV * o->scale + o->offset;
130  if ((t < o->min) || (t > o->max)) { return NAN; }
131  return t;
132  }
133  return busV;
134 }
135 
148 float i2c_ina219_read_power(const int busHandle, const int devAddr, const void *opts) {
149  if (ioctl(busHandle, I2C_SLAVE, devAddr) < 0) { return NAN; }
150  if (!i2c_ina219_configure(busHandle, devAddr)) { return NAN; }
151 
152  int32_t res = i2c_smbus_read_word_data(busHandle, INA219_REG_POWER);
153  if (res < 0) { return NAN; }
154  uint16_t sres = i2c_swapbytes(res);
155  float power = sres * 2E-3;
156  if (opts) {
158  float t = power * o->scale + o->offset;
159  if ((t < o->min) || (t > o->max)) { return NAN; }
160  return t;
161  }
162  return power;
163 }
164 
173 float i2c_ina219_read_current(const int busHandle, const int devAddr, const void *opts) {
174  if (ioctl(busHandle, I2C_SLAVE, devAddr) < 0) { return NAN; }
175  if (!i2c_ina219_configure(busHandle, devAddr)) { return NAN; }
176 
177  int32_t res = i2c_smbus_read_word_data(busHandle, INA219_REG_CURRENT);
178  if (res < 0) { return NAN; }
179  uint16_t sres = i2c_swapbytes(res);
180  float current = 0;
181  if ((sres & 0x8000)) {
182  uint16_t t = ~(sres & 0x7FFF) + 1;
183  current = t * 1E-4;
184  } else {
185  current = (sres & 0x7FFF) * 1E-4;
186  }
187  if (opts) {
189  float t = current * o->scale + o->offset;
190  if ((t < o->min) || (t > o->max)) { return NAN; }
191  return t;
192  }
193  return current;
194 }
int16_t i2c_swapbytes(const int16_t in)
Swap word byte order.
Definition: I2CConnection.c:58
float i2c_ina219_read_shuntVoltage(const int busHandle, const int devAddr, const void *opts)
Get voltage across the shunt resistor in millivolts.
Definition: I2C-INA219.c:77
bool i2c_ina219_configure(const int busHandle, const int devAddr)
Send configuration command to the specified device.
Definition: I2C-INA219.c:40
float i2c_ina219_read_current(const int busHandle, const int devAddr, const void *opts)
Get current flow through shunt resistor in amps.
Definition: I2C-INA219.c:173
float i2c_ina219_read_busVoltage(const int busHandle, const int devAddr, const void *opts)
Get bus voltage (at V- terminal) in volts.
Definition: I2C-INA219.c:115
uint16_t i2c_ina219_read_configuration(const int busHandle, const int devAddr)
Read configuration from device.
Definition: I2C-INA219.c:59
float i2c_ina219_read_power(const int busHandle, const int devAddr, const void *opts)
Get power consumption in watts.
Definition: I2C-INA219.c:148
#define INA219_CONFIG_RESET
Definition: I2C-INA219.h:83
#define INA219_CONFIG_DEF
Default sensor configuration for this library.
Definition: I2C-INA219.h:78
#define INA219_REG_SHUNT
INA219 shunt voltage register.
Definition: I2C-INA219.h:46
#define INA219_REG_CALIBRATION
INA219 calibration registor.
Definition: I2C-INA219.h:58
#define INA219_REG_CONFIG
INA219 configuration register.
Definition: I2C-INA219.h:43
#define INA219_REG_BUS
INA219 bus voltage register.
Definition: I2C-INA219.h:49
#define INA219_REG_POWER
INA219 calculated power register.
Definition: I2C-INA219.h:52
#define INA219_REG_CURRENT
INA219 current register.
Definition: I2C-INA219.h:55
float offset
Add this amount to received value.
Definition: I2C-INA219.h:87
float max
If not NaN, largest value considered valid.
Definition: I2C-INA219.h:89
float scale
Scale received value by this quantity.
Definition: I2C-INA219.h:86