-
Notifications
You must be signed in to change notification settings - Fork 2
/
ina219.c
196 lines (147 loc) · 4.2 KB
/
ina219.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "ina219.h"
//physics constants
//shunt voltage precision = 10 mkV
#define INA_219_DEVICE_SHUNT_VOLTAGE_LSB 1e+05
//bus voltage precision = 4 mV
#define INA_219_DEVICE_BUS_VOLTAGE_LSB 250
static int32_t ina_219_device_read_reg(ina_219_device *dev, uint8_t reg);
static int32_t ina_219_device_write_reg(ina_219_device *dev, uint8_t refg, uint16_t data);
ina_219_device* ina_219_device_open(const char * ina_219_device_filename, uint8_t i2c_device_addr)
{
ina_219_device *res = (ina_219_device*) malloc(sizeof(ina_219_device));
//open file-descriptor
if ((res->fd = open(ina_219_device_filename, O_RDWR)) < 0)
goto open_i2c_error;
//set device address
if (ioctl(res->fd, I2C_SLAVE, i2c_device_addr) < 0)
goto address_device_error;
res->shunt_on = 0;
res->bus_on = 0;
return res;
address_device_error:
printf("init communication with device error\n");
open_i2c_error:
printf("open device error\n");
printf("device addr: %x\n", i2c_device_addr);
free(res);
return NULL;
}
int ina_219_device_close(ina_219_device *dev)
{
close(dev->fd);
free(dev);
}
/*
shunt_resistor_resistance in Om
max_current in A
*/
double ina_219_device_get_current(ina_219_device *dev)
{
int32_t res = ina_219_device_read_reg(dev, INA_219_DEVICE_CURRENT_REG);
if (res < 0) {
printf("read current error\n");
exit(1);
}
//не забываем отбросить старшие разряды
int16_t res_p = (int16_t)res;
return (double)res_p / dev->current_LSB;
}
double ina_219_device_get_bus_voltage(ina_219_device *dev)
{
int32_t res;
int16_t res_p;
if (!dev->bus_on) {
printf("warning: bus mode is off\n");
return 0.0;
}
do {
res = ina_219_device_read_reg(dev, INA_219_DEVICE_BUS_VOLTAGE_REG);
if (res < 0) {
printf("read bus voltage error\n");
exit(1);
}
//не забываем отбросить старшие разряды
res_p = (int16_t)res;
} while (!(res_p & 0b10u));
if (res_p & 0b01u) {
printf("Math Overflow error\n");
return 0;
}
res_p >>= 3;
return (double)res_p / 250;
}
double ina_219_device_get_shunt_voltage(ina_219_device *dev)
{
if (!dev->shunt_on) {
printf("warning: shunt mode is off\n");
return 0.0;
}
int32_t res = ina_219_device_read_reg(dev, INA_219_DEVICE_SHUNT_VOLTAGE_REG);
if (res < 0) {
printf("read shunt voltage error\n");
exit(1);
}
//не забываем отбросить старшие разряды
int16_t res_p = (int16_t)res;
return (double)res_p / dev->shunt_LSB;
}
int32_t ina_219_device_calibrate(ina_219_device *dev, double shunt_resistor_resistance, double max_current)
{
double current_LSB = max_current / 32768;
unsigned degree = 1;
while ((int)current_LSB < 1 ) {
current_LSB *= 10;
degree *= 10;
}
degree = degree >= 10 ? degree / 10 : 1;
dev->current_LSB = degree;
dev->bus_LSB = INA_219_DEVICE_BUS_VOLTAGE_LSB;
dev->shunt_LSB = INA_219_DEVICE_SHUNT_VOLTAGE_LSB;
current_LSB = 1 / (double) degree;
double calibration = 0.04096 / (shunt_resistor_resistance * current_LSB);
uint16_t cal_reg_value = (uint16_t) trunc(calibration);
return ina_219_device_write_reg(dev, INA_219_DEVICE_CALIBRATION_REG, cal_reg_value);
}
int32_t ina_219_device_config(ina_219_device *dev, uint16_t conf_p)
{
if (~(conf_p | ~INA_219_DEVICE_MODE_SHUNT))
dev->shunt_on = 0;
else
dev->shunt_on = 1;
if (~(conf_p | ~INA_219_DEVICE_MODE_BUS))
dev->bus_on = 0;
else
dev->bus_on = 1;
return ina_219_device_write_reg(dev, INA_219_DEVICE_CONFIG_REG, conf_p);
}
int32_t ina_219_device_reset(ina_219_device *dev)
{
return ina_219_device_write_reg(dev, INA_219_DEVICE_CONFIG_REG, INA_219_DEVICE_RESET);
}
//read word and swap it
int32_t ina_219_device_read_reg(ina_219_device *dev, uint8_t reg)
{
int32_t res;
res = i2c_smbus_read_word_data(dev->fd, reg);
if (res < 0)
return -1;
//swap bytes
res = ((res << 8) | (res >> 8)) & 0xffff;
return res;
}
//swap data-word and write it
int32_t ina_219_device_write_reg(ina_219_device *dev, uint8_t reg, uint16_t data)
{
int32_t res;
//swap bytes
data = (data << 8) | (data >> 8);
res = i2c_smbus_write_word_data(dev->fd, reg, data);
return res;
}