New drivers
[hackover2013-badge-firmware.git] / drivers / sensors / ina219 / ina219.c
1 /**************************************************************************/
2 /*!
3 @file ina219.c
4 @author K. Townsend (microBuilder.eu)
5
6 @brief Driver for the TI INA219 current/power monitor
7
8 @section DESCRIPTION
9
10 The INA219 is an I2C-based current/power monitor that monitors the
11 voltage drop across a shunt resistor, as well as the supply voltage.
12
13 @section EXAMPLE
14 @code
15 ina219Init();
16
17 int16_t current = 0;
18 int16_t power = 0;
19 int16_t current_mA = 0;
20 int16_t power_mW = 0;
21 int16_t busvoltage = 0;
22 int16_t shuntvoltage = 0;
23 int16_t loadVoltage = 0;
24
25 while(1)
26 {
27 shuntvoltage = ina219GetShuntVoltage();
28 busvoltage = ina219GetBusVoltage();
29 power = ina219GetPower();
30 current = ina219GetCurrent();
31 power_mW = ina219GetPower_mW();
32 current_mA = ina219GetCurrent_mA();
33 loadVoltage = busvoltage + (shuntvoltage / 100);
34 printf("%-15s %6d = %d.%dmV (%duV) \r\n", "Shunt Voltage:", shuntvoltage, shuntvoltage / 100, shuntvoltage % 100, shuntvoltage * 10);
35 printf("%-15s %6d = %d.%dV \r\n", "Bus Voltage:", busvoltage, busvoltage / 1000, busvoltage % 1000);
36 printf("%-15s %6d = %d.%dV \r\n", "Load Voltage:", loadVoltage, loadVoltage / 1000, loadVoltage % 1000);
37 printf("%-15s %6d = %dmW \r\n", "Power:", power, power_mW);
38 printf("%-15s %6d = %dmA \r\n", "Current:", current, current_mA);
39 printf("\r\n");
40 systickDelay(5000);
41 }
42 @endcode
43
44 @section LICENSE
45
46 Software License Agreement (BSD License)
47
48 Copyright (c) 2012 Kevin Townsend
49 All rights reserved.
50
51 Redistribution and use in source and binary forms, with or without
52 modification, are permitted provided that the following conditions are met:
53 1. Redistributions of source code must retain the above copyright
54 notice, this list of conditions and the following disclaimer.
55 2. Redistributions in binary form must reproduce the above copyright
56 notice, this list of conditions and the following disclaimer in the
57 documentation and/or other materials provided with the distribution.
58 3. Neither the name of the copyright holders nor the
59 names of its contributors may be used to endorse or promote products
60 derived from this software without specific prior written permission.
61
62 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
63 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
64 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
65 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
66 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
67 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
68 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
69 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
70 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
71 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72 */
73 /**************************************************************************/
74 #include "ina219.h"
75 #include "core/systick/systick.h"
76
77 extern volatile uint8_t I2CMasterBuffer[I2C_BUFSIZE];
78 extern volatile uint8_t I2CSlaveBuffer[I2C_BUFSIZE];
79
80 // The following multipliers are used to convert raw current and power
81 // values to mA and mW, taking into account the current config settings
82 uint32_t ina219_currentDivider_mA = 0;
83 uint32_t ina219_powerDivider_mW = 0;
84
85 /**************************************************************************/
86 /*!
87 @brief Sends a single command byte over I2C
88 */
89 /**************************************************************************/
90 static void ina219WriteRegister (uint8_t reg, uint16_t value)
91 {
92 // Clear write buffers
93 uint32_t i;
94 for ( i = 0; i < I2C_BUFSIZE; i++ )
95 {
96 I2CMasterBuffer[i] = 0x00;
97 }
98
99 I2CWriteLength = 4;
100 I2CReadLength = 0;
101 I2CMasterBuffer[0] = INA219_ADDRESS; // I2C device address
102 I2CMasterBuffer[1] = reg; // Register
103 I2CMasterBuffer[2] = value >> 8; // Upper 8-bits
104 I2CMasterBuffer[3] = value & 0xFF; // Lower 8-bits
105 i2cEngine();
106 }
107
108 /**************************************************************************/
109 /*!
110 @brief Reads a 16 bit values over I2C
111 */
112 /**************************************************************************/
113 static void ina219Read16(uint8_t reg, uint16_t *value)
114 {
115 // Clear write buffers
116 uint32_t i;
117 for ( i = 0; i < I2C_BUFSIZE; i++ )
118 {
119 I2CMasterBuffer[i] = 0x00;
120 }
121
122 I2CWriteLength = 2;
123 I2CReadLength = 2;
124 I2CMasterBuffer[0] = INA219_ADDRESS; // I2C device address
125 I2CMasterBuffer[1] = reg; // Command register
126 // Append address w/read bit
127 I2CMasterBuffer[2] = INA219_ADDRESS | INA219_READ;
128 i2cEngine();
129
130 // Shift values to create properly formed integer
131 *value = ((I2CSlaveBuffer[0] << 8) | I2CSlaveBuffer[1]);
132 }
133
134 /**************************************************************************/
135 /*!
136 @brief Configures to INA219 to be able to measure up to 32V and 2A
137 of current. Each unit of current corresponds to 100uA, and
138 each unit of power corresponds to 2mW. Counter overflow
139 occurs at 3.2A.
140
141 @note These calculations assume a 0.1 ohm resistor is present
142 */
143 /**************************************************************************/
144 static void ina219SetCalibration_32V_2A(void)
145 {
146 // By default we use a pretty huge range for the input voltage,
147 // which probably isn't the most appropriate choice for system
148 // that don't use a lot of power. But all of the calculations
149 // are shown below if you want to change the settings. You will
150 // also need to change any relevant register settings, such as
151 // setting the VBUS_MAX to 16V instead of 32V, etc.
152
153 // VBUS_MAX = 32V (Assumes 32V, can also be set to 16V)
154 // VSHUNT_MAX = 0.32 (Assumes Gain 8, 320mV, can also be 0.16, 0.08, 0.04)
155 // RSHUNT = 0.1 (Resistor value in ohms)
156
157 // 1. Determine max possible current
158 // MaxPossible_I = VSHUNT_MAX / RSHUNT
159 // MaxPossible_I = 3.2A
160
161 // 2. Determine max expected current
162 // MaxExpected_I = 2.0A
163
164 // 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
165 // MinimumLSB = MaxExpected_I/32767
166 // MinimumLSB = 0.000061 (61µA per bit)
167 // MaximumLSB = MaxExpected_I/4096
168 // MaximumLSB = 0,000488 (488µA per bit)
169
170 // 4. Choose an LSB between the min and max values
171 // (Preferrably a roundish number close to MinLSB)
172 // CurrentLSB = 0.0001 (100µA per bit)
173
174 // 5. Compute the calibration register
175 // Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
176 // Cal = 4096 (0x1000)
177
178 // 6. Calculate the power LSB
179 // PowerLSB = 20 * CurrentLSB
180 // PowerLSB = 0.002 (2mW per bit)
181
182 // 7. Compute the maximum current and shunt voltage values before overflow
183 //
184 // Max_Current = Current_LSB * 32767
185 // Max_Current = 3.2767A before overflow
186 //
187 // If Max_Current > Max_Possible_I then
188 // Max_Current_Before_Overflow = MaxPossible_I
189 // Else
190 // Max_Current_Before_Overflow = Max_Current
191 // End If
192 //
193 // Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
194 // Max_ShuntVoltage = 0.32V
195 //
196 // If Max_ShuntVoltage >= VSHUNT_MAX
197 // Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
198 // Else
199 // Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
200 // End If
201
202 // 8. Computer the Maximum Power
203 // MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
204 // MaximumPower = 3.2 * 32V
205 // MaximumPower = 102.4W
206
207 // Set multipliers to convert raw current/power values
208 ina219_currentDivider_mA = 10; // Current LSB = 100uA per bit (1000/100 = 10)
209 ina219_powerDivider_mW = 2; // Power LSB = 1mW per bit (2/1)
210
211 // Set Calibration register to 'Cal' calculated above
212 ina219WriteRegister(INA219_REG_CALIBRATION, 0x1000);
213
214 // Set Config register to take into account the settings above
215 uint16_t config = INA219_CONFIG_BVOLTAGERANGE_32V |
216 INA219_CONFIG_GAIN_8_320MV |
217 INA219_CONFIG_BADCRES_12BIT |
218 INA219_CONFIG_SADCRES_12BIT_1S_532US |
219 INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;
220 ina219WriteRegister(INA219_REG_CONFIG, config);
221 }
222
223 /**************************************************************************/
224 /*!
225 @brief Configures to INA219 to be able to measure up to 32V and 1A
226 of current. Each unit of current corresponds to 40uA, and each
227 unit of power corresponds to 800µW. Counter overflow occurs at
228 1.3A.
229
230 @note These calculations assume a 0.1 ohm resistor is present
231 */
232 /**************************************************************************/
233 static void ina219SetCalibration_32V_1A(void)
234 {
235 // By default we use a pretty huge range for the input voltage,
236 // which probably isn't the most appropriate choice for system
237 // that don't use a lot of power. But all of the calculations
238 // are shown below if you want to change the settings. You will
239 // also need to change any relevant register settings, such as
240 // setting the VBUS_MAX to 16V instead of 32V, etc.
241
242 // VBUS_MAX = 32V (Assumes 32V, can also be set to 16V)
243 // VSHUNT_MAX = 0.32 (Assumes Gain 8, 320mV, can also be 0.16, 0.08, 0.04)
244 // RSHUNT = 0.1 (Resistor value in ohms)
245
246 // 1. Determine max possible current
247 // MaxPossible_I = VSHUNT_MAX / RSHUNT
248 // MaxPossible_I = 3.2A
249
250 // 2. Determine max expected current
251 // MaxExpected_I = 1.0A
252
253 // 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
254 // MinimumLSB = MaxExpected_I/32767
255 // MinimumLSB = 0.0000305 (30.5µA per bit)
256 // MaximumLSB = MaxExpected_I/4096
257 // MaximumLSB = 0.000244 (244µA per bit)
258
259 // 4. Choose an LSB between the min and max values
260 // (Preferrably a roundish number close to MinLSB)
261 // CurrentLSB = 0.0000400 (40µA per bit)
262
263 // 5. Compute the calibration register
264 // Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
265 // Cal = 10240 (0x2800)
266
267 // 6. Calculate the power LSB
268 // PowerLSB = 20 * CurrentLSB
269 // PowerLSB = 0.0008 (800µW per bit)
270
271 // 7. Compute the maximum current and shunt voltage values before overflow
272 //
273 // Max_Current = Current_LSB * 32767
274 // Max_Current = 1.31068A before overflow
275 //
276 // If Max_Current > Max_Possible_I then
277 // Max_Current_Before_Overflow = MaxPossible_I
278 // Else
279 // Max_Current_Before_Overflow = Max_Current
280 // End If
281 //
282 // ... In this case, we're good though since Max_Current is less than MaxPossible_I
283 //
284 // Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
285 // Max_ShuntVoltage = 0.131068V
286 //
287 // If Max_ShuntVoltage >= VSHUNT_MAX
288 // Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
289 // Else
290 // Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
291 // End If
292
293 // 8. Computer the Maximum Power
294 // MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
295 // MaximumPower = 1.31068 * 32V
296 // MaximumPower = 41.94176W
297
298 // Set multipliers to convert raw current/power values
299 ina219_currentDivider_mA = 25; // Current LSB = 40uA per bit (1000/40 = 25)
300 ina219_powerDivider_mW = 1; // Power LSB = 800µW per bit
301
302 // Set Calibration register to 'Cal' calculated above
303 ina219WriteRegister(INA219_REG_CALIBRATION, 0x2800);
304
305 // Set Config register to take into account the settings above
306 uint16_t config = INA219_CONFIG_BVOLTAGERANGE_32V |
307 INA219_CONFIG_GAIN_8_320MV |
308 INA219_CONFIG_BADCRES_12BIT |
309 INA219_CONFIG_SADCRES_12BIT_1S_532US |
310 INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;
311 ina219WriteRegister(INA219_REG_CONFIG, config);
312 }
313
314 /**************************************************************************/
315 /*!
316 @brief Configures to INA219 to be able to measure up to 16V and 500mA
317 of current. Each unit of current corresponds to 25uA, and each
318 unit of power corresponds to 500µW. Counter overflow occurs at
319 800mA.
320
321 @note These calculations assume a 0.1 ohm resistor is present
322 */
323 /**************************************************************************/
324 static void ina219SetCalibration_16V_500mA(void)
325 {
326 // VBUS_MAX = 16V
327 // VSHUNT_MAX = 0.08 (Assumes Gain 2, 80mV, can also be 0.32, 0.16, 0.04)
328 // RSHUNT = 0.1 (Resistor value in ohms)
329
330 // 1. Determine max possible current
331 // MaxPossible_I = VSHUNT_MAX / RSHUNT
332 // MaxPossible_I = 0.8A
333
334 // 2. Determine max expected current
335 // MaxExpected_I = 0.5A
336
337 // 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
338 // MinimumLSB = MaxExpected_I/32767
339 // MinimumLSB = 0.0000153 (15.3µA per bit)
340 // MaximumLSB = MaxExpected_I/4096
341 // MaximumLSB = 0.0001221 (122µA per bit)
342
343 // 4. Choose an LSB between the min and max values
344 // (Preferrably a roundish number close to MinLSB)
345 // CurrentLSB = 0.0000250 (25µA per bit)
346
347 // 5. Compute the calibration register
348 // Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
349 // Cal = 16384 (0x4000)
350
351 // 6. Calculate the power LSB
352 // PowerLSB = 20 * CurrentLSB
353 // PowerLSB = 0.0005 (500µW per bit)
354
355 // 7. Compute the maximum current and shunt voltage values before overflow
356 //
357 // Max_Current = Current_LSB * 32767
358 // Max_Current = 0.819175 (819 mA before overflow)
359 //
360 // If Max_Current > Max_Possible_I then
361 // Max_Current_Before_Overflow = MaxPossible_I
362 // Else
363 // Max_Current_Before_Overflow = Max_Current
364 // End If
365 //
366 // Max_Current_Before_Overflow = 0.8A
367 //
368 // Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
369 // Max_ShuntVoltage = 0.8 * 0.1
370 // Max_ShuntVoltage = 0.08V
371 //
372 // If Max_ShuntVoltage >= VSHUNT_MAX
373 // Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
374 // Else
375 // Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
376 // End If
377
378 // 8. Computer the Maximum Power
379 // MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
380 // MaximumPower = 0.8 * 16V
381 // MaximumPower = 12.8W
382
383 // Set multipliers to convert raw current/power values
384 ina219_currentDivider_mA = 40; // Current LSB = 25uA per bit (1000/25 = 40)
385 ina219_powerDivider_mW = 1; // Power LSB = 500µW per bit
386
387 // Set Calibration register to 'Cal' calculated above
388 ina219WriteRegister(INA219_REG_CALIBRATION, 0x4000);
389
390 // Set Config register to take into account the settings above
391 uint16_t config = INA219_CONFIG_BVOLTAGERANGE_16V |
392 INA219_CONFIG_GAIN_2_80MV |
393 INA219_CONFIG_BADCRES_12BIT |
394 INA219_CONFIG_SADCRES_12BIT_1S_532US |
395 INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;
396 ina219WriteRegister(INA219_REG_CONFIG, config);
397 }
398
399 /**************************************************************************/
400 /*!
401 @brief Configures to INA219 to be able to measure up to 16V and 200mA
402 of current. Each unit of current corresponds to 10uA, and each
403 unit of power corresponds to 200µW. Counter overflow occurs at
404 327mA.
405
406 @note These calculations assume a 0.1 ohm resistor is present
407 */
408 /**************************************************************************/
409 static void ina219SetCalibration_16V_200mA(void)
410 {
411 // VBUS_MAX = 16V
412 // VSHUNT_MAX = 0.04 (Assumes Gain 1, 40mV, can also be 0.32, 0.16, 0.08)
413 // RSHUNT = 0.1 (Resistor value in ohms)
414
415 // 1. Determine max possible current
416 // MaxPossible_I = VSHUNT_MAX / RSHUNT
417 // MaxPossible_I = 0.4A
418
419 // 2. Determine max expected current
420 // MaxExpected_I = 0.2A
421
422 // 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
423 // MinimumLSB = MaxExpected_I/32767
424 // MinimumLSB = 0.000006104 (6.104µA per bit)
425 // MaximumLSB = MaxExpected_I/4096
426 // MaximumLSB = 0,000048828 (48.82µA per bit)
427
428 // 4. Choose an LSB between the min and max values
429 // CurrentLSB = 0.000010 (10µA per bit)
430
431 // 5. Compute the calibration register
432 // Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
433 // Cal = 40960 (0xA000)
434
435 // 6. Calculate the power LSB
436 // PowerLSB = 20 * CurrentLSB
437 // PowerLSB = 0.0002 (200µW per bit)
438
439 // 7. Compute the maximum current and shunt voltage values before overflow
440 //
441 // Max_Current = Current_LSB * 32767
442 // Max_Current = 0.32767 (328 mA before overflow)
443 //
444 // If Max_Current > Max_Possible_I then
445 // Max_Current_Before_Overflow = MaxPossible_I
446 // Else
447 // Max_Current_Before_Overflow = Max_Current
448 // End If
449 //
450 // Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
451 // Max_ShuntVoltage = 0.032767V
452 //
453 // If Max_ShuntVoltage >= VSHUNT_MAX
454 // Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
455 // Else
456 // Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
457 // End If
458
459 // 8. Computer the Maximum Power
460 // MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
461 // MaximumPower = 0.32767 * 16V
462 // MaximumPower = 5.24W
463
464 // Set multipliers to convert raw current/power values
465 ina219_currentDivider_mA = 100; // Current LSB = 10uA per bit (1000/10 = 100)
466 ina219_powerDivider_mW = 1; // Power LSB = 200µW per bit
467
468 // Set Calibration register to 'Cal' calculated above
469 ina219WriteRegister(INA219_REG_CALIBRATION, 0xA000);
470
471 // Set Config register to take into account the settings above
472 uint16_t config = INA219_CONFIG_BVOLTAGERANGE_16V |
473 INA219_CONFIG_GAIN_1_40MV |
474 INA219_CONFIG_BADCRES_12BIT |
475 INA219_CONFIG_SADCRES_12BIT_1S_532US |
476 INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;
477 ina219WriteRegister(INA219_REG_CONFIG, config);
478 }
479
480 /**************************************************************************/
481 /*!
482 @brief Initialises the I2C block
483 */
484 /**************************************************************************/
485 void ina219Init(void)
486 {
487 // Reset INA219 (set to default values)
488 ina219WriteRegister(INA219_REG_CONFIG, INA219_CONFIG_RESET);
489
490 // Setup chip for 32V and 2A by default
491 ina219SetCalibration_32V_2A();
492 }
493
494 /**************************************************************************/
495 /*!
496 @brief Gets the shunt voltage (16-bit signed integer, so +-32767)
497 */
498 /**************************************************************************/
499 int16_t ina219GetShuntVoltage(void)
500 {
501 uint16_t value;
502 ina219Read16(INA219_REG_SHUNTVOLTAGE, &value);
503 return value;
504 }
505
506 /**************************************************************************/
507 /*!
508 @brief Gets the shunt voltage (16-bit signed integer, so +-32767)
509 */
510 /**************************************************************************/
511 int16_t ina219GetBusVoltage(void)
512 {
513 uint16_t value;
514 ina219Read16(INA219_REG_BUSVOLTAGE, &value);
515 // Shift to the right 3 to drop CNVR and OVF and then multiply by LSB
516 return (value >> 3) * 4;
517 }
518
519 /**************************************************************************/
520 /*!
521 @brief Gets the raw power value (16-bit signed integer, so +-32767)
522 */
523 /**************************************************************************/
524 int16_t ina219GetPower(void)
525 {
526 uint16_t value;
527 ina219Read16(INA219_REG_POWER, &value);
528 return value;
529 }
530
531 /**************************************************************************/
532 /*!
533 @brief Gets the power value in mW, taking into account the config
534 settings and power LSB
535 */
536 /**************************************************************************/
537 int16_t ina219GetPower_mW(void)
538 {
539 uint16_t value;
540 ina219Read16(INA219_REG_POWER, &value);
541 return value / ina219_powerDivider_mW;
542 }
543
544 /**************************************************************************/
545 /*!
546 @brief Gets the raw current value (16-bit signed integer, so +-32767)
547 */
548 /**************************************************************************/
549 int16_t ina219GetCurrent(void)
550 {
551 uint16_t value;
552 ina219Read16(INA219_REG_CURRENT, &value);
553 return value;
554 }
555
556 /**************************************************************************/
557 /*!
558 @brief Gets the current value in mA, taking into account the
559 config settings and current LSB
560 */
561 /**************************************************************************/
562 int16_t ina219GetCurrent_mA(void)
563 {
564 uint16_t value;
565 ina219Read16(INA219_REG_CURRENT, &value);
566 return value / ina219_currentDivider_mA;
567 }
568
569
This page took 0.10474 seconds and 5 git commands to generate.