Statistics
| Branch: | Tag: | Revision:

amiro-lld / source / alld_ina219.c @ ef078306

History | View | Annotate | Download (13.3 KB)

1
/*
2
AMiRo-LLD is a compilation of low-level hardware drivers for the Autonomous Mini Robot (AMiRo) platform.
3
Copyright (C) 2016..2019  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 Lesser 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 Lesser General Public License for more details.
14

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

    
19
/**
20
 * @file    alld_ina219.c
21
 * @brief   Power Monitor function implementations
22
 *
23
 * @addtogroup lld_power
24
 * @{
25
 */
26

    
27
#include <alld_ina219.h>
28

    
29
#if defined(AMIROLLD_CFG_USE_INA219) || defined(__DOXYGEN__)
30

    
31
/******************************************************************************/
32
/* LOCAL DEFINITIONS                                                          */
33
/******************************************************************************/
34

    
35
/******************************************************************************/
36
/* EXPORTED VARIABLES                                                         */
37
/******************************************************************************/
38

    
39
/******************************************************************************/
40
/* LOCAL TYPES                                                                */
41
/******************************************************************************/
42

    
43
/******************************************************************************/
44
/* LOCAL VARIABLES                                                            */
45
/******************************************************************************/
46

    
47
/******************************************************************************/
48
/* LOCAL FUNCTIONS                                                            */
49
/******************************************************************************/
50

    
51
/******************************************************************************/
52
/* EXPORTED FUNCTIONS                                                         */
53
/******************************************************************************/
54

    
55
/**
56
 * @brief Read the value of one or more of the registers.
57
 * @param[in]   i2cd        i2c driver
58
 * @param[in]   inad        ina219 driver
59
 * @param[in]   addr        register address
60
 * @param[out]  data        register content
61
 * @param[in]   num         number of subsequent registers to read
62
 * @param[in]   timeout     timeout
63
 * @return                  An indicator whether the call was successfull
64
 */
65
inline apalExitStatus_t
66
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)
67
{
68
  apalDbgAssert(ina219 != NULL);
69
  apalDbgAssert(ina219->i2cd != NULL);
70
  apalDbgAssert(data != NULL);
71

    
72
  uint8_t buffer[num*2];
73
  apalExitStatus_t status = apalI2CMasterTransmit(ina219->i2cd, (INA219_LLD_I2C_ADDR_FIXED | ina219->addr), (uint8_t*)&addr, 1, buffer, 2*num, timeout);
74
  for (uint8_t dataIdx = 0; dataIdx < num; dataIdx++) {
75
    data[dataIdx] = (buffer[2*dataIdx] << 8) | buffer[2*dataIdx+1];
76
  }
77
  return status;
78
}
79

    
80
/**
81
 * @brief Write the value of one or more of the registers.
82
 * @param[in]   i2cd        i2c driver
83
 * @param[in]   inad        ina219 driver
84
 * @param[in]   addr        register address
85
 * @param[in]   data        data to write
86
 * @param[in]   num         number of subsequent registers to read
87
 * @param[in]   timeout     timeout
88
 * @return                  An indicator whether the call was successfull
89
 */
90
inline apalExitStatus_t
91
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)
92
{
93
  apalDbgAssert(ina219 != NULL);
94
  apalDbgAssert(ina219->i2cd != NULL);
95
  apalDbgAssert(data != NULL);
96

    
97
  uint8_t buffer[1+2*num];
98
  buffer[0] = addr;
99
  for (uint8_t dataIdx = 0; dataIdx < num; dataIdx++) {
100
    buffer[dataIdx*2+1] = data[dataIdx] >> 8;
101
    buffer[dataIdx*2+2] = data[dataIdx] & (0x00FFu);
102
  }
103
  return apalI2CMasterTransmit(ina219->i2cd, (INA219_LLD_I2C_ADDR_FIXED | ina219->addr), buffer, 1+2*num, NULL, 0, timeout);
104
}
105

    
106
/**
107
 * @brief Calibrate the ina219.
108
 * @param[in]   i2cd        i2c driver
109
 * @param[in]   inad        APAL_STATUS_SUCCESS;
110
 * @param[in]   calib_in    calibration input data
111
 * @param[out]  calib_out   output of the calibration
112
 * @param[in]   timeout     timeout
113
 * @return                  An indicator whether the call was successfull
114
 */
115
inline apalExitStatus_t
116
ina219_lld_calibration(INA219Driver* const ina219, const ina219_lld_calib_input_t* const calib_in, ina219_lld_calib_output_t* const calib_out)
117
{
118
  apalDbgAssert(ina219 != NULL);
119
  apalDbgAssert(calib_in != NULL);
120
  apalDbgAssert(calib_out != NULL);
121

    
122
  uint16_t current_lsb_uA = calib_in->current_lsb_uA;
123
  if (current_lsb_uA < calib_in->max_expected_current_A / 0.032768f) {
124
    current_lsb_uA = calib_in->max_expected_current_A / 0.032768f;
125
  } else if (current_lsb_uA > calib_in->max_expected_current_A / 0.004096f) {
126
    current_lsb_uA = calib_in->max_expected_current_A / 0.004096f;
127
  }
128

    
129
  uint16_t calib_value = (uint16_t) (40960 / (current_lsb_uA * calib_in->shunt_resistance_0));
130

    
131
  float V_shunt_max;
132
  switch (calib_in->cfg_reg.options.gain) {
133
    case INA219_LLD_GAIN_1_40mV:
134
        V_shunt_max = 0.04f;
135
        break;
136
    case INA219_LLD_GAIN_2_80mV:
137
        V_shunt_max = 0.08f;
138
        break;
139
    case INA219_LLD_GAIN_4_160mV:
140
        V_shunt_max = 0.16f;
141
        break;
142
    case INA219_LLD_GAIN_8_320mV:
143
        V_shunt_max = 0.32f;
144
        break;
145
  }
146

    
147
  calib_out->max_current_before_overflow_A = (current_lsb_uA * 0.032767f >= V_shunt_max /calib_in->shunt_resistance_0) ?
148
                                                V_shunt_max / calib_in->shunt_resistance_0 :
149
                                                current_lsb_uA * 0.032767f;
150
  calib_out->max_shunt_voltage_before_overflow_V =
151
                                ((calib_out->max_current_before_overflow_A * calib_in->shunt_resistance_0) >= V_shunt_max) ?
152
                                                   V_shunt_max :
153
                                                   calib_out->max_current_before_overflow_A * calib_in->shunt_resistance_0;
154

    
155
  calib_out->current_lsb_uA = current_lsb_uA;
156
  calib_out->calibration = calib_value;
157

    
158
  ina219->current_lsb_uA = current_lsb_uA;
159

    
160
  return APAL_STATUS_SUCCESS;
161
}
162

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

    
177
  return ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &cfg->data, 1, timeout);
178
}
179

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

    
193
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &cfg.data, 1, timeout);
194
}
195

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

    
210
  return ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CALIBRATION, calib, 1, timeout);
211
}
212

    
213
/**
214
 * @brief Write a new calibration value.
215
 * @param[in]   i2cd        i2c driver
216
 * @param[in]   inad        ina219 driver
217
 * @param[in]   calib       new calibration value
218
 * @param[in]   timeout     timeout
219
 * @return                  An indicator whether the call was successfull
220
 */
221
inline apalExitStatus_t
222
ina219_lld_write_calibration(const INA219Driver* const ina219, const uint16_t calib, const apalTime_t timeout)
223
{
224
  apalDbgAssert(ina219 != NULL);
225

    
226
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CALIBRATION, &calib, 1, timeout);
227
}
228

    
229
/**
230
 * @brief Reset the ina219.
231
 * @param[in]   i2cd        i2c driver
232
 * @param[in]   inad        ina219 driver
233
 * @param[in]   timeout     timeout
234
 * @return                  An indicator whether the call was successfull
235
 */
236
inline apalExitStatus_t
237
ina219_lld_reset(const INA219Driver* const ina219, const apalTime_t timeout)
238
{
239
  apalDbgAssert(ina219 != NULL);
240

    
241
  uint16_t data = 0x8000;
242
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &data, 1, timeout);
243
}
244

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

    
259
  uint16_t buffer = 0;
260
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_SHUNT_VOLTAGE, &buffer, 1, timeout);
261

    
262
  switch (ina219->config->options.gain) {
263
    case INA219_LLD_GAIN_8_320mV:
264
      *data = (int32_t)(buffer & 0x7FFFu) * ((buffer & 0x8000u) ? -10 : 10);
265
      break;
266
    case INA219_LLD_GAIN_4_160mV:
267
      *data = (int32_t)(buffer & 0x3FFFu) * ((buffer & 0xC000u) ? -10 : 10);
268
      break;
269
    case INA219_LLD_GAIN_2_80mV:
270
      *data = (int32_t)(buffer & 0x1FFFu) * ((buffer & 0xE000u) ? -10 : 10);
271
      break;
272
    case INA219_LLD_GAIN_1_40mV:
273
      *data = (int32_t)(buffer & 0x0FFFu) * ((buffer & 0xF000u) ? -10 : 10);
274
      break;
275
  }
276

    
277
  return status;
278
}
279

    
280
/**
281
 * @brief Read the current bus voltage (uV).
282
 * @param[in]   i2cd        i2c driver
283
 * @param[in]   inad        ina219 driver
284
 * @param[out]  data        bus voltage
285
 * @param[in]   timeout     timeout
286
 * @return                  An indicator whether the call was successfull
287
 */
288
inline apalExitStatus_t
289
ina219_lld_read_bus_voltage(const INA219Driver* const ina219, uint32_t* const data, const apalTime_t timeout)
290
{
291
  apalDbgAssert(ina219 != NULL);
292
  apalDbgAssert(data != NULL);
293

    
294
  uint16_t buffer = 0;
295
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_BUS_VOLTAGE, &buffer, 1, timeout);
296
  if (buffer & 0x01) {
297
    status = APAL_STATUS_ERROR;
298
  }
299
  *data = (uint32_t)(buffer >> 3) * 4000;
300
  return status;
301
}
302

    
303
/**
304
 * @brief Read the power (uW).
305
 * @param[in]   i2cd        i2c driver
306
 * @param[in]   inad        ina219 driver
307
 * @param[out]  data        power
308
 * @param[in]   timeout     timeout
309
 * @return                  An indicator whether the call was successfull
310
 */
311
inline apalExitStatus_t
312
ina219_lld_read_power(const INA219Driver* const ina219, uint32_t* const data, const apalTime_t timeout)
313
{
314
  apalDbgAssert(ina219 != NULL);
315
  apalDbgAssert(data != NULL);
316

    
317
  uint16_t buffer = 0;
318
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_POWER, &buffer, 1, timeout);
319
  *data = (uint32_t)buffer * 20 * ina219->current_lsb_uA;
320
  return status;
321
}
322

    
323
/**
324
 * @brief Read the current (uA).
325
 * @param[in]   i2cd        i2c driver
326
 * @param[in]   inad        ina219 driver
327
 * @param[out]  data        current
328
 * @param[in]   timeout     timeout
329
 * @return                  An indicator whether the call was successfull
330
 */
331
inline apalExitStatus_t
332
ina219_lld_read_current(const INA219Driver* const ina219, int16_t* const data, const apalTime_t timeout)
333
{
334
  apalDbgAssert(ina219 != NULL);
335
  apalDbgAssert(data != NULL);
336

    
337
  uint16_t buffer = 0;
338
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CURRENT, &buffer, 1, timeout);
339
  *data = ((int16_t) buffer) * ina219->current_lsb_uA;
340
  return status;
341
}
342

    
343
/**
344
 * @brief Read the bus conversion ready flag.
345
 * @param[in]   i2cd        i2c driver
346
 * @param[in]   inad        ina219 driver
347
 * @param[out]  buscnv      conversion ready flag
348
 * @param[in]   timeout     timeout
349
 * @return                  An indicator whether the call was successfull
350
 */
351
inline apalExitStatus_t
352
ina219_lld_bus_conversion_ready(const INA219Driver* const ina219, uint16_t* const buscnv, const apalTime_t timeout)
353
{
354
  apalDbgAssert(ina219 != NULL);
355
  apalDbgAssert(buscnv != NULL);
356

    
357
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_BUS_VOLTAGE, buscnv, 1, timeout);
358
  *buscnv >>= 1;
359
  *buscnv &= 1;
360
  return status;
361
}
362

    
363
#endif /* defined(AMIROLLD_CFG_USE_INA219) */
364

    
365
/** @} */