Possible to detect a low supply voltage condition?

Does the wixel’s processor have any built in way of knowing when its supply voltage is getting lower than an acceptable threshold? I have several strategies in my app to help guard against excessively draining my battery, such as going to low current sleep mode if there is no activity detected after a specified time. But it would be nice to go a step further and immediately jump into sleep mode if a low voltage (brown-out?) condition were detected.

Perhaps I could do something like this using the A/D capability, but it would be very tricky to do that in my app because every single I/O pin is already being used. I guess I could add an external power management chip too, but the best thing would be if the CPU already has some awareness of a low voltage condition, so I could periodically read and respond to it.


You might be able to use the internal 1.25 V source as a reference to detect a low supply voltage condition. More information on using the internal reference voltage can be found on the Analog-to-Digital Converter library page.

- Jeremy

Thanks Jeremy. based on your advice, I thought maybe the adcReadVddMillivolts() might be a good start for me, since it does not seem dependent on actually setting up a pin as an A/D input. Looking at what it returns via USB basedf diags, I’m not sure I understand its return value (about 7496 powered from the USB port). But if its a predictable number I can use for comparison, maybe it will be useful!

Now I have to rig a USB cable without its power wire, so I can watch and see how the value drops when powered by battery, as the battery voltage drops!

I think you should try to figure out why you are getting 7496 from adcReadVddMillivolts. I just double-checked the math in its implementation and it seems correct to me. It calls adcRead to read the voltage of the VDD/3 line using the 1250 mV internal reference. The maximum reading is 2047, so the answer from adcRead will be (VDD/3) * (2047/1250). Solving for VDD, we get VDD = adcRead31250/2047, which matches the code. The test_adc app in the Wixel SDK reports the return value of adcReadVccMillivolts, so maybe you could try running that.


Thanks Dave. You were right… dumb programming error on my part. I get more like 3300 now, give or take.

Now I have to figure out a way to use the LEDs to indicate this value to me so i can see the reading as the wixel approaches the threshold of unacceptable low operating voltage. ! can’t use the USB to monitor, because even with a “doctored” usb cable ( that gets its VDD from a jumper back to the battery), the USB communication back to the PC drops out with a supply of about 3.8 volts. I know from my existing LED indications that my program is running down to a much lower voltage, so… back to the old flashing LED tricks!

I’ll report again when I get a better handle on this. Someone else using battery power may also wish to drop into sleep mode when a low voltage condition is sensed.

Tell me… to watch the 3v3 voltage slowly drop off, should I be recalibrating continually, as in…

while (1)
uint16 vddMillivolts = adcReadVddMillivolts();
adcSetMillivoltCalibration(vddMillivolts); // ???

displayVoltageSomehow(vddMillivolts );


OK this worked out very well! As i said in my last post, i had to create a little routine to signal the voltage to me through the LEDs, and indeed I could see and prove that the wixel could keep operating even slightly below 2 volts. This (ugly) routine can be called continually from a main() loop. It flashes 3 digits, 1/2 second apart. Make the REP_SPEED higher to make it easier to see the flashed digits. Of course this is intended to show the wixel’s 3V3 voltage when powered by a battery (or variable test supply), so the USB is normally unconnected. So the routine simply returns when the USB is connected.

[code]#define NUM_DIGITS 3
#define REP_SPEED 60

void monitorVoltage()
static uint32 timer =0;
static XDATA uint16 mv;
XDATA char report[10];
XDATA uint16 i, n;
uint32 timeNow = getMs();

if (timer == 0) timer = timeNow;

if ((timeNow - timer) < 1000L) return;
timer = timeNow;

if ( usbPowerPresent()) return;

mv = adcReadVddMillivolts();

sprintf(report, “%-4d”, mv);

for (i = 0; i < NUM_DIGITS; i++) // report 3 digits
n = (report[i] - ‘0’); // convert digit to number


But anyway, this is great! Now, in addition to an inactivity timer to force low power mode, i can further protect my battery by forcing sleep mode at some prescribed voltage. Of course I can only approximate the battery voltage at the measured 3V3 voltage level, plus .3 ~ .4 volt drop lost across the diode. But that’s fine. I can’t find exact data on it, but I imagine the radio transmission power must begin suffering anyway as the voltage goes down, so I’ll define a run time “param” variable so I can experiment and find the best cutoff.

Is there no end to this MCU’s tricks?? :slight_smile:


Calling adcSetMillivoltCalibration is OK but is probably not necessary for you. It only has an effect on the adcConvertToMillivolts function.


Well here I go again, resurrecting an old thread. My app is running on a little 200mAH LiPO cell, and I needed to warn the user when the cell was getting low. A LiPO cell charges to a max of about 4.2V, and can safely operated down to about 3.0 to avoid degrading the cell. So I was using adcReadVddMillivolts() to warn the user. It took a little experimentation to compensate for the shottky diodes, but it seemed to work.

Unfortunately the discharge curve of a LiPO cell is such that by the time it starts effecting the adcReadVddMillivolts() reading, you really don’t have much time left. It would be much better if I set up an A/D pin with a 1/2 voltage divider, to just read the VIN voltage directly. That way I can warn the user when the cell is at about 3.4V, half of which would be 1.7V ( well below the 3.3V reference).

Before I do this, I note that the Wixel already has a 100K resistor between VIN and P2-3, and I believe the wixel docs hint that the P2 pins might be internally pulled low. I don’t think the P2 pins can be used for A/D readings, but if I’m wrong please tell me, because it will make my task easier. I can just as easily re-do the math for a 100K resistor in series with the internal 20K pull down.

Hello. The P2_* pins on the Wixel cannot be used for ADC readings.