0.2.1 INA219

This commit is contained in:
Rob Tillaart 2024-01-18 16:36:09 +01:00
parent 163524c559
commit d6c3e13bcf
13 changed files with 262 additions and 81 deletions

View File

@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.1] - 2024-01-17
- add **bool setBusResolution(bits)**
- add **bool setBusSamples(value)**
- add **bool setShuntResolution(bits)**
- add **bool setShuntSamples(value)**
- improve error checking several functions
- calls to **writeRegister()** should return 0.
- error handling needs improvement, this is a first step.
- improve **INA219_get_settings.ino**
- update keywords.txt
- update readme.md
## [0.2.0] - 2023-12-04
- Fix #8, refactor API - support ESP32-S3
- update readme.md

View File

@ -1,6 +1,6 @@
// FILE: INA219.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2021-05-18
// PURPOSE: Arduino library for INA219 voltage, current and power sensor
// URL: https://github.com/RobTillaart/INA219
@ -124,15 +124,16 @@ bool INA219::getConversionFlag()
//
// CONFIGURATION
//
void INA219::reset()
bool INA219::reset()
{
uint16_t config = _readRegister(INA219_CONFIGURATION);
config |= 0x8000;
_writeRegister(INA219_CONFIGURATION, config);
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
// reset calibration
_current_LSB = 0;
_maxCurrent = 0;
_shunt = 0;
return (wrrv == 0);
}
@ -144,8 +145,9 @@ bool INA219::setBusVoltageRange(uint8_t voltage)
uint16_t config = _readRegister(INA219_CONFIGURATION);
config &= ~INA219_CONF_BUS_RANGE_VOLTAGE;
if (voltage == 32) config |= INA219_CONF_BUS_RANGE_VOLTAGE;
_writeRegister(INA219_CONFIGURATION, config);
return true;
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
return (wrrv == 0);
}
@ -168,8 +170,9 @@ bool INA219::setGain(uint8_t factor)
if (factor == 2) config |= (1 << 11);
else if (factor == 4) config |= (2 << 11);
else if (factor == 8) config |= (3 << 11);
_writeRegister(INA219_CONFIGURATION, config);
return true;
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
return (wrrv == 0);
}
@ -184,21 +187,49 @@ uint8_t INA219::getGain()
}
////////////////////////////////////////////////////////
//
// BUS
//
bool INA219::setBusResolution(uint8_t bits)
{
if ((bits < 9) || (bits > 12)) return false;
bits -= 9;
uint16_t config = _readRegister(INA219_CONFIGURATION);
config &= ~INA219_CONF_BUS_ADC;
config |= (bits << 7);
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
return (wrrv == 0);
}
// value = 0..7, always 12 bit resolution,
bool INA219::setBusSamples(uint8_t value)
{
if (value > 7) return false;
value |= 8;
uint16_t config = _readRegister(INA219_CONFIGURATION);
config &= ~INA219_CONF_BUS_ADC;
config |= (value << 7);
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
return (wrrv == 0);
}
bool INA219::setBusADC(uint8_t mask)
{
if (mask > 0x0F) return false;
// TODO improve this one. datasheet.
// two functions
// setBusResolution + setBusSamples()
uint16_t config = _readRegister(INA219_CONFIGURATION);
config &= ~INA219_CONF_BUS_ADC;
config |= (mask << 7);
// if (bits == 10) config |= (1 << 7);
// else if (bits == 11) config |= (2 << 7);
// else if (bits == 12) config |= (3 << 7);
_writeRegister(INA219_CONFIGURATION, config);
return true;
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
return (wrrv == 0);
}
@ -210,18 +241,49 @@ uint8_t INA219::getBusADC()
}
////////////////////////////////////////////////////////
//
// SHUNT
//
bool INA219::setShuntResolution(uint8_t bits)
{
if ((bits < 9) || (bits > 12)) return false;
bits -= 9;
uint16_t config = _readRegister(INA219_CONFIGURATION);
config &= ~INA219_CONF_SHUNT_ADC;
config |= (bits << 3);
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
return (wrrv == 0);
}
// value = 0..7, always 12 bit resolution,
bool INA219::setShuntSamples(uint8_t value)
{
if (value > 7) return false;
value |= 8;
uint16_t config = _readRegister(INA219_CONFIGURATION);
config &= ~INA219_CONF_SHUNT_ADC;
config |= (value << 3);
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
return (wrrv == 0);
}
bool INA219::setShuntADC(uint8_t mask)
{
if (mask > 0x0F) return false;
// TODO improve this one. datasheet.
// two functions
// setShuntResolution + setShuntSamples()
uint16_t config = _readRegister(INA219_CONFIGURATION);
config &= ~INA219_CONF_SHUNT_ADC;
config |= (mask << 3);
_writeRegister(INA219_CONFIGURATION, config);
return true;
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
return (wrrv == 0);
}
@ -233,14 +295,19 @@ uint8_t INA219::getShuntADC()
}
////////////////////////////////////////////////////////
//
// MODE
//
bool INA219::setMode(uint8_t mode)
{
if (mode > 7) return false;
uint16_t config = _readRegister(INA219_CONFIGURATION);
config &= ~INA219_CONF_MODE;
config |= mode;
_writeRegister(INA219_CONFIGURATION, config);
return true;
uint16_t wrrv = _writeRegister(INA219_CONFIGURATION, config);
return (wrrv == 0);
}
@ -258,7 +325,7 @@ uint8_t INA219::getMode()
//
bool INA219::setMaxCurrentShunt(float maxCurrent, float shunt)
{
// #define printdebug
// #define PRINTDEBUG
uint16_t calib = 0;
if (maxCurrent < 0.001) return false;
@ -269,10 +336,9 @@ bool INA219::setMaxCurrentShunt(float maxCurrent, float shunt)
_maxCurrent = maxCurrent;
_shunt = shunt;
calib = round(0.04096 / (_current_LSB * shunt));
_writeRegister(INA219_CALIBRATION, calib);
uint16_t wrrv = _writeRegister(INA219_CALIBRATION, calib);
#ifdef printdebug
#ifdef PRINTDEBUG
Serial.println();
Serial.print("current_LSB:\t");
Serial.print(_current_LSB, 8);
@ -288,7 +354,7 @@ bool INA219::setMaxCurrentShunt(float maxCurrent, float shunt)
Serial.println(" ohm Ω");
#endif
return true;
return (wrrv == 0);
}

View File

@ -1,20 +1,19 @@
#pragma once
// FILE: INA219.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.2.1
// DATE: 2021-05-18
// PURPOSE: Arduino library for INA219 voltage, current and power sensor
// URL: https://github.com/RobTillaart/INA219
//
// Read the datasheet for the details how to connect!
//
#include "Arduino.h"
#include "Wire.h"
#define INA219_LIB_VERSION (F("0.2.0"))
#define INA219_LIB_VERSION (F("0.2.1"))
class INA219
@ -52,17 +51,26 @@ public:
// CONFIGURATION
// need improvement API wise.
void reset();
bool reset();
// voltage = 16, 32 (values below 32 are rounded to 16 or 32)
bool setBusVoltageRange(uint8_t voltage = 16);
uint8_t getBusVoltageRange(); // returns 16 or 32.
// factor = 1, 2, 4, 8
bool setGain(uint8_t factor = 1);
uint8_t getGain();
// mask
bool setBusADC(uint8_t mask = 0x03);
// configuration BUS
// use one of the next three
bool setBusResolution(uint8_t bits); // 9..12, always 1 sample
bool setBusSamples(uint8_t value); // 0..7, always 12 bits.
bool setBusADC(uint8_t mask = 0x03); // uses a mask, check datasheet
uint8_t getBusADC();
bool setShuntADC(uint8_t mask = 0x03);
// configuration SHUNT
// use one of the next three
bool setShuntResolution(uint8_t bits); // 9..12, always 1 sample
bool setShuntSamples(uint8_t value); // 0..7, always 12 bits.
bool setShuntADC(uint8_t mask = 0x03); // uses a mask, check datasheet
uint8_t getShuntADC();
// Operating mode = 0..7
@ -103,6 +111,7 @@ private:
uint16_t _readRegister(uint8_t reg);
uint16_t _writeRegister(uint8_t reg, uint16_t value);
float _current_LSB;
float _shunt;
float _maxCurrent;

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021-2023 Rob Tillaart
Copyright (c) 2021-2024 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -32,6 +32,15 @@ Maxima, see datasheet, chapter 7, esp 7.5
| shunt voltage | 320 | mVolt | depends on PGA setting
#### Related
- https://www.ti.com/product/INA219#tech-docs
- https://www.ti.com/product/INA219#params
- https://www.ti.com/document-viewer/INA219/datasheet
- https://github.com/RobTillaart/INA219
- https://github.com/RobTillaart/INA226
#### 0.2.0 Breaking change
Version 0.2.0 introduced a breaking change.
@ -67,7 +76,7 @@ The address depends on how the A0 and A1 address lines are connected to the SCL,
#### Performance
Datasheet states it supports 1 KHz .. 2.56 MHz.
Note: higher speeds need smaller pull up resistors.
Note: higher speeds and longer wires need smaller pull up resistors.
Some timings in micros for **INA.getMode()** on an Arduino UNO.
This is just one readRegister call, similar to most functions.
@ -97,6 +106,7 @@ use **INA219_test_I2C.ino**
- **bool begin()** UNO ea. initializes the class.
Returns true if the INA219 address (set in the constructor) is on the I2C bus.
- **bool isConnected()** Returns true if the INA219 address (set in the constructor) is on the I2C bus.
- **uint8_t getAddress()** Returns the INA219 address set in the constructor.
#### Core Functions
@ -111,7 +121,7 @@ Also the value is not meaningful if there is no shunt connected.
The library has helper functions to convert above output to a more appropriate scale of units.
Helper functions for the milli scale.
Helper functions for the milli-scale.
- **float getBusVoltage_mV()** idem, returns millivolts.
Note: returns -100 if the math overflow bit is set.
@ -119,7 +129,7 @@ Note: returns -100 if the math overflow bit is set.
- **float getCurrent_mA()** idem in milliAmpere.
- **float getPower_mW()** idem in milliWatt.
Helper functions for the micro scale.
Helper functions for the micro-scale.
- **float getBusVoltage_uV()** idem microVolt.
- **float getShuntVoltage_uV()** idem microVolt.
@ -136,48 +146,99 @@ Especially useful in non-continuous modi.
#### Configuration
Note: the conversion runs in the background and if done the value is stored in a register.
The core functions can always be read from the registers, so they will not block.
Result can be that you get the very same value if no new value is ready.
- **void reset()** software power on reset.
- **bool reset()** software power on reset.
This implies that calibration with **setMaxCurrentShunt()** needs to be redone.
See section below.
Returns false if it could not write settings to device.
- **bool setBusVoltageRange(uint8_t voltage = 16)** set to 16 or 32.
Values < 16 map to 16 and values between 16 and 32 map to 32.
Values above 32 return false.
Values <= 16 map to 16 and values between 16 and 32 map to 32.
Returns false if voltage is above 32..
Returns false if it could not write settings to device.
- **uint8_t getBusVoltageRange()** returns 16 or 32. (Volts)
- **bool setGain(uint8_t factor = 1)** factor = 1, 2, 4, 8.
Determines the shunt voltage range. 40, 80, 160 or 320 mV.
Returns false if factor is not a valid value.
Returns false if it could not write settings to device.
- **uint8_t getGain()** returns set factor.
- **bool setBusADC(uint8_t mask = 0x03)** check datasheet for meaning of mask.
Returns false if mask > 0x0F.
- **uint8_t getBusADC()** returns mask.
- **bool setShuntADC(uint8_t mask = 0x03)** check datasheet for meaning of mask.
Returns false if mask > 0x0F.
- **uint8_t getShuntADC()** returns mask.
#### Configuration BUS and SHUNT
**Note:**
The internal conversions runs in the background in the INA219.
If a conversion is finished the measured value is stored in the appropriate register.
The last obtained values can always be read from the registers, so they will not block.
Result can be that you get the very same value if no new data is available yet.
This is especially true if you increase the number of samples.
(See also discussion in #11).
Using more samples reduces the noise level, but one will miss the faster
changes in voltage or current.
Depending on your project needs you can choose one over the other.
As a rule of thumb one could take the time between two I2C reads of
a register as an upper limit.
This would result in a fresh measurement every time one reads the register.
NB it is always possible to average readings fetched from the device
in your own code.
Use one of these three so set **bus** resolution and sampling.
- **bool setBusResolution(uint8_t bits)** bits = 9..12, always 1 sample.
Returns false if parameter out of range.
Returns false if it could not write settings to device.
- **bool setBusSamples(uint8_t value)** value = 0..7 => maps to 2^value samples.
Always 12 bits.
Returns false if parameter out of range.
Returns false if it could not write settings to device.
- **bool setBusADC(uint8_t mask = 0x03)** see table below.
Check datasheet for all details.
Returns false if parameter out of range (mask > 0x0F).
Returns false if it could not write settings to device.
- **uint8_t getBusADC()** returns mask, see table below.
Use one of these three so set **shunt** resolution and sampling.
- **bool setShuntResolution(uint8_t bits)** bits = 9..12, always 1 sample.
Returns false if parameter out of range.
Returns false if it could not write settings to device.
- **bool setShuntSamples(uint8_t value)** value = 0..7 => maps to 2^value samples.
Always 12 bits.
Returns false if parameter out of range.
Returns false if it could not write settings to device.
- **bool setShuntADC(uint8_t mask = 0x03)** see table below.
Check datasheet for all details.
Returns false if parameter out of range (mask > 0x0F).
Returns false if it could not write settings to device.
- **uint8_t getShuntADC()** returns mask, see table below.
#### Resolution samples table
mask = both resolution + averaging multiple samples.
minus - == don't care
| bit mask | value | description | conversion time |
|:----------:|:-------:|:------------------|:---------------:|
| 0-00 | 0 / 4 | 9 bit resolution | 84 μs |
| 0-01 | 1 / 5 | 10 bit resolution | 148 μs |
| 0-10 | 2 / 6 | 11 bit resolution | 276 μs |
| 0-11 | 3 / 7 | 12 bit resolution | 532 μs |
| 1000 | 8 | 12 bit 1 sample | 532 μs |
| 1001 | 9 | 2 samples | 1.06 ms |
| 1010 | 10 | 4 samples | 2.13 ms |
| 1011 | 11 | 8 samples | 4.26 ms |
| 1100 | 12 | 16 samples | 8.51 ms |
| 1101 | 13 | 32 samples | 17.02 ms |
| 1110 | 14 | 64 samples | 34.05 ms |
| 1111 | 15 | 128 samples | 68.10 ms |
- note that a new value can take a while depending on value set.
| bit mask | value | resolution | samples | conversion time |
|:----------:|:-------:|:-------------|:--------------|:---------------:|
| 0-00 | 0 / 4 | 9 bit | 1 sample | 84 μs |
| 0-01 | 1 / 5 | 10 bit | 1 sample | 148 μs |
| 0-10 | 2 / 6 | 11 bit | 1 sample | 276 μs |
| 0-11 | 3 / 7 | 12 bit | 1 sample | 532 μs |
| | | | | |
| 1000 | 8 | 12 bit | 1 sample | 532 μs |
| 1001 | 9 | 12 bit | 2 samples | 1.06 ms |
| 1010 | 10 | 12 bit | 4 samples | 2.13 ms |
| 1011 | 11 | 12 bit | 8 samples | 4.26 ms |
| 1100 | 12 | 12 bit | 16 samples | 8.51 ms |
| 1101 | 13 | 12 bit | 32 samples | 17.02 ms |
| 1110 | 14 | 12 bit | 64 samples | 34.05 ms |
| 1111 | 15 | 12 bit | 128 samples | 68.10 ms |
- note that a new value set can substantially increase the conversion time.
- note that you cannot set e.g. 9 bits and 16 samples.
- note that there are 3 ways to set 12 bits 1 sample.
#### Operating mode
@ -185,10 +246,12 @@ minus - == don't care
See details datasheet,
- **bool setMode(uint8_t mode = 7)** mode = 0..7.
The value 7 == ShuntBusContinuous mode.
The default value 7 == ShuntBusContinuous mode.
Returns false if parameter out of range (mode > 7).
Returns false if it could not write settings to device.
- **uint8_t getMode()** returns the mode (0..7) set.
Descriptive mode functions (convenience wrappers).
Descriptive mode functions (convenience wrappers around **setMode()**).
- **bool shutDown()** mode 0
- **bool setModeShuntTrigger()** mode 1 - how to trigger to be investigated.
@ -212,6 +275,8 @@ From this the LSB is derived.
Note the function will round up the LSB to nearest round value by default.
This may cause loss of precision. The function may force normalization if underflow detected.
The user **must** check the return value == true, otherwise the calibration register is **not** set.
Returns false if parameter out of range.
Returns false if it could not write settings to device.
- **bool isCalibrated()** returns true if CurrentLSB has been calculated by **setMaxCurrentShunt()**.
- **float getCurrentLSB()** returns the LSB in Ampere == precision of the calibration.
- **float getCurrentLSB_mA()** returns the LSB in milliampere.
@ -223,9 +288,19 @@ To print these values one might use https://github.com/RobTillaart/printHelpers
to get the values in scientific notation like "3.5e-6"
#### debugging
#### Debugging
- **uint16_t getRegister(uint8_t reg)** fetch registers directly, meant for debugging only. Check datasheet.
- **uint16_t getRegister(uint8_t reg)** fetch values from registers directly.
Meant for debugging only, reg = 0..5. Check datasheet for the details.
| reg | description | RW |
|:-----:|:----------------|:----:|
| 0 | configuration | RW |
| 1 | shunt voltage | R |
| 2 | bus voltage | R |
| 3 | power | R |
| 4 | current | R |
| 5 | calibration | RW |
## Future
@ -240,6 +315,10 @@ to get the values in scientific notation like "3.5e-6"
#### Should
- sync INA226 where meaningful
- improve error handling
- low level I2C, readRegister() + writeRegister()
- other? parameters
- create unit tests
- test performance
- verify conversion time

View File

@ -6,7 +6,6 @@
#include "INA219.h"
#include "Wire.h"
INA219 INA(0x40);

View File

@ -6,7 +6,6 @@
#include "INA219.h"
#include "Wire.h"
INA219 INA(0x40);

View File

@ -6,7 +6,6 @@
#include "INA219.h"
#include "Wire.h"
INA219 INA(0x40);
@ -87,7 +86,7 @@ void setup()
///////////////////////////////////////////////
Serial.print("BADC:\t");
for (uint8_t b = 0; b < 8; b++)
for (uint8_t b = 0; b < 16; b++)
{
INA.setBusADC(b);
Serial.print(INA.getBusADC());
@ -99,7 +98,7 @@ void setup()
///////////////////////////////////////////////
Serial.print("SADC:\t");
for (uint8_t s = 0; s < 8; s++)
for (uint8_t s = 0; s < 16; s++)
{
INA.setShuntADC(s);
Serial.print(INA.getShuntADC());

View File

@ -6,7 +6,6 @@
#include "INA219.h"
#include "Wire.h"
INA219 INA(0x40);

View File

@ -6,7 +6,6 @@
#include "INA219.h"
#include "Wire.h"
INA219 INA(0x40);

View File

@ -8,6 +8,7 @@ INA219 KEYWORD1
# Methods and Functions (KEYWORD2)
begin KEYWORD2
isConnected KEYWORD2
getAddress KEYWORD2
getShuntVoltage KEYWORD2
getBusVoltage KEYWORD2
@ -17,9 +18,11 @@ getMathOverflowFlag KEYWORD2
getConversionFlag KEYWORD2
getBusVoltage_mV KEYWORD2
getShuntVoltage_uV KEYWORD2
getShuntVoltage_mV KEYWORD2
getCurrent_mA KEYWORD2
getPower_mW KEYWORD2
getBusVoltage_uV KEYWORD2
getShuntVoltage_uV KEYWORD2
getCurrent_uA KEYWORD2
getPower_uW KEYWORD2
@ -29,8 +32,14 @@ setBusVoltageRange KEYWORD2
getBusVoltageRange KEYWORD2
setGain KEYWORD2
getGain KEYWORD2
setBusResolution KEYWORD2
setBusSamples KEYWORD2
setBusADC KEYWORD2
getBusADC KEYWORD2
setShuntResolution KEYWORD2
setShuntSamples KEYWORD2
setShuntADC KEYWORD2
getShuntADC KEYWORD2
@ -46,6 +55,16 @@ setModeShuntContinuous KEYWORD2
setModeBusContinuous KEYWORD2
setModeShuntBusContinuous KEYWORD2
setMaxCurrentShunt KEYWORD2
isCalibrated KEYWORD2
getCurrentLSB KEYWORD2
getCurrentLSB_mA KEYWORD2
getCurrentLSB_uA KEYWORD2
getShunt KEYWORD2
getMaxCurrent KEYWORD2
getRegister KEYWORD2
# Constants (LITERAL1)
INA219_LIB_VERSION LITERAL1

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/INA219.git"
},
"version": "0.2.0",
"version": "0.2.1",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=INA219
version=0.2.0
version=0.2.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for INA219 voltage, current and power sensor.