MAX17048 battery monitor

Am I reading this incorrectly or is there truly something wrong with my battery monitor. I am using the MAX17048 to monitor the voltage and SOC of a 3.7V 2500mAh li-ion battery and I am running the example sketch provided by the library and I am currently reading:

3.473 V
0.64 % SOC

That doesn't make sense to me since in their comments in the source file says SOC is reported from 0 - 100.0 %.

I have VIN, GND, SDA, and SCL connected only.

#include <Streaming.h>
#include "Adafruit_MAX1704X.h"

Adafruit_MAX17048 maxlipo;

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);    // wait until serial monitor opens

  Serial.println(F("\nAdafruit MAX17048 simple demo"));

  while (!maxlipo.begin()) {
    Serial.println(F("Couldnt find Adafruit MAX17048?\nMake sure a battery is plugged in!"));
    delay(2000);
  }
  Serial.print(F("Found MAX17048"));
  Serial.print(F(" with Chip ID: 0x")); 
  Serial.println(maxlipo.getChipID(), HEX);
}

void loop() {
  float cellVoltage = maxlipo.cellVoltage();
  if (isnan(cellVoltage)) {
    Serial.println("Failed to read cell voltage, check battery is connected!");
    delay(2000);
    return;
  }
  Serial.print(F("Batt Voltage: ")); Serial.print(cellVoltage, 3); Serial.println(" V");
  Serial.print(F("Batt Percent: ")); Serial.print(maxlipo.cellPercent(), 2); Serial.println(" %");
  Serial.println();

  delay(2000);  // dont query too often!
}

Could You present a pen and paper drawing of the setup?
As soon as a fully charged battery delivers current the voltage will decrease. How much varies.
Does the manual tell about calibration?
You could make a test measuring on a charged battery that is not connected to any load. The see what value You get.

Measuring the battery with a multimeter I get 3.516V.
When I plug it into the battery monitor I get 3.504V.

There are various functions in the source code that talks about resetting and auto-calibration.

RESET

/*!
 *    @brief  Soft reset the MAX1704x
 *    @return True on reset success
 */
bool Adafruit_MAX17048::reset(void) {
  Adafruit_BusIO_Register cmd =
      Adafruit_BusIO_Register(i2c_dev, MAX1704X_CMD_REG, 2, MSBFIRST);

  // send reset command, the MAX1704 will reset before ACKing,
  // so I2C xfer is expected to *fail* with a NACK
  if (cmd.write(0x5400)) {
    return false;
  }

  // loop and attempt to clear alert until success
  for (uint8_t retries = 0; retries < 3; retries++) {
    if (clearAlertFlag(MAX1704X_ALERTFLAG_RESET_INDICATOR)) {
      return true;
    }
  }

  // something didn't work :(
  return false;
}

AUTO-CALIBRATE

/*!
 *    @brief  Quick starting allows an instant 'auto-calibration' of the
 battery. However, its a bad idea to do this right when the battery is first
 plugged in or if there's a lot of load on the battery so uncomment only if
 you're sure you want to 'reset' the chips charge calculator.
 */
void Adafruit_MAX17048::quickStart(void) {
  Adafruit_BusIO_Register mode_reg =
      Adafruit_BusIO_Register(i2c_dev, MAX1704X_MODE_REG);
  Adafruit_BusIO_RegisterBits quick_bit =
      Adafruit_BusIO_RegisterBits(&mode_reg, 1, 6);
  quick_bit.write(true);
  // bit is cleared immediately
}

Which "Arduino" are you using?

Controller - Adafruit Feather RP2040
Battery Monitor - Adafruit Max17048
Battery - 3.7V 2500mAh battery

Communication is I2C.

It seems to me that the problem is in the library, in this function below: It predicts that the ADC value is 10 bits. (return percent / 256.0;), it returns the value divided by 256. But if the "Arduino" is 12 bits, then the calculation will be wrong.

float Adafruit_MAX17048::cellPercent(void) {
  if (!isDeviceReady())
    return NAN;
  Adafruit_BusIO_Register vperc =
      Adafruit_BusIO_Register(i2c_dev, MAX1704X_SOC_REG, 2, MSBFIRST);

  float percent = vperc.read();
  return percent / 256.0;
}

PS: as expected the 2040's ADC is 12-bit

1 Like

Isn't 10 bit ADC 1024 resolution?

Yes, you are sure, 1024 is 10 bits.

Can you temporarily modify the library, removing the value 256,
and seeing what value it prints?

Batt Voltage: 3.507 V
Batt Percent: 299.00 %

I find this in MAX1704X datasheet:

The SOC register is a read-only register that displays
the state of charge of the cell as calculated by the
ModelGauge algorithm. The result is displayed as a
percentage of the cell’s full capacity. This register
automatically adapts to variation in battery size since
the MAX17043/MAX17044 naturally recognize relative
SOC. Units of % can be directly determined by observing only the high byte of the SOC register. The low byte
provides additional resolution in units 1/256%. The
reported SOC also includes residual capacity, which
might not be available to the actual application because
of early termination voltage requirements. When SOC()
= 0, typical applications have no remaining capacity.
The first update occurs 125ms after POR of the IC.
Subsequent updates occur at variable intervals
depending on application conditions. ModelGauge calculations outside the register are clamped at minimum
and maximum register limits. Figure 4 shows the SOC
register format.

It's a float so it could be less than 0
Adafruit is not always correct.
ADC has nothing to do with it.

What is the tolerance of the parts you’re using? Also, what is the calibration status of your meter, and is it currently in calibration? The difference you’re observing seems to be a result of a stack-up of tolerances.

I appreciate the help so far on helping me troubleshoot my battery monitor. I just realized I am getting a Chip ID of 0xC.

The battery monitor has a print on it that says I2C address is 0x36.

I must be getting something wrong with the wire.begin for I2C.