How to Monitor VUSB on the Electron?

So I’d like the Electron to tell me if my mains supply has failed. The most obvious way to do this is to hook a USB mains adapter and then monitor the +5v that should be present on the “VSUB” test point. My question is can I read this information internally from the Electron or would I need to bring this back in I/O port? Am I OK to leave the USB supply and 3.7v battery permanently connected? I know this will only tell me if the adapter is working, not a true mains reading but it will do for my purposes.
Thanks…

You can also just check to see if the Electron is USB powered. This will be inexact - you likely won’t see momentary drops in main power because most USB power supplies will smooth over these, but you will certainly see anything longer than a few seconds. And it doesn’t even require any additional hardware - you can do it entirely in software on the Electron!

#include "Particle.h"

bool isUsbPowered(); // forward declaration

PMIC pmic;
bool lastPowerState = false;


void setup() {
	pmic.begin();
}

void loop() {
	bool powerState = isUsbPowered();
	if (powerState != lastPowerState) {
		Particle.publish("usbPowered", (powerState ? "true" : "false"), 60, PRIVATE);
		lastPowerState = powerState;
	}

	delay(2000);
}

bool isUsbPowered() {
	byte systemStatus = pmic.getSystemStatus();

	return ((systemStatus & 0xc0) == 0x40);
}

/*
//System Status Register
//NOTE: This is a read-only register
REG08
BIT
--- VBUS status
7: VBUS_STAT[1]	| 00: Unknown (no input, or DPDM detection incomplete), 01: USB host
6: VBUS_STAT[0]	| 10: Adapter port, 11: OTG
--- Charging status
5: CHRG_STAT[1] | 00: Not Charging,  01: Pre-charge (<VBATLOWV)
4: CHRG_STAT[0] | 10: Fast Charging, 11: Charge termination done
3: DPM_STAT		0: Not DPM
				1: VINDPM or IINDPM
2: PG_STAT		0: Power NO Good :(
				1: Power Good :)
1: THERM_STAT	0: Normal
				1: In Thermal Regulation (HOT)
0: VSYS_STAT	0: Not in VSYSMIN regulation (BAT > VSYSMIN)
				1: In VSYSMIN regulation (BAT < VSYSMIN)ault is 3.5V (101)
0: Reserved
 */
3 Likes

Thanks my freind,

Just what I was looking for.

Smashey

@rickkas7 :
I tried this code and it works as expected when powered from a USB from a computer.

However if I powered it from a USB adapter like an iPhone charger, even if the red charging LED turns on, isUsbPowered() still returns false!!!

I tried this on several adapters and it’s the same result… And also on several computers where the status does come as expected!

Any clues on how to fix this or am I doing something wrong?

You’re right, it doesn’t work properly with power adapters. I tested the obvious fix (it should also check for 0x80) but that didn’t work either, so I’ll have to go back to the data sheet and do some more investigating why that would be.

Thank you @rickkas7

I saw the comments of status register in the source code of the firmware where it specifies what the systemStatus register.

Quick question…

How do you know which register to check. I see you check if == 0x40, how does that maps to VBUS_Stat?

This are the comments:

BIT
--- VBUS status
7: VBUS_STAT[1]	| 00: Unknown (no input, or DPDM detection incomplete), 01: USB host
6: VBUS_STAT[0]	| 10: Adapter port, 11: > OTG
--- Charging status
5: CHRG_STAT[1] | 00: Not Charging,  01: Pre-charge (<VBATLOWV)
4: CHRG_STAT[0] | 10: Fast Charging, 11: Charge termination done
3: DPM_STAT		0: Not DPM
				1: VINDPM or IINDPM
2: PG_STAT		0: Power NO Good :(
				1: Power Good :)
1: THERM_STAT	0: Normal
				1: In Thermal Regulation (HOT)
0: VSYS_STAT	0: Not in VSYSMIN regulation (BAT > VSYSMIN)
				1: In VSYSMIN regulation (BAT < VSYSMIN)ault is 3.5V (101)
0: Reserved

If I want to check for example fast charging, CHRG_STAT[0]. What would you check for in the if statement?

1 Like

It’s an 8-bit value in the register, and the bits are numbered where 7 is the MSB and 0 is the LSB. So VBUS_STAT is bit masks 0x80 and 0x40. CHRG_STAT is bits 0x20 and 0x10. DBM_STAT is bit 0x08. Another way to look at it is:

int chrgStat = (systemStatus >> 4) & 0x03;

This will give you a value of 0, 1 (0b01), 2 (0b10), or 3 (0b11) that correspond to not charing, pre-charge, fast-charging and charge termination done, respectively.

@rickkas7 Great info!

Quick question:
Why do you do the (& 0x03) ??

I know that the >> 4 is to shift it for the 4th bit. but then the value, you do an & operation with 0x03… So I guess this is to convert it to int?

It’s because once you shift the systemStatus 4 to the right, you have both VBUS_STAT and CHRG_STAT remaining. The logical AND with 0x03 takes the lowest two bits (CHRG_STAT) and removes VBUS_STAT.

Thank you for the lesson @rickkas7 , sorry for me asking too much :smile:

And If I wanted to get VBUS_STAT?

Is it & 0x40 ??

No problem!

int vbusStat = (systemStatus >> 6) & 0x03;

That returns the the values 0 (0b00) unknown, 1 (0b01) usb host, 2 (0b10) adapter port, or 3 (0b11) otg

Got it! So you always want the lower to bits in a shift… Unless?? You are getting the last two bits?

The & 0x03 might have been unnecessary when getting VBUS_STAT since it is the last two bits, but I generally put it in anyway, just in case, because sign extension of negative values can result in 1 bits where you might not expect them.

1 Like

Thank you @rickkas7 No more questions :smile:

Good info here on detecting USB power but I’m also experiencing the same thing when detecting USB power from an adaptor as opposed to a USB port on laptop. No idea why it would be different. @rickkas7 or @friobo, did you guys came up with a solution to detecting power when using a charging block.

I have a newer version of the code that work with chargers in this post:

Basically, using PG_STAT works better than VBUS_STAT, however that catch is that you can't tell the difference between a USB charger and powering by VIN.

		byte systemStatus = pmic.getSystemStatus();
		if ((systemStatus & 0x04) != 0) {
			// Bit 2 (mask 0x4) == PG_STAT. If non-zero, power is good
			// This means we're powered off USB or VIN, so we don't know for sure if there's a battery
2 Likes

Thank you @rickkas7. Haven’t implement but I read thru your code and it makes sense. Surprisingly tricky to simply detect charger block power.

1 Like

Note: the source code for the PMIC can be found at [firmwareversion]/wiring/src/spark_wiring_power.cpp.

Here is the code snippet I’m using to detect Vin/usb availability

PMIC power_management;
bool powerStatus = false;
// checks if input power is OK (usb/Vin)
powerStatus = power_management.isPowerGood();
1 Like