Power Shield: Detecting Power Source

Has anyone come up with a reliable way to programmatically determine if your Power Shield enabled Photon is being powered by the on-board battery or USB power?

I’m finding that monitoring the voltage and SOC variables are lagging.

1 Like

@abenzick, the power shield has two outputs, USPG and ACPG which are open drain outputs (will go to GND when active so need a pull-up otherwise). The USBG output indicates “good” USB power while ACPG indicates “good” AC Power which is really external power connected to the 2-terminal connector on the board. There are pads you can connect a wire between these output and an input pin on the Photon or Core.

Look at the docs diagram for details. :smile:

3 Likes

Totally missed that, thank you!

I have a Photon connected to a Powershield and am planning on using the battery as a backup with a USB wall-adapter providing the main power.

I have 1K resistor connected between the USBG pin and D2 on the Photon since you said it needs a pull-up resistor.
The Photon works okay and I’m getting believable values from the I2C batteryMonitor published to the Particle Cloud, but the value coming back from reading D2 is always 0, whether a USB cable is connected to the Powershield or not.
Thanks for any help or thoughts you might have about this.

Relevant code is below:( a good chunk of this was swiped from the Powershield Publish demo app :slight_smile:

#include "PowerShield.h"
PowerShield batteryMonitor;
int usbpg = 0;
int acpg = 0;

void setup() {
    
    pinMode(D2,INPUT);
    pinMode(D3,INPUT);
    // This essentially starts the I2C bus
    batteryMonitor.begin();
    // This sets up the fuel gauge
    batteryMonitor.quickStart();
    // Wait for it to settle down
    delay(500); //delay 0.5 second
}

void loop() {
    
     usbpg = digitalRead(D2);
     acpg = digitalRead(D3);
     
    // Read the volatge of the LiPo
    float cellVoltage = batteryMonitor.getVCell();
    // Read the State of Charge of the LiPo
    float stateOfCharge = batteryMonitor.getSoC();

    // Publish Cell Voltage to cloud
    Particle.publish("ps-voltage", String(cellVoltage));

    // Publish State of Charge to Cloud
    Particle.publish("ps-soc", String(stateOfCharge));
    
    Particle.publish("ps-usb", String(usbpg));
    Particle.publish("ps-ac",String(acpg));

    delay(60000);
}

That's not how a pull-up resistor is wired. It should go between power and the USBG pin. However, you can just get rid of that resistor, and set the pin mode of D2 to INPUT_PULLUP which will accomplish the same thing.

1 Like

If power is more than 3.3V you should not use internal pull-ups.

https://docs.particle.io/datasheets/photon-datasheet/#peripherals-and-gpio

My understanding of the open drain output of the USBG pin, is that it is either high-z , or pulled to ground, so does it matter what the power is? Shouldn't the D2 pin never "see" the power from the shield (whatever value that is)?

If you use internal pull-ups and have power supply more than 3.3V you’ll have a current flow from the higher voltage level to the internal 3.3V rail via the internal pull-up.

Since I’m not going to check what that power pin/source/whatever refers to, I just threw in the “warning”.


Update: Rereading your response clarified that your first statement what was to correct the understanding how to use an ext pull-up and the second was actually meant as a full substitute where there is no connection between power and USBG/D2 at all. In this case you can just scrap my comment :blush:

Hi Ric,
Thanks for responding. Would that be “Power” as in VIN or VBAT ?
I’m not using AC power. I have the 3.7 LiPO that came w/ the PowerShield attached to the little JST connector and a 5V USB wall-wart adapter plugged into the micro-USB port on the PowerShield.

I’ve tried tying USBG to VIN with a 1K resistor and then connecting D2 to that and I’m still getting a HIGH (1) signal back from reading D2 whether the USB cable is plugged into the PowerShield or not.

Sorry to be so thick about this at the moment, but I’m kinda stumped.

Forget the resistor entirely. Just connect the USBG pad to D2, and set D2 pinMode to INPUT_PULLUP. There should be no connection to any power (to USBG or D2) if you do it this way. I tested this, and I get values of 0 (LOW) with the USB plugged in, and 1 (HIGH) with no USB.

1 Like

That did it!
I thought I had done that to begin with, but maybe not.
Anyway, it works. Thanks Ric!

Hi, I wasn’t able to solve this with a floating pin. I kept getting low / high - very inconsistent. I used (sort-of) a voltage divider. As I understand it, there’s a 40kΩ resister in the D* pins. I connected a low-value resistor (2-300Ω) from 3.3v to the pin, then a direct connection from the pin to USBPG. When something grounds the USB port, the voltage flows to that and my pin drops below the high threshold. When it’s floating, my pin goes high. In code, I just say:

chargingUSB = !digitalRead(D5);
chargingAC = !digitalRead(D6);

I’m not an EE; however, it didn’t fry the board, get hot, etc, so I just thought I’d throw that out there.