Statistics
| Branch: | Tag: | Revision:

amiro-lld / drivers / INA219 / v1 / alld_INA219.c @ 9466e34d

History | View | Annotate | Download (13.098 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
/******************************************************************************/
30
/* LOCAL DEFINITIONS                                                          */
31
/******************************************************************************/
32

    
33
/******************************************************************************/
34
/* EXPORTED VARIABLES                                                         */
35
/******************************************************************************/
36

    
37
/******************************************************************************/
38
/* LOCAL TYPES                                                                */
39
/******************************************************************************/
40

    
41
/******************************************************************************/
42
/* LOCAL VARIABLES                                                            */
43
/******************************************************************************/
44

    
45
/******************************************************************************/
46
/* LOCAL FUNCTIONS                                                            */
47
/******************************************************************************/
48

    
49
/******************************************************************************/
50
/* EXPORTED FUNCTIONS                                                         */
51
/******************************************************************************/
52

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

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

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

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

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

    
117
  uint16_t current_lsb_uA = calib_in->current_lsb_uA;
118
  if (current_lsb_uA < calib_in->max_expected_current_A / 0.032768f) {
119
    current_lsb_uA = calib_in->max_expected_current_A / 0.032768f;
120
  } else if (current_lsb_uA > calib_in->max_expected_current_A / 0.004096f) {
121
    current_lsb_uA = calib_in->max_expected_current_A / 0.004096f;
122
  }
123

    
124
  uint16_t calib_value = (uint16_t) (40960 / (current_lsb_uA * calib_in->shunt_resistance_0));
125

    
126
  float V_shunt_max;
127
  switch (calib_in->cfg_reg.options.gain) {
128
    case INA219_LLD_GAIN_1_40mV:
129
        V_shunt_max = 0.04f;
130
        break;
131
    case INA219_LLD_GAIN_2_80mV:
132
        V_shunt_max = 0.08f;
133
        break;
134
    case INA219_LLD_GAIN_4_160mV:
135
        V_shunt_max = 0.16f;
136
        break;
137
    case INA219_LLD_GAIN_8_320mV:
138
        V_shunt_max = 0.32f;
139
        break;
140
  }
141

    
142
  calib_out->max_current_before_overflow_A = (current_lsb_uA * 0.032767f >= V_shunt_max /calib_in->shunt_resistance_0) ?
143
                                                V_shunt_max / calib_in->shunt_resistance_0 :
144
                                                current_lsb_uA * 0.032767f;
145
  calib_out->max_shunt_voltage_before_overflow_V =
146
                                ((calib_out->max_current_before_overflow_A * calib_in->shunt_resistance_0) >= V_shunt_max) ?
147
                                                   V_shunt_max :
148
                                                   calib_out->max_current_before_overflow_A * calib_in->shunt_resistance_0;
149

    
150
  calib_out->current_lsb_uA = current_lsb_uA;
151
  calib_out->calibration = calib_value;
152

    
153
  ina219->current_lsb_uA = current_lsb_uA;
154

    
155
  return APAL_STATUS_SUCCESS;
156
}
157

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

    
171
  return ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &cfg->data, 1, timeout);
172
}
173

    
174
/**
175
 * @brief Write a new configuration.
176
 * @param[in]   i2cd        i2c driver
177
 * @param[in]   inad        ina219 driver
178
 * @param[in]   cfg         new configuration
179
 * @param[in]   timeout     timeout
180
 * @return                  An indicator whether the call was successfull
181
 */
182
apalExitStatus_t ina219_lld_write_config(const INA219Driver* const ina219, ina219_lld_cfg_t cfg, const apalTime_t timeout)
183
{
184
  apalDbgAssert(ina219 != NULL);
185

    
186
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &cfg.data, 1, timeout);
187
}
188

    
189
/**
190
 * @brief Read the current calibration value.
191
 * @param[in]   i2cd        i2c driver
192
 * @param[in]   inad        ina219 driver
193
 * @param[out]  calib       current calibration value
194
 * @param[in]   timeout     timeout
195
 * @return                  An indicator whether the call was successfull
196
 */
197
apalExitStatus_t ina219_lld_read_calibration(const INA219Driver* const ina219, uint16_t* const calib, const apalTime_t timeout)
198
{
199
  apalDbgAssert(ina219 != NULL);
200
  apalDbgAssert(calib != NULL);
201

    
202
  return ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CALIBRATION, calib, 1, timeout);
203
}
204

    
205
/**
206
 * @brief Write a new calibration value.
207
 * @param[in]   i2cd        i2c driver
208
 * @param[in]   inad        ina219 driver
209
 * @param[in]   calib       new calibration value
210
 * @param[in]   timeout     timeout
211
 * @return                  An indicator whether the call was successfull
212
 */
213
apalExitStatus_t ina219_lld_write_calibration(const INA219Driver* const ina219, const uint16_t calib, const apalTime_t timeout)
214
{
215
  apalDbgAssert(ina219 != NULL);
216

    
217
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CALIBRATION, &calib, 1, timeout);
218
}
219

    
220
/**
221
 * @brief Reset the ina219.
222
 * @param[in]   i2cd        i2c driver
223
 * @param[in]   inad        ina219 driver
224
 * @param[in]   timeout     timeout
225
 * @return                  An indicator whether the call was successfull
226
 */
227
apalExitStatus_t ina219_lld_reset(const INA219Driver* const ina219, const apalTime_t timeout)
228
{
229
  apalDbgAssert(ina219 != NULL);
230

    
231
  uint16_t data = 0x8000;
232
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &data, 1, timeout);
233
}
234

    
235
/**
236
 * @brief Read the current shunt voltage (uV).
237
 * @param[in]   i2cd        i2c driver
238
 * @param[in]   inad        ina219 driver
239
 * @param[out]  data        shunt voltage
240
 * @param[in]   timeout     timeout
241
 * @return                  An indicator whether the call was successfull
242
 */
243
apalExitStatus_t ina219_lld_read_shunt_voltage(const INA219Driver* const ina219, int32_t* const data, const apalTime_t timeout)
244
{
245
  apalDbgAssert(ina219 != NULL);
246
  apalDbgAssert(data != NULL);
247

    
248
  uint16_t buffer = 0;
249
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_SHUNT_VOLTAGE, &buffer, 1, timeout);
250

    
251
  switch (ina219->config->options.gain) {
252
    case INA219_LLD_GAIN_8_320mV:
253
      *data = (int32_t)(buffer & 0x7FFFu) * ((buffer & 0x8000u) ? -10 : 10);
254
      break;
255
    case INA219_LLD_GAIN_4_160mV:
256
      *data = (int32_t)(buffer & 0x3FFFu) * ((buffer & 0xC000u) ? -10 : 10);
257
      break;
258
    case INA219_LLD_GAIN_2_80mV:
259
      *data = (int32_t)(buffer & 0x1FFFu) * ((buffer & 0xE000u) ? -10 : 10);
260
      break;
261
    case INA219_LLD_GAIN_1_40mV:
262
      *data = (int32_t)(buffer & 0x0FFFu) * ((buffer & 0xF000u) ? -10 : 10);
263
      break;
264
  }
265

    
266
  return status;
267
}
268

    
269
/**
270
 * @brief Read the current bus voltage (uV).
271
 * @param[in]   i2cd        i2c driver
272
 * @param[in]   inad        ina219 driver
273
 * @param[out]  data        bus voltage
274
 * @param[in]   timeout     timeout
275
 * @return                  An indicator whether the call was successfull
276
 */
277
apalExitStatus_t ina219_lld_read_bus_voltage(const INA219Driver* const ina219, uint32_t* const data, const apalTime_t timeout)
278
{
279
  apalDbgAssert(ina219 != NULL);
280
  apalDbgAssert(data != NULL);
281

    
282
  uint16_t buffer = 0;
283
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_BUS_VOLTAGE, &buffer, 1, timeout);
284
  if (buffer & 0x01) {
285
    status = APAL_STATUS_ERROR;
286
  }
287
  *data = (uint32_t)(buffer >> 3) * 4000;
288
  return status;
289
}
290

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

    
304
  uint16_t buffer = 0;
305
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_POWER, &buffer, 1, timeout);
306
  *data = (uint32_t)buffer * 20 * ina219->current_lsb_uA;
307
  return status;
308
}
309

    
310
/**
311
 * @brief Read the current (uA).
312
 * @param[in]   i2cd        i2c driver
313
 * @param[in]   inad        ina219 driver
314
 * @param[out]  data        current
315
 * @param[in]   timeout     timeout
316
 * @return                  An indicator whether the call was successfull
317
 */
318
apalExitStatus_t ina219_lld_read_current(const INA219Driver* const ina219, int16_t* const data, const apalTime_t timeout)
319
{
320
  apalDbgAssert(ina219 != NULL);
321
  apalDbgAssert(data != NULL);
322

    
323
  uint16_t buffer = 0;
324
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CURRENT, &buffer, 1, timeout);
325
  *data = ((int16_t) buffer) * ina219->current_lsb_uA;
326
  return status;
327
}
328

    
329
/**
330
 * @brief Read the bus conversion ready flag.
331
 * @param[in]   i2cd        i2c driver
332
 * @param[in]   inad        ina219 driver
333
 * @param[out]  buscnv      conversion ready flag
334
 * @param[in]   timeout     timeout
335
 * @return                  An indicator whether the call was successfull
336
 */
337
apalExitStatus_t ina219_lld_bus_conversion_ready(const INA219Driver* const ina219, uint16_t* const buscnv, const apalTime_t timeout)
338
{
339
  apalDbgAssert(ina219 != NULL);
340
  apalDbgAssert(buscnv != NULL);
341

    
342
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_BUS_VOLTAGE, buscnv, 1, timeout);
343
  *buscnv >>= 1;
344
  *buscnv &= 1;
345
  return status;
346
}
347

    
348
/** @} */
349