Statistics
| Branch: | Tag: | Revision:

amiro-lld / source / alld_ina219.c @ f125ae07

History | View | Annotate | Download (11.862 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
 * @brief Read the value of one or more of the registers.
33
 * @param[in]   i2cd        i2c driver
34
 * @param[in]   inad        ina219 driver
35
 * @param[in]   addr        register address
36
 * @param[out]  data        register content
37
 * @param[in]   num         number of subsequent registers to read
38
 * @param[in]   timeout     timeout
39
 * @return                  An indicator whether the call was successfull
40
 */
41
inline apalExitStatus_t
42
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)
43
{
44
  apalDbgAssert(ina219 != NULL);
45
  apalDbgAssert(ina219->i2cd != NULL);
46
  apalDbgAssert(data != NULL);
47

    
48
  uint8_t buffer[num*2];
49
  apalExitStatus_t status = apalI2CMasterTransmit(ina219->i2cd, (INA219_LLD_I2C_ADDR_FIXED | ina219->addr), (uint8_t*)&addr, 1, buffer, 2*num, timeout);
50
  for (uint8_t dataIdx = 0; dataIdx < num; dataIdx++) {
51
    data[dataIdx] = (buffer[2*dataIdx] << 8) | buffer[2*dataIdx+1];
52
  }
53
  return status;
54
}
55

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

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

    
82
/**
83
 * @brief Calibrate the ina219.
84
 * @param[in]   i2cd        i2c driver
85
 * @param[in]   inad        APAL_STATUS_SUCCESS;
86
 * @param[in]   calib_in    calibration input data
87
 * @param[out]  calib_out   output of the calibration
88
 * @param[in]   timeout     timeout
89
 * @return                  An indicator whether the call was successfull
90
 */
91
inline apalExitStatus_t
92
ina219_lld_calibration(INA219Driver* const ina219, const ina219_lld_calib_input_t* const calib_in, ina219_lld_calib_output_t* const calib_out)
93
{
94
  apalDbgAssert(ina219 != NULL);
95
  apalDbgAssert(calib_in != NULL);
96
  apalDbgAssert(calib_out != NULL);
97

    
98
  uint16_t current_lsb_uA = calib_in->current_lsb_uA;
99
  if (current_lsb_uA < calib_in->max_expected_current_A / 0.032768f) {
100
    current_lsb_uA = calib_in->max_expected_current_A / 0.032768f;
101
  } else if (current_lsb_uA > calib_in->max_expected_current_A / 0.004096f) {
102
    current_lsb_uA = calib_in->max_expected_current_A / 0.004096f;
103
  }
104

    
105
  uint16_t calib_value = (uint16_t) (40960 / (current_lsb_uA * calib_in->shunt_resistance_0));
106

    
107
  float V_shunt_max;
108
  switch (calib_in->cfg_reg.options.gain) {
109
    case INA219_LLD_GAIN_1_40mV:
110
        V_shunt_max = 0.04f;
111
        break;
112
    case INA219_LLD_GAIN_2_80mV:
113
        V_shunt_max = 0.08f;
114
        break;
115
    case INA219_LLD_GAIN_4_160mV:
116
        V_shunt_max = 0.16f;
117
        break;
118
    case INA219_LLD_GAIN_8_320mV:
119
        V_shunt_max = 0.32f;
120
        break;
121
  }
122

    
123
  calib_out->max_current_before_overflow_A = (current_lsb_uA * 0.032767f >= V_shunt_max /calib_in->shunt_resistance_0) ?
124
                                                V_shunt_max / calib_in->shunt_resistance_0 :
125
                                                current_lsb_uA * 0.032767f;
126
  calib_out->max_shunt_voltage_before_overflow_V =
127
                                ((calib_out->max_current_before_overflow_A * calib_in->shunt_resistance_0) >= V_shunt_max) ?
128
                                                   V_shunt_max :
129
                                                   calib_out->max_current_before_overflow_A * calib_in->shunt_resistance_0;
130

    
131
  calib_out->current_lsb_uA = current_lsb_uA;
132
  calib_out->calibration = calib_value;
133

    
134
  ina219->current_lsb_uA = current_lsb_uA;
135

    
136
  return APAL_STATUS_SUCCESS;
137
}
138

    
139
/**
140
 * @brief Read the current configuration.
141
 * @param[in]   i2cd        i2c driver
142
 * @param[in]   inad        ina219 driver
143
 * @param[out]  cfg         current configuration
144
 * @param[in]   timeout     timeout
145
 * @return                  An indicator whether the call was successfull
146
 */
147
inline apalExitStatus_t
148
ina219_lld_read_config(const INA219Driver* const ina219, ina219_lld_cfg_t* const cfg, const apalTime_t timeout)
149
{
150
  apalDbgAssert(ina219 != NULL);
151
  apalDbgAssert(cfg != NULL);
152

    
153
  return ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &cfg->data, 1, timeout);
154
}
155

    
156
/**
157
 * @brief Write a new configuration.
158
 * @param[in]   i2cd        i2c driver
159
 * @param[in]   inad        ina219 driver
160
 * @param[in]   cfg         new configuration
161
 * @param[in]   timeout     timeout
162
 * @return                  An indicator whether the call was successfull
163
 */
164
inline apalExitStatus_t
165
ina219_lld_write_config(const INA219Driver* const ina219, ina219_lld_cfg_t cfg, const apalTime_t timeout)
166
{
167
  apalDbgAssert(ina219 != NULL);
168

    
169
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &cfg.data, 1, timeout);
170
}
171

    
172
/**
173
 * @brief Read the current calibration value.
174
 * @param[in]   i2cd        i2c driver
175
 * @param[in]   inad        ina219 driver
176
 * @param[out]  calib       current calibration value
177
 * @param[in]   timeout     timeout
178
 * @return                  An indicator whether the call was successfull
179
 */
180
inline apalExitStatus_t
181
ina219_lld_read_calibration(const INA219Driver* const ina219, uint16_t* const calib, const apalTime_t timeout)
182
{
183
  apalDbgAssert(ina219 != NULL);
184
  apalDbgAssert(calib != NULL);
185

    
186
  return ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CALIBRATION, calib, 1, timeout);
187
}
188

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

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

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

    
217
  uint16_t data = 0x8000;
218
  return ina219_lld_write_register(ina219, INA219_LLD_REGISTER_CONFIGURATION, &data, 1, timeout);
219
}
220

    
221
/**
222
 * @brief Read the current shunt voltage (uV).
223
 * @param[in]   i2cd        i2c driver
224
 * @param[in]   inad        ina219 driver
225
 * @param[out]  data        shunt voltage
226
 * @param[in]   timeout     timeout
227
 * @return                  An indicator whether the call was successfull
228
 */
229
inline apalExitStatus_t
230
ina219_lld_read_shunt_voltage(const INA219Driver* const ina219, int32_t* const data, const apalTime_t timeout)
231
{
232
  apalDbgAssert(ina219 != NULL);
233
  apalDbgAssert(data != NULL);
234

    
235
  uint16_t buffer = 0;
236
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_SHUNT_VOLTAGE, &buffer, 1, timeout);
237

    
238
  switch (ina219->config->options.gain) {
239
    case INA219_LLD_GAIN_8_320mV:
240
      *data = (int32_t)(buffer & 0x7FFFu) * ((buffer & 0x8000u) ? -10 : 10);
241
      break;
242
    case INA219_LLD_GAIN_4_160mV:
243
      *data = (int32_t)(buffer & 0x3FFFu) * ((buffer & 0xC000u) ? -10 : 10);
244
      break;
245
    case INA219_LLD_GAIN_2_80mV:
246
      *data = (int32_t)(buffer & 0x1FFFu) * ((buffer & 0xE000u) ? -10 : 10);
247
      break;
248
    case INA219_LLD_GAIN_1_40mV:
249
      *data = (int32_t)(buffer & 0x0FFFu) * ((buffer & 0xF000u) ? -10 : 10);
250
      break;
251
  }
252

    
253
  return status;
254
}
255

    
256
/**
257
 * @brief Read the current bus voltage (uV).
258
 * @param[in]   i2cd        i2c driver
259
 * @param[in]   inad        ina219 driver
260
 * @param[out]  data        bus voltage
261
 * @param[in]   timeout     timeout
262
 * @return                  An indicator whether the call was successfull
263
 */
264
inline apalExitStatus_t
265
ina219_lld_read_bus_voltage(const INA219Driver* const ina219, uint32_t* const data, const apalTime_t timeout)
266
{
267
  apalDbgAssert(ina219 != NULL);
268
  apalDbgAssert(data != NULL);
269

    
270
  uint16_t buffer = 0;
271
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_BUS_VOLTAGE, &buffer, 1, timeout);
272
  if (buffer & 0x01) {
273
    status = APAL_STATUS_ERROR;
274
  }
275
  *data = (uint32_t)(buffer >> 3) * 4000;
276
  return status;
277
}
278

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

    
293
  uint16_t buffer = 0;
294
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_POWER, &buffer, 1, timeout);
295
  *data = (uint32_t)buffer * 20 * ina219->current_lsb_uA;
296
  return status;
297
}
298

    
299
/**
300
 * @brief Read the current (uA).
301
 * @param[in]   i2cd        i2c driver
302
 * @param[in]   inad        ina219 driver
303
 * @param[out]  data        current
304
 * @param[in]   timeout     timeout
305
 * @return                  An indicator whether the call was successfull
306
 */
307
inline apalExitStatus_t
308
ina219_lld_read_current(const INA219Driver* const ina219, int16_t* const data, const apalTime_t timeout)
309
{
310
  apalDbgAssert(ina219 != NULL);
311
  apalDbgAssert(data != NULL);
312

    
313
  uint16_t buffer = 0;
314
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_CURRENT, &buffer, 1, timeout);
315
  *data = ((int16_t) buffer) * ina219->current_lsb_uA;
316
  return status;
317
}
318

    
319
/**
320
 * @brief Read the bus conversion ready flag.
321
 * @param[in]   i2cd        i2c driver
322
 * @param[in]   inad        ina219 driver
323
 * @param[out]  buscnv      conversion ready flag
324
 * @param[in]   timeout     timeout
325
 * @return                  An indicator whether the call was successfull
326
 */
327
inline apalExitStatus_t
328
ina219_lld_bus_conversion_ready(const INA219Driver* const ina219, uint16_t* const buscnv, const apalTime_t timeout)
329
{
330
  apalDbgAssert(ina219 != NULL);
331
  apalDbgAssert(buscnv != NULL);
332

    
333
  apalExitStatus_t status = ina219_lld_read_register(ina219, INA219_LLD_REGISTER_BUS_VOLTAGE, buscnv, 1, timeout);
334
  *buscnv >>= 1;
335
  *buscnv &= 1;
336
  return status;
337
}
338

    
339
#endif /* defined(AMIROLLD_CFG_USE_INA219) */
340

    
341
/** @} */