Statistics
| Branch: | Tag: | Revision:

amiro-lld / source / alld_ina219.c @ e2db16a4

History | View | Annotate | Download (11.714 KB)

1
/*
2
AMiRo-LLD is a compilation of low-level hardware drivers for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2018  Thomas Schöpping et al.
4

5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9

10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14

15
You should have received a copy of the GNU General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
*/
18

    
19
#include <alld_ina219.h>
20

    
21
#if defined(AMIROLLD_CFG_USE_INA219) || defined(__DOXYGEN__)
22

    
23
/**
24
 * @brief Read the value of one or more of the registers.
25
 * @param[in]   i2cd        i2c driver
26
 * @param[in]   inad        ina219 driver
27
 * @param[in]   addr        register address
28
 * @param[out]  data        register content
29
 * @param[in]   num         number of subsequent registers to read
30
 * @param[in]   timeout     timeout
31
 * @return                  An indicator whether the call was successfull
32
 */
33
inline apalExitStatus_t
34
ina219_lld_read_register(const INA219Driver* const ina219, const ina219_lld_register_t addr, uint16_t* const data, const uint8_t num, const apalTime_t timeout)
35
{
36
  apalDbgAssert(ina219 != NULL);
37
  apalDbgAssert(ina219->i2cd != NULL);
38
  apalDbgAssert(data != NULL);
39

    
40
  uint8_t buffer[num*2];
41
  apalExitStatus_t status = apalI2CMasterTransmit(ina219->i2cd, (INA219_LLD_I2C_ADDR_FIXED | ina219->addr), (uint8_t*)&addr, 1, buffer, 2*num, timeout);
42
  for (uint8_t dataIdx = 0; dataIdx < num; dataIdx++) {
43
    data[dataIdx] = (buffer[2*dataIdx] << 8) | buffer[2*dataIdx+1];
44
  }
45
  return status;
46
}
47

    
48
/**
49
 * @brief Write the value of one or more of the registers.
50
 * @param[in]   i2cd        i2c driver
51
 * @param[in]   inad        ina219 driver
52
 * @param[in]   addr        register address
53
 * @param[in]   data        data to write
54
 * @param[in]   num         number of subsequent registers to read
55
 * @param[in]   timeout     timeout
56
 * @return                  An indicator whether the call was successfull
57
 */
58
inline apalExitStatus_t
59
ina219_lld_write_register(const INA219Driver* const ina219, const ina219_lld_register_t addr, const uint16_t* const data, const uint8_t num, const apalTime_t timeout)
60
{
61
  apalDbgAssert(ina219 != NULL);
62
  apalDbgAssert(ina219->i2cd != NULL);
63
  apalDbgAssert(data != NULL);
64

    
65
  uint8_t buffer[1+2*num];
66
  buffer[0] = addr;
67
  for (uint8_t dataIdx = 0; dataIdx < num; dataIdx++) {
68
    buffer[dataIdx*2+1] = data[dataIdx] >> 8;
69
    buffer[dataIdx*2+2] = data[dataIdx] & (0x00FFu);
70
  }
71
  return apalI2CMasterTransmit(ina219->i2cd, (INA219_LLD_I2C_ADDR_FIXED | ina219->addr), buffer, 1+2*num, NULL, 0, timeout);
72
}
73

    
74
/**
75
 * @brief Calibrate the ina219.
76
 * @param[in]   i2cd        i2c driver
77
 * @param[in]   inad        APAL_STATUS_SUCCESS;
78
 * @param[in]   calib_in    calibration input data
79
 * @param[out]  calib_out   output of the calibration
80
 * @param[in]   timeout     timeout
81
 * @return                  An indicator whether the call was successfull
82
 */
83
inline apalExitStatus_t
84
ina219_lld_calibration(INA219Driver* const ina219, const ina219_lld_calib_input_t* const calib_in, ina219_lld_calib_output_t* const calib_out)
85
{
86
  apalDbgAssert(ina219 != NULL);
87
  apalDbgAssert(calib_in != NULL);
88
  apalDbgAssert(calib_out != NULL);
89

    
90
  uint16_t current_lsb_uA = calib_in->current_lsb_uA;
91
  if (current_lsb_uA < calib_in->max_expected_current_A / 0.032768f) {
92
    current_lsb_uA = calib_in->max_expected_current_A / 0.032768f;
93
  } else if (current_lsb_uA > calib_in->max_expected_current_A / 0.004096f) {
94
    current_lsb_uA = calib_in->max_expected_current_A / 0.004096f;
95
  }
96

    
97
  uint16_t calib_value = (uint16_t) (40960 / (current_lsb_uA * calib_in->shunt_resistance_0));
98

    
99
  float V_shunt_max;
100
  switch (calib_in->cfg_reg.options.gain) {
101
    case INA219_LLD_GAIN_1_40mV:
102
        V_shunt_max = 0.04f;
103
        break;
104
    case INA219_LLD_GAIN_2_80mV:
105
        V_shunt_max = 0.08f;
106
        break;
107
    case INA219_LLD_GAIN_4_160mV:
108
        V_shunt_max = 0.16f;
109
        break;
110
    case INA219_LLD_GAIN_8_320mV:
111
        V_shunt_max = 0.32f;
112
        break;
113
  }
114

    
115
  calib_out->max_current_before_overflow_A = (current_lsb_uA * 0.032767f >= V_shunt_max /calib_in->shunt_resistance_0) ?
116
                                                V_shunt_max / calib_in->shunt_resistance_0 :
117
                                                current_lsb_uA * 0.032767f;
118
  calib_out->max_shunt_voltage_before_overflow_V =
119
                                ((calib_out->max_current_before_overflow_A * calib_in->shunt_resistance_0) >= V_shunt_max) ?
120
                                                   V_shunt_max :
121
                                                   calib_out->max_current_before_overflow_A * calib_in->shunt_resistance_0;
122

    
123
  calib_out->current_lsb_uA = current_lsb_uA;
124
  calib_out->calibration = calib_value;
125

    
126
  ina219->current_lsb_uA = current_lsb_uA;
127

    
128
  return APAL_STATUS_SUCCESS;
129
}
130

    
131
/**
132
 * @brief Read the current configuration.
133
 * @param[in]   i2cd        i2c driver
134
 * @param[in]   inad        ina219 driver
135
 * @param[out]  cfg         current configuration
136
 * @param[in]   timeout     timeout
137
 * @return                  An indicator whether the call was successfull
138
 */
139
inline apalExitStatus_t
140
ina219_lld_read_config(const INA219Driver* const ina219, ina219_lld_cfg_t* const cfg, const apalTime_t timeout)
141
{
142
  apalDbgAssert(ina219 != NULL);
143
  apalDbgAssert(cfg != NULL);
144

    
145
  return ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &cfg->data, 1, timeout);
146
}
147

    
148
/**
149
 * @brief Write a new configuration.
150
 * @param[in]   i2cd        i2c driver
151
 * @param[in]   inad        ina219 driver
152
 * @param[in]   cfg         new configuration
153
 * @param[in]   timeout     timeout
154
 * @return                  An indicator whether the call was successfull
155
 */
156
inline apalExitStatus_t
157
ina219_lld_write_config(const INA219Driver* const ina219, ina219_lld_cfg_t cfg, const apalTime_t timeout)
158
{
159
  apalDbgAssert(ina219 != NULL);
160

    
161
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &cfg.data, 1, timeout);
162
}
163

    
164
/**
165
 * @brief Read the current calibration value.
166
 * @param[in]   i2cd        i2c driver
167
 * @param[in]   inad        ina219 driver
168
 * @param[out]  calib       current calibration value
169
 * @param[in]   timeout     timeout
170
 * @return                  An indicator whether the call was successfull
171
 */
172
inline apalExitStatus_t
173
ina219_lld_read_calibration(const INA219Driver* const ina219, uint16_t* const calib, const apalTime_t timeout)
174
{
175
  apalDbgAssert(ina219 != NULL);
176
  apalDbgAssert(calib != NULL);
177

    
178
  return ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CALIBRATION, calib, 1, timeout);
179
}
180

    
181
/**
182
 * @brief Write a new calibration value.
183
 * @param[in]   i2cd        i2c driver
184
 * @param[in]   inad        ina219 driver
185
 * @param[in]   calib       new calibration value
186
 * @param[in]   timeout     timeout
187
 * @return                  An indicator whether the call was successfull
188
 */
189
inline apalExitStatus_t
190
ina219_lld_write_calibration(const INA219Driver* const ina219, const uint16_t calib, const apalTime_t timeout)
191
{
192
  apalDbgAssert(ina219 != NULL);
193

    
194
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CALIBRATION, &calib, 1, timeout);
195
}
196

    
197
/**
198
 * @brief Reset the ina219.
199
 * @param[in]   i2cd        i2c driver
200
 * @param[in]   inad        ina219 driver
201
 * @param[in]   timeout     timeout
202
 * @return                  An indicator whether the call was successfull
203
 */
204
inline apalExitStatus_t
205
ina219_lld_reset(const INA219Driver* const ina219, const apalTime_t timeout)
206
{
207
  apalDbgAssert(ina219 != NULL);
208

    
209
  uint16_t data = 0x8000;
210
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &data, 1, timeout);
211
}
212

    
213
/**
214
 * @brief Read the current shunt voltage (uV).
215
 * @param[in]   i2cd        i2c driver
216
 * @param[in]   inad        ina219 driver
217
 * @param[out]  data        shunt voltage
218
 * @param[in]   timeout     timeout
219
 * @return                  An indicator whether the call was successfull
220
 */
221
inline apalExitStatus_t
222
ina219_lld_read_shunt_voltage(const INA219Driver* const ina219, int32_t* const data, const apalTime_t timeout)
223
{
224
  apalDbgAssert(ina219 != NULL);
225
  apalDbgAssert(data != NULL);
226

    
227
  uint16_t buffer = 0;
228
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_SHUNT_VOLTAGE, &buffer, 1, timeout);
229

    
230
  switch (ina219->config->options.gain) {
231
    case INA219_LLD_GAIN_8_320mV:
232
      *data = (int32_t)(buffer & 0x7FFFu) * ((buffer & 0x8000u) ? -10 : 10);
233
      break;
234
    case INA219_LLD_GAIN_4_160mV:
235
      *data = (int32_t)(buffer & 0x3FFFu) * ((buffer & 0xC000u) ? -10 : 10);
236
      break;
237
    case INA219_LLD_GAIN_2_80mV:
238
      *data = (int32_t)(buffer & 0x1FFFu) * ((buffer & 0xE000u) ? -10 : 10);
239
      break;
240
    case INA219_LLD_GAIN_1_40mV:
241
      *data = (int32_t)(buffer & 0x0FFFu) * ((buffer & 0xF000u) ? -10 : 10);
242
      break;
243
  }
244

    
245
  return status;
246
}
247

    
248
/**
249
 * @brief Read the current bus voltage (uV).
250
 * @param[in]   i2cd        i2c driver
251
 * @param[in]   inad        ina219 driver
252
 * @param[out]  data        bus voltage
253
 * @param[in]   timeout     timeout
254
 * @return                  An indicator whether the call was successfull
255
 */
256
inline apalExitStatus_t
257
ina219_lld_read_bus_voltage(const INA219Driver* const ina219, uint32_t* const data, const apalTime_t timeout)
258
{
259
  apalDbgAssert(ina219 != NULL);
260
  apalDbgAssert(data != NULL);
261

    
262
  uint16_t buffer = 0;
263
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_BUS_VOLTAGE, &buffer, 1, timeout);
264
  if (buffer & 0x01) {
265
    status = APAL_STATUS_ERROR;
266
  }
267
  *data = (uint32_t)(buffer >> 3) * 4000;
268
  return status;
269
}
270

    
271
/**
272
 * @brief Read the power (uW).
273
 * @param[in]   i2cd        i2c driver
274
 * @param[in]   inad        ina219 driver
275
 * @param[out]  data        power
276
 * @param[in]   timeout     timeout
277
 * @return                  An indicator whether the call was successfull
278
 */
279
inline apalExitStatus_t
280
ina219_lld_read_power(const INA219Driver* const ina219, uint32_t* const data, const apalTime_t timeout)
281
{
282
  apalDbgAssert(ina219 != NULL);
283
  apalDbgAssert(data != NULL);
284

    
285
  uint16_t buffer = 0;
286
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_POWER, &buffer, 1, timeout);
287
  *data = (uint32_t)buffer * 20 * ina219->current_lsb_uA;
288
  return status;
289
}
290

    
291
/**
292
 * @brief Read the current (uA).
293
 * @param[in]   i2cd        i2c driver
294
 * @param[in]   inad        ina219 driver
295
 * @param[out]  data        current
296
 * @param[in]   timeout     timeout
297
 * @return                  An indicator whether the call was successfull
298
 */
299
inline apalExitStatus_t
300
ina219_lld_read_current(const INA219Driver* const ina219, int16_t* const data, const apalTime_t timeout)
301
{
302
  apalDbgAssert(ina219 != NULL);
303
  apalDbgAssert(data != NULL);
304

    
305
  uint16_t buffer = 0;
306
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CURRENT, &buffer, 1, timeout);
307
  *data = ((int16_t) buffer) * ina219->current_lsb_uA;
308
  return status;
309
}
310

    
311
/**
312
 * @brief Read the bus conversion ready flag.
313
 * @param[in]   i2cd        i2c driver
314
 * @param[in]   inad        ina219 driver
315
 * @param[out]  buscnv      conversion ready flag
316
 * @param[in]   timeout     timeout
317
 * @return                  An indicator whether the call was successfull
318
 */
319
inline apalExitStatus_t
320
ina219_lld_bus_conversion_ready(const INA219Driver* const ina219, uint16_t* const buscnv, const apalTime_t timeout)
321
{
322
  apalDbgAssert(ina219 != NULL);
323
  apalDbgAssert(buscnv != NULL);
324

    
325
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_BUS_VOLTAGE, buscnv, 1, timeout);
326
  *buscnv >>= 1;
327
  *buscnv &= 1;
328
  return status;
329
}
330

    
331
#endif /* defined(AMIROLLD_CFG_USE_INA219) */