diff --git a/libraries/INA226/INA226.cpp b/libraries/INA226/INA226.cpp index c1cb335c..b71bbb28 100644 --- a/libraries/INA226/INA226.cpp +++ b/libraries/INA226/INA226.cpp @@ -1,21 +1,11 @@ -// FILE: INA266.h +// FILE: INA226.h // AUTHOR: Rob Tillaart -// VERSION: 0.1.6 +// VERSION: 0.2.0 // DATE: 2021-05-18 -// PURPOSE: Arduino library for INA266 power sensor +// PURPOSE: Arduino library for INA226 power sensor // URL: https://github.com/RobTillaart/INA226 // -// HISTORY: -// 0.1.0 2021-05-18 initial version -// 0.1.1 2021-06-21 improved calibration + added functions -// 0.1.2 2021-06-22 add check of parameters of several functions + unit tests -// add getShunt() , getMaxCurrent() -// 0.1.3 2021-06-22 add getCurrentLSB_uA() + improve examples -// fix for calibration -// 0.1.4 2021-08-07 fix getCurrent() -// 0.1.5 2021-11-05 update build-CI, add badges -// fix address in constructor. -// 0.1.6 2021-12-20 update library.json, license, minor edits +// HISTORY: see releaseNotes.md #include "INA226.h" @@ -40,7 +30,7 @@ INA226::INA226(const uint8_t address, TwoWire *wire) { _address = address; _wire = wire; - // as these + // not calibrated values by default. _current_LSB = 0; _maxCurrent = 0; _shunt = 0; @@ -79,14 +69,7 @@ bool INA226::isConnected() // float INA226::getShuntVoltage() { - uint16_t val = _readRegister(INA226_SHUNT_VOLTAGE); - if (val & 0x8000) - { - val = val & 0x7FFF; - val = val ^ 0x7FFF; - val++; - return val * -2.5e-6; - } + int16_t val = _readRegister(INA226_SHUNT_VOLTAGE); return val * 2.5e-6; // fixed 2.50 uV } @@ -107,14 +90,7 @@ float INA226::getPower() float INA226::getCurrent() { - uint16_t val = _readRegister(INA226_CURRENT); - if (val & 0x8000) - { - val = val & 0x7FFF; - val = val ^ 0x7FFF; - val++; - return val * -_current_LSB; - } + int16_t val = _readRegister(INA226_CURRENT); return val * _current_LSB; } @@ -128,7 +104,10 @@ void INA226::reset() uint16_t mask = _readRegister(INA226_CONFIGURATION); mask |= 0x800; _writeRegister(INA226_CONFIGURATION, mask); - // reset calibration? + // reset calibration + _current_LSB = 0; + _maxCurrent = 0; + _shunt = 0; } @@ -198,30 +177,49 @@ uint8_t INA226::getShuntVoltageConversionTime() // bool INA226::setMaxCurrentShunt(float maxCurrent, float shunt, bool normalize) { - if (maxCurrent > 20 || maxCurrent < 0.001) return false; + // #define printdebug true + uint32_t calib = 0; + uint32_t factor = 1; + + if ((maxCurrent > 20) || (maxCurrent < 0.001)) return false; if (shunt < 0.001) return false; _current_LSB = maxCurrent * 3.0517578125e-5; // maxCurrent / 32768; + #ifdef printdebug + Serial.println(); + Serial.print("normalize:\t"); + Serial.println(normalize ? " true":" false"); + Serial.print("initial current_LSB:\t"); + Serial.print(_current_LSB, 8); + Serial.println(" uA / bit"); + #endif + // normalize the LSB to a round number // LSB will increase if (normalize) { - // Serial.print("current_LSB:\t"); - // Serial.println(_current_LSB, 10); - uint32_t factor = 1; + calib = round(0.00512 / (_current_LSB * shunt)); + _current_LSB = 0.00512 / (calib * shunt); + + #ifdef printdebug + Serial.print("Prescale current_LSB:\t"); + Serial.print(_current_LSB, 8); + Serial.println(" uA / bit"); + #endif + + // auto scale current_LSB + factor = 1; while (_current_LSB < 1) { _current_LSB *= 10; factor *= 10; } - _current_LSB = 10.0 / factor; - // Serial.print("current_LSB:\t"); - // Serial.println(_current_LSB, 10); + _current_LSB = 1.0 / factor; } - // auto-scale - uint32_t calib = round(0.00512 / (_current_LSB * shunt)); + // auto scale calibration + calib = round(0.00512 / (_current_LSB * shunt)); while (calib > 65535) { _current_LSB *= 10; @@ -229,11 +227,25 @@ bool INA226::setMaxCurrentShunt(float maxCurrent, float shunt, bool normalize) } _writeRegister(INA226_CALIBRATION, calib); - // Serial.print("Calibration:\t"); - // Serial.println(calib); - _maxCurrent = _current_LSB * 32768.0; _shunt = shunt; + + #ifdef printdebug + Serial.print("factor:\t"); + Serial.println(factor); + Serial.print("Final current_LSB:\t"); + Serial.print(_current_LSB, 8); + Serial.println(" uA / bit"); + Serial.print("Calibration:\t"); + Serial.println(calib); + Serial.print("Max current:\t"); + Serial.print(_maxCurrent); + Serial.println(" A"); + Serial.print("Shunt:\t"); + Serial.print(_shunt, 8); + Serial.println(" ohm"); + #endif + return true; } diff --git a/libraries/INA226/INA226.h b/libraries/INA226/INA226.h index ce1b4037..23cc5d27 100644 --- a/libraries/INA226/INA226.h +++ b/libraries/INA226/INA226.h @@ -1,9 +1,9 @@ #pragma once -// FILE: INA266.h +// FILE: INA226.h // AUTHOR: Rob Tillaart -// VERSION: 0.1.6 +// VERSION: 0.2.0 // DATE: 2021-05-18 -// PURPOSE: Arduino library for INA266 power sensor +// PURPOSE: Arduino library for INA226 power sensor // URL: https://github.com/RobTillaart/INA226 // // Read the datasheet for the details @@ -14,7 +14,7 @@ #include "Wire.h" -#define INA226_LIB_VERSION (F("0.1.6")) +#define INA226_LIB_VERSION (F("0.2.0")) // set by setAlertRegister @@ -77,8 +77,10 @@ public: // mandatory to set these! // maxCurrent = 0.001 .. 20 // shunt >= 0.001 - bool setMaxCurrentShunt(float macCurrent = 20.0, float shunt = 0.002, + bool setMaxCurrentShunt(float macCurrent = 20.0, + float shunt = 0.002, bool normalize = true); + bool isCalibrated() { return _current_LSB != 0.0; }; // these return zero if not calibrated! float getCurrentLSB() { return _current_LSB; }; diff --git a/libraries/INA226/README.md b/libraries/INA226/README.md index db438459..46fe4fe8 100644 --- a/libraries/INA226/README.md +++ b/libraries/INA226/README.md @@ -21,9 +21,9 @@ Not all functionality is tested / investigated. The INA226 is a voltage, current and power measurement device. a few important maxima. (See datasheet, chapter 6) -| description | max | unit | -|:--------------|------:|-------:| -| bus voltage | 36 | Volt | +| description | max | unit | notes | +|:--------------|------:|-------:|:------| +| bus voltage | 36 | Volt | unclear for how long. | shunt voltage | 80 | mVolt | | current | 20 | Ampere | @@ -36,7 +36,7 @@ See datasheet - table 2 - datasheet. ## About Measurements -Calibration is mandatory to get **getCurrent()** and **getPower()** to work. +Calibration with **setMaxCurrentShunt()** is mandatory to get **getCurrent()** and **getPower()** to work. Some initial tests shows that the readings do not 100% add up. I expect this is caused by fluctuations in my power supply used and @@ -53,18 +53,30 @@ always check and verify what is on the shunt and even verify with a DMM that thi With the calibration function **setMaxCurrentShunt()** one can just set the actual value and even compensate slightly if readings are structural too low or too high. -I noted that the **getPower()** function does not always equal **getBusVoltage()** times **getCurrent()** -Cause is rounding/trunking maths and time of measurement. You might prefer to multiply those values yourself -to get extra digits. Please be aware that more digits is not always more exact (think significant digits) +I noted that the **getPower()** function does not always equal **getBusVoltage()** times **getCurrent()**. +Cause is rounding/trunking maths and time of measurement. +You might prefer to multiply those values yourself to get extra digits. +Please be aware that more digits is not always more exact (think significant digits) The example sketch **INA226_setMaxCurrentShunt.ino** switches between two calibration modes. It shows the **INA266** sensor needs time to accommodate to this change. -In practice you should call **setMaxCurrentShunt()** only once in **setup()** +In practice you should call **setMaxCurrentShunt()** only once in **setup()**. + + +## Versions + +#### 0.2.0 + +- **reset()** also resets the calibration (current_lsb, maxCurrent and shunt), +thereby forcing the user to redo the calibration call with **setMaxCurrentShunt()**. +- fixes issue #11 => a factor 10 bug in current_lsb. +- some edits in readme.md. +- added **bool isCalibrated()**. ## Interface -read datasheet for details +read datasheet for details. ### Constructor @@ -84,34 +96,40 @@ the sensor. Also the value is not meaningful if there is no shunt connected. - **float getShuntVoltage()** idem. - **float getBusVoltage()** idem. Max 36 Volt. -- **float getCurrent()** is the current through the shunt in Ampere -- **float getPower()** is the current x BusVoltage in Watt +- **float getCurrent()** is the current through the shunt in Ampere. +- **float getPower()** is the current x BusVoltage in Watt. -Helper functions to get the right scale +Helper functions to get the right scale. -- **float getBusVoltage_mV()** idem, in millivolts -- **float getShuntVoltage_mV()** idem, in millivolts -- **float getCurrent_mA()** idem in milliAmpere -- **float getPower_mW()** idem in milliWatt -- **float getShuntVoltage_uV()** idem microVolt -- **float getCurrent_uA()** idem in microAmpere -- **float getPower_uW()** idem, in microWatt +- **float getBusVoltage_mV()** idem, in millivolts. +- **float getShuntVoltage_mV()** idem, in millivolts. +- **float getCurrent_mA()** idem in milliAmpere. +- **float getPower_mW()** idem in milliWatt. +- **float getShuntVoltage_uV()** idem microVolt. +- **float getCurrent_uA()** idem in microAmpere. +- **float getPower_uW()** idem, in microWatt. ### Configuration -Note: the conversion time runs in the background and if done value is stored in a register. The core functions read from the registers, so they are not blocked, but just get the same value if no new is ready. +Note: the conversion time runs in the background and if done value is stored in a register. +The core functions read from the registers, so they are not blocked, +but just get the same value if no new is ready. -- **void reset()** software power on reset -- **bool setAverage(uint8_t avg = 0)** see table below -(0 = default ==> 1 read), returns false if parameter > 7 -- **uint8_t getAverage()** returns the value set. Note this is not the count of samples. -- **bool setBusVoltageConversionTime(uint8_t bvct = 4)** see table below -(4 = default ==> 1.1 ms), returns false if parameter > 7 -- **uint8_t getBusVoltageConversionTime()** return the value set. Note this is not a unit of time. -- **bool setShuntVoltageConversionTime(uint8_t svct = 4)** see table below -(4 = default ==> 1.1 ms), returns false if parameter > 7 -- **uint8_t getShuntVoltageConversionTime()** return the value set. Note this is not a unit of time. +- **void reset()** software power on reset. +This implies calibration with **setMaxCurrentShunt()** needs to be redone. +- **bool setAverage(uint8_t avg = 0)** see table below. +(0 = default ==> 1 read), returns false if parameter > 7. +- **uint8_t getAverage()** returns the value set. See table below. +Note this is not the count of samples. +- **bool setBusVoltageConversionTime(uint8_t bvct = 4)** see table below. +(4 = default ==> 1.1 ms), returns false if parameter > 7. +- **uint8_t getBusVoltageConversionTime()** return the value set. +Note the value returned is not a unit of time. +- **bool setShuntVoltageConversionTime(uint8_t svct = 4)** see table below. +(4 = default ==> 1.1 ms), returns false if parameter > 7. +- **uint8_t getShuntVoltageConversionTime()** return the value set. +Note the value returned is not a unit of time. | Average | # samples | notes | @@ -153,11 +171,16 @@ set the calibration register based upon the shunt and the max ampere. 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. -- **float getCurrentLSB()** returns the LSB == precision of the calibration -- **float getCurrentLSB_uA()** returns the LSB == precision of the calibration -- **float getShunt()** returns the value set for the shunt +The user **must** check the return value == true, otherwise the calibration register is **not** set. +- **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. +- **float getCurrentLSB_uA()** returns the LSB in microampere. +- **float getShunt()** returns the value set for the shunt. - **float getMaxCurrent()** returns the value for the maxCurrent which can be corrected. +To print these values one might use https://github.com/RobTillaart/printHelpers + ### Operating mode @@ -215,6 +238,11 @@ The alert line falls when alert is reached. - **uint16_t getDieID()** should return 0x2260 +### debugging + +- **uint16_t getRegister(uint8_t reg)** fetch registers directly, for debugging only. + + ## Operational See examples.. @@ -223,14 +251,20 @@ See examples.. ## Future - test different loads (low edge) -- test unit tests +- expand unit tests possible? - test examples - investigate alert functions / interface -- improve readme.md -- disconnected load, can it be recognized? -- **lastError()** do we need this... +- disconnected load, + - can it be recognized? => current drop? +- **lastError()** do we need this +- if **BVCT SVCT** is set to 6 or 7 + - does the long timing affects RTOS? ==> yield() - cache configuration ? ==> 2 bytes -- **float getCurrentLSB_mA()** wrapper? -- **bool isCalibrated()** - - + - what is gained? updates are faster. + - 15 times used, +- separate release notes. +- can the calibration math be optimized + - integer only? + - less iterations? + - local var for current_lsb? + - ?? diff --git a/libraries/INA226/library.json b/libraries/INA226/library.json index 15956f87..2b32e8a5 100644 --- a/libraries/INA226/library.json +++ b/libraries/INA226/library.json @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/INA226.git" }, - "version": "0.1.6", + "version": "0.2.0", "license": "MIT", "frameworks": "arduino", "platforms": "*", diff --git a/libraries/INA226/library.properties b/libraries/INA226/library.properties index 5127d66e..24b4508e 100644 --- a/libraries/INA226/library.properties +++ b/libraries/INA226/library.properties @@ -1,5 +1,5 @@ name=INA226 -version=0.1.6 +version=0.2.0 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for INA226 power sensor diff --git a/libraries/INA226/releaseNotes.md b/libraries/INA226/releaseNotes.md new file mode 100644 index 00000000..51d569da --- /dev/null +++ b/libraries/INA226/releaseNotes.md @@ -0,0 +1,43 @@ + +# INA226 library + +## Release notes + + +## 0.2.0 2022-02-02 +- fix #11 normalize +- fix #13 simplify sign handling shunt and current +- add releaseNotes.md + +## 0.1.6 2021-12-20 +- update library.json, +- license, +- minor edits + +## 0.1.5 2021-11-05 +- update build-CI, +- add badges in readme.md +- fix address in constructor + +## 0.1.4 2021-08-07 +- fix getCurrent() + +## 0.1.3 2021-06-22 +- add getCurrentLSB_uA() +- improve examples +- fix for calibration + +## 0.1.2 2021-06-22 +- add check of parameters of several functions +- add unit tests +- add getShunt() +- add getMaxCurrent() + +## 0.1.1 2021-06-21 +- improved calibration +- added functions + +## 0.1.0 2021-05-18 +- initial version + + diff --git a/libraries/INA226/test/unit_test_001.cpp b/libraries/INA226/test/unit_test_001.cpp index 4d7237ba..6a3e183a 100644 --- a/libraries/INA226/test/unit_test_001.cpp +++ b/libraries/INA226/test/unit_test_001.cpp @@ -50,9 +50,11 @@ unittest(test_constructor) { INA226 INA(0x40); - + assertTrue(INA.begin()); assertTrue(INA.isConnected()); + + assertFalse(INA.isCalibrated()); }