Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setMaxCurrentShunt normalization optimized #29

Merged
merged 5 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 59 additions & 24 deletions INA226.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ int INA226::setMaxCurrentShunt(float maxCurrent, float shunt, bool normalize)

// fix #16 - datasheet 6.5 Electrical Characteristics
// rounded value to 80 mV
float shuntVoltage = abs(maxCurrent * shunt);
float shuntVoltage = maxCurrent * shunt;
if (shuntVoltage > 0.080) return INA226_ERR_SHUNTVOLTAGE_HIGH;
if (maxCurrent < 0.001) return INA226_ERR_MAXCURRENT_LOW;
if (shunt < INA226_MINIMAL_SHUNT) return INA226_ERR_SHUNT_LOW;
Expand All @@ -194,62 +194,97 @@ int INA226::setMaxCurrentShunt(float maxCurrent, float shunt, bool normalize)
Serial.print("normalize:\t");
Serial.println(normalize ? " true":" false");
Serial.print("initial current_LSB:\t");
Serial.print(_current_LSB, 8);
Serial.print(_current_LSB * 1e+6, 1);
Serial.println(" uA / bit");
#endif

uint32_t calib = 0;
uint32_t factor = 1;

// normalize the LSB to a round number
// LSB will increase
if (normalize)
{
calib = round(0.00512 / (_current_LSB * shunt));
_current_LSB = 0.00512 / (calib * shunt);
/* check if maxCurrent (normal) or shunt resistor (due to unusual low resistor values in relation to maxCurrent) determines currentLSB
we have to take the upper value for currentLSB

calculation of currentLSB based on shunt resistor and calibration register limits (2 bytes)
cal = 0.00512 / ( shunt * currentLSB )
cal(max) = 2^16-1
currentLSB(min) = 0.00512 / ( shunt * cal(max) )
currentLSB(min) ~= 0.00512 / ( shunt * 2^16 )
currentLSB(min) ~= 2^9 * 1e-5 / ( shunt * 2^16 )
currentLSB(min) ~= 1e-5 / 2^7 / shunt
currentLSB(min) ~= 7.8125e-8 / shunt
*/
if( 7.8125e-8 / shunt > _current_LSB ) {
// shunt resistor determines currentLSB -> take this a starting point for currentLSB
_current_LSB = 7.8125e-8 / shunt;
}

#ifdef printdebug
Serial.print("Prescale current_LSB:\t");
Serial.print(_current_LSB, 8);
Serial.print(_current_LSB * 1e+6, 1);
Serial.println(" uA / bit");
#endif

// auto scale current_LSB
factor = 1;
while (_current_LSB < 1)
{
_current_LSB *= 10;
factor *= 10;
// normalize _current_LSB to a value of 1, 2 or 5 * 1e-6 to 1e-3
// convert float to int
uint16_t currentLSB_uA = float(_current_LSB * 1e+6);
currentLSB_uA++; // ceil would be more precise, but uses 176 bytes of flash

uint16_t factor = 1; // 1u to 1000u
RobTillaart marked this conversation as resolved.
Show resolved Hide resolved
uint8_t i = 0; // 1 byte loop reduces footprint
RobTillaart marked this conversation as resolved.
Show resolved Hide resolved
do{
if( 1*factor >= currentLSB_uA){
_current_LSB = 1*factor * 1e-6;
i=0xFF;
}else if( 2*factor >= currentLSB_uA){
_current_LSB = 2*factor * 1e-6;
i=0xFF;
}else if( 5*factor >= currentLSB_uA){
_current_LSB = 5*factor * 1e-6;
i=0xFF;
}else {
factor *= 10;
i++;
}
}while(i < 4); // 10^4

if(i != 0xFF) {
_current_LSB = 0;
return INA226_ERR_NORMALIZE_FAILED;
}
_current_LSB = 1.0 / factor;

#ifdef printdebug
Serial.print("After scale current_LSB:\t");
Serial.print(_current_LSB * 1e+6, 1);
Serial.println(" uA / bit");
#endif
// done
}

// auto scale calibration
calib = round(0.00512 / (_current_LSB * shunt));
uint32_t calib = round(0.00512 / (_current_LSB * shunt));
while (calib > 65535)
{
_current_LSB *= 10;
calib /= 10;
_current_LSB *= 2;
calib = calib >> 1;
RobTillaart marked this conversation as resolved.
Show resolved Hide resolved
}
_writeRegister(INA226_CALIBRATION, calib);

_maxCurrent = _current_LSB * 32768;
_shunt = shunt;

#ifdef printdebug
Serial.print("factor:\t");
Serial.println(factor);
Serial.print("Final current_LSB:\t");
Serial.print(_current_LSB, 8);
Serial.print(_current_LSB * 1e+6, 1);
Serial.println(" uA / bit");
Serial.print("Calibration:\t");
Serial.println(calib);
Serial.print("Max current:\t");
Serial.print(_maxCurrent);
Serial.print(_maxCurrent, 3);
Serial.println(" A");
Serial.print("Shunt:\t");
Serial.print(_shunt, 8);
Serial.println(" ohm");
Serial.print(_shunt, 4);
Serial.println(" Ohm");
Serial.print("ShuntV:\t");
Serial.print(shuntVoltage, 4);
Serial.println(" Volt");
Expand Down
5 changes: 2 additions & 3 deletions INA226.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,11 @@
#define INA226_ERR_SHUNTVOLTAGE_HIGH 0x8000
#define INA226_ERR_MAXCURRENT_LOW 0x8001
#define INA226_ERR_SHUNT_LOW 0x8002

#define INA226_ERR_NORMALIZE_FAILED 0x8003

// See issue #26
#define INA226_MINIMAL_SHUNT (0.001)


class INA226
{
public:
Expand Down Expand Up @@ -88,7 +87,7 @@ class INA226
// shunt * maxCurrent < 81 mV
// maxCurrent >= 0.001
// shunt >= 0.001
int setMaxCurrentShunt(float macCurrent = 20.0,
int setMaxCurrentShunt(float maxCurrent = 20.0,
float shunt = 0.002,
bool normalize = true);
bool isCalibrated() { return _current_LSB != 0.0; };
Expand Down
Loading