Understanding PWR and CHG on a Xenon

Can anyone help clarify the meaning of the PWR and CHG digital pins on a Xenon? From reading the forums, I have picked up the following:
CHG active low, high when there is power coming from USB.
PWR && !CHG will provide the actual charging status.

From that I’m assuming that means:
CHG = 0 - Charging
CHG = 1 - Not charging
PWR = 0 - No USB power
PWR = 1 - USB Power

0 | 0 | No USB power, battery charging
0 | 1 | No USB power, battery not charging
1 | 0 | USB power, battery charging
1 | 1 | USB power, battery not charging

I currently have a solar panel connected via a INA219 module where I can read the incoming voltage (busVoltage). The load goes to the VUSB pin on my xenon. As it got dark this evening, I recorded:
17:00 : Bus voltage 2.96. PWR=1, CHG=1 - USB power, battery not charging
17:19 : Bus voltage 2.09. PWR=1, CHG=0 - USB power, battery charging
17:21 : Bus voltage 1.96. PWR=0, CHG=0 - No USB power, battery charging

Looking at that, it suggests that CHG is 1 when charging and 0 when not. I would expect that it was receiving power and charging at 17:00, the sunlight dropped to where VUSB power was detected but not enough to charge the battery and 2 minutes later the solar cell neither charged or powered the battery.

The truth table above says the battery only charged for 2 minutes as it was getting dark, which does not make much sense.


This is the code I use in a Xenon to determine the battery SoC and power state.

// Determines powerState: [BATTERY, MAINS, RECHARGING] from reading digital pins PWR and CHG
// Determines SoC: [UNKNOWN, EMPTY, RECHARGE, NOMINAL, FULL] battery voltage level from reading analog pin BATT
void checkBattery()
    batteryVoltage = analogRead(BATT) * 0.0011224;
    if (batteryVoltage >= 4.1)      SoC = FULL;
    else if (batteryVoltage >= 3.7) SoC = NOMINAL;
    else if (batteryVoltage >= 3.6) SoC = RECHARGE;
    else if (batteryVoltage >= 3.3) SoC = EMPTY;
    else                            SoC = UNKNOWN;
    powerState = (digitalRead(PWR) == 1)?((digitalRead(CHG) == 0)?RECHARGING:MAINS):BATTERY;

The main difference in the logic is that if PWR is 0 then it is battery. If PWR is 1 then it may be recharging or not. Do you have a diode on the solar panel output or a voltage regulator?

I should have added a diode, so have just done that now.

It is currently reading 3.7v in, PWR=1, CHG=1.

Your code suggests the same as what I read, that CHG should be zero when charging.

Key point is that PWR = 0 and CHG = 0 is not relevant whereas the rest of what you had understood was correct.

I used the following:

  pinMode(PWR, INPUT);
  pinMode(CHG, INPUT);

  charge = (digitalRead(PWR) && !digitalRead(CHG));  // 0 = Not Charging
  onBatteryPower = (!digitalRead(PWR));              // 0 = Not on Battery Power


  • If a Solar Xenon’s charge cycle is interrupted, it wont resume charging until the Li-Po drops below 4.05V.
  • If both charge and onBatteryPower are “0”, the Panel is providing the operating current for the Xenon.
  • voltage = analogRead(BATT) * 0.0011224; will be incorrect under certain conditions.
  • This Thread has more details at the time (and firmware version) of my testing.

Thanks for the info, I have added your code to mine so now the full source is

float batVolts;
char jsonOut[255];

void setup() {


    // Check power and charging status
    pinMode(PWR, INPUT);
    pinMode(CHG, INPUT);


void loop() {
    float busVoltage = 0;
    float current = 0; // Measure in milli amps
    float power = 0;

    busVoltage = sensor219.getBusVoltage_V();
    current = sensor219.getCurrent_mA();
    power = busVoltage * (current/1000); // Calculate the Power    
    int inputPwr, inputChg, charge, onBatteryPower;
    batVolts = analogRead(BATT) * 0.0011224;


    charge = (inputPwr && !inputChg);  // 0 = Not Charging
    onBatteryPower = (!inputPwr);              // 0 = Not on Battery Power

    sprintf(jsonOut, "{'battery': %0.2f; 'busVoltage': %0.2f; 'current':%0.2f; 'power': %0.2f; 'devPower': %d; 'devCharge': %d; 'chargeStatus': %d; 'onBatteryPower': %d}",
        batVolts, busVoltage, current, power, inputPwr, inputChg, charge, onBatteryPower);
    Particle.publish("SolarTest", jsonOut, PRIVATE);


This gives an output of (on an east facing window sill in the afternoon on a day of light cloud)

{'battery': 3.98; 'busVoltage': 3.84; 'current':1.20; 'power': 0.00; 'devPower': 1; 'devCharge': 1; 'chargeStatus': 0; 'onBatteryPower': 0}

That suggests the panel is powering the xenon. This surprises me as I didn’t think the panel had enough power. However if I pull the battery out, I get the same result.

For interest, I added the output from the INA219 board I’m using to the micro USB connector, rather than the VUSB pin. That does not seem to make much difference.

I believe the Xenon only requires 32 mW, or 0.032 Watt.
That’s not a lot, even for a tiny 0.5 Watt panel (not sure what size Panel you’re using).

By removing the Li-Po, you confirmed the Xenon was being powered solely by the Panel :sunglasses:

Sorry, I typed rubbish there. I should have said that if I pull the battery out it powers down!

Not sure what I was supposed to be typing there.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.