Challenges getting the PMIC up and running with an M SoM

I am trying to convince the M404 to play nicely with a BQ24195 PMIC and MAX17048 fuel gauge and am not having any luck. I am initializing with the correct settings I believe to get it to recognize that it is wired and connected to the I2C on D0 and D1 as expected. I am not getting errors, but am getting empty and/or incorrect (I believe) values.

The firmware is below:

// Include Particle Device OS APIs
#include "Particle.h"

system_tick_t lastSample = 0;
std::chrono::milliseconds sampleInterval = 5s;

// Let Device OS manage the connection to the Particle Cloud
SYSTEM_MODE(AUTOMATIC);

// Run the application and system concurrently in separate threads
SYSTEM_THREAD(ENABLED);

// Show system, cloud connectivity, and application logs over USB
// View logs with CLI using 'particle serial monitor --follow'
SerialLogHandler logHandler(LOG_LEVEL_INFO, {
  {"app.rtc", LOG_LEVEL_TRACE},
});

enum DeviceState {
  STARTUP,
  IDLE,
  TEST,
};

DeviceState nextState = STARTUP;

// setup() runs once, when the device is first turned on
void setup() {
  Cellular.prefer();

  // Configure the PMIC
  // See: https://docs.particle.io/reference/device-os/firmware/#power-manager
  SystemPowerConfiguration conf;

  conf.batteryChargeVoltage(4210)
      .batteryChargeCurrent(850)
      .powerSourceMaxCurrent(2000)
      .feature(SystemPowerFeature::PMIC_DETECTION)
      .feature(SystemPowerFeature::USE_VIN_SETTINGS_WITH_USB_HOST);

  int res = System.setPowerConfiguration(conf);
  Log.info("setPowerConfiguration=%d", res);

  // Put initialization like pinMode and begin functions here
  Serial.begin(9600);
}

// loop() runs over and over again, as quickly as it can execute.
void loop() {

  if (millis() - lastSample >= sampleInterval.count()) {
    lastSample = millis();

    PMIC power(true);
    
    Log.info("Current PMIC settings:");
    Log.info("VIN Vmin: %u", power.getInputVoltageLimit());
    Log.info("VIN Imax: %u", power.getInputCurrentLimit());
    Log.info("Ichg: %u", power.getChargeCurrentValue());
    Log.info("Iterm: %u", power.getChargeVoltageValue());

    int powerSource = System.powerSource();
    int batteryState = System.batteryState();
    float batterySoc = System.batteryCharge();

    constexpr char const* batteryStates[] = {
        "unknown", "not charging", "charging",
        "charged", "discharging", "fault", "disconnected"
    };
    constexpr char const* powerSources[] = {
        "unknown", "vin", "usb host", "usb adapter",
        "usb otg", "battery"
    };

    Log.info("Power source: %s", powerSources[std::max(0, powerSource)]);
    Log.info("Battery state: %s", batteryStates[std::max(0, batteryState)]);
    Log.info("Battery charge: %f", batterySoc);

    FuelGauge fuel;

    Log.info( "voltage=%.2f", fuel.getVCell() );
    Log.info( "SoC=%.2f", fuel.getSoC() );
  }  

}

Example output is below:

0000230000 [app] INFO: Current PMIC settings:
0000230012 [app] INFO: VIN Vmin: 3880
0000230022 [app] INFO: VIN Imax: 1500
0000230032 [app] INFO: Ichg: 832
0000230041 [app] INFO: Iterm: 4208
0000230052 [app] INFO: Power source: unknown
0000230063 [app] INFO: Battery state: not charging
0000230075 [app] INFO: Battery charge: 0.046875
0000230087 [app] INFO: voltage=3.32
0000230098 [app] INFO: SoC=0.04

When I measure the LiPo voltage with a multimeter, I get 3.67V. I can add the schematic if helpful - otherwise, it is being powered by USB, VIN, and BAT. Any help or pointers on where to look would be appreciated!

An aside: it looks like the "tags" need to be updated to include more recent hardware!

What was the result code from setPowerConfiguration()? You will probably need to add a waitFor(Serial.isConnected(), 10000) before it.

It returns 0.

Anything else I can look into, probe, or try @rickkas7?

I'm not sure about the PMIC settings, but the reason the fuel gauge doesn't work is that the MAX17048 is not sufficiently compatible with the MAX17043, and Device OS only knows how to communicate with the MAX17043.

In particular, the scale of the SoC result is different on the MAX17048, which is why the numbers are very wrong, but seem to be retrievable without error.

You may need to put the power manager in manual mode and manage it yourself if you need to use the MAX17048. Device vitals, system charging indicator, and SoC will return the wrong information, but you should at least be able to get it running.

For the PMIC, there is a possibility that Device OS is overriding your setting, so I'd first try setting the power manager into SystemPowerFeature::DISABLE mode and see if the setting change sticks in that mode.

Hmm. I tried disabling the PMIC and testing out a separate library for the MAX17048 and it reads the same values that the onboard Particle DeviceOS did. I'll probe a bit more tomorrow to see if I can figure out what's going on. It does look setting SystemPowerFeature::DISABLE did take though, which is good. I can swap to the MAX1403 for production, but am unconvinced there aren't additional issues at the moment.