Using Analog pin for battery voltage detection

Discussion about writing software for VS1005 and the VSOS Operating System. Also posts about VS1005-related hardware design and device drivers should be posted here.
treverwagenhals
Senior User
Posts: 21
Joined: Thu 2018-03-01 15:45

Using Analog pin for battery voltage detection

Post by treverwagenhals »

Hi all,

As the title explains, I would like to use one of the available analog pins to determine the battery voltage so that I can monitor it.

I read through this thread:

viewtopic.php?f=8&t=2065&p=11044&hilit= ... ead#p11044

but it didn't seem to specify what chipset they were implementing on. I don't know if this is a generic function that can be used across all chips or not. It seems to make reference to the Hi-res Player, which is based off of the VS1005 so it should be a fairly simple edit if so.

Anyway, is this implementation usable for my purposes? If not, is there an example of voltage monitoring on an analog pin for the VS1005 that is readily available? If not, how can I effectively implement my own solution?
Hannu
VLSI Staff
Posts: 526
Joined: Mon 2016-05-30 11:54
Location: Finland
Contact:

Re: Using Analog pin for battery voltage detection

Post by Hannu »

Hello!

The Hi-Res player monitors the battery voltage so it can be done. The best example can be found from VS1010.
viewtopic.php?f=15&t=2131 Only differences are the ANA_CFx registers. To enable SAR you need to use PERIP(ANA_CF1) |= ANA_CF1_SAR_ENA; Rest of the code isn't that much chip specific.

You can also search the implementation from the hires player sources.

If you use external resistor divider, it consumes power all the time. If you take power straight from the battery to VHIGH, you can measure it too. VHIGH has internally connected SAR channel.
User avatar
Panu
VSDSP Expert
Posts: 2829
Joined: Tue 2010-06-22 13:43

Re: Using Analog pin for battery voltage detection

Post by Panu »

That's right. The VS1010 ReadVoltage - GetBatteryVoltage example, to which Hannu linked to, is in fact derived from the VS1005 Hi-Res player code. The Hi-Res player uses an analog pin to measure the battery voltage because it wants to measure the battery voltage ALSO when USB power is connected. And then VHIGH is obviously in the USB voltage and measuring VHIGH is pretty much useless.

So the external voltage divider is needed to measure the battery when USB is present and VHIGH is at 5 volts. It drains a couple of microamperes from the battery, decreasing the self discharge time a little. That's unfortunate, but I felt that I can live with it.

-Panu
treverwagenhals
Senior User
Posts: 21
Joined: Thu 2018-03-01 15:45

Re: Using Analog pin for battery voltage detection

Post by treverwagenhals »

Thanks for the replies and guidance.

My particular solution uses a lithium battery with a voltage regulator to 5V. I was planning on connecting the battery directly to an AUX pin to read the value.

My followup question then is that I saw the voltage rating for the AUX pins is 3.6V. This is the nominal voltage for lithium cell batteries, however they do charge up to 4.2V. If I connect the battery directly to the pin, is that okay? Will voltages above the stated 3.6V cause damage, or simply cause the 10-bit value to be all 1's? I am fine with reading all values above 3.6V as 3.6V, but I don't want to damage the board. If damage is a concern, I would assume that I would just create a voltage divider to bring it back to safe values.
User avatar
pasi
VLSI Staff
Posts: 2120
Joined: Thu 2010-07-15 16:04

Re: Using Analog pin for battery voltage detection

Post by pasi »

3.6V is the maximum rating for the silicon process.

Also, if a voltage on the analog pin is above the AVDD voltage (or below AGND), current starts to flow through the protection diodes to try to protect the IC.

Measuring 4.2V would need a voltage divider.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
treverwagenhals
Senior User
Posts: 21
Joined: Thu 2018-03-01 15:45

Re: Using Analog pin for battery voltage detection

Post by treverwagenhals »

Thanks again for the quick response.

I have a quick question in regards to implementation of this code now.

I would like to take the solution as mentioned and have it run as a separate task that spends the majority of the time asleep and once every few minutes wakes up to check the voltage to see the battery life.

From the Playfiles driver, I see that the Startask() function is used to created a separate task for the audio decoding so that it may run in the background. This lets me know that the Startask() function is what I want to use.

The second parameter passed is the function to run in the background. In the case of the audio decoding in playFiles, it is the playerThread function. In my case, I would name it something along the lines of monitorVoltage(). So, now my command looks something like:
StartTask(TASK_DECODER, monitorVoltage)

From what I read the task_decoder variable has something to do with specifying the memory for the task. My question then is if I am allowed to have two tasks running, both with the TASK_DECODER variable passed? If not, what are the other possibilities here that will allow both to work at the same time?

Also, I see in the programmer documentation that it says the DELAY() function is used to release the CPU for a specified time. This is what I want to do, so I would place that within my monitorVoltage() function somewhere. I just wanted to verify that this function actually places the task to sleep and does not continue to waste power through busy waiting, like a for loop would do.

Thanks in advance for all the help.
Hannu
VLSI Staff
Posts: 526
Joined: Mon 2016-05-30 11:54
Location: Finland
Contact:

Re: Using Analog pin for battery voltage detection

Post by Hannu »

You need to allocate the task memory space.

From auxplay:
struct TaskAndStack *taskAndStack = NULL;
taskAndStack = CreateTaskAndStack(AudioTask, "AUXPLAY", 256, 2)
And the auxplay task starts. See AUXPLAY solution

After task has exited: FreeTaskAndStack(taskAndStack);

However... I as you already said, the monitor is sleeping most of the time, you could use cyclic interface

Code: Select all

#include <cyclic.h>
void MyCyclicFunc(register struct CyclicNode *cyclicNode) {
 // ....
}
struct CyclicNode myCyclicNode = {{0}, MyCyclicFunc};
ioresult main() {
  // ...
  AddCyclic(&myCyclicNode, TICKS_PER_SEC/10, TICKS_PER_SEC/10);
  // ...
}
void fini() {
  DropCyclicNode(&myCyclicNode)
}
treverwagenhals
Senior User
Posts: 21
Joined: Thu 2018-03-01 15:45

Re: Using Analog pin for battery voltage detection

Post by treverwagenhals »

Thanks again for the information. I may stick to the first approach rather than use the Cyclic command.

Quick testing gives me unexpected results. When I run a modified version of the provided code, I have an RCAP and AUX value of 438. Since they are both 438, the voltage reported ends up being 1.66. This seems okay, I just need to subtract the 1.66 from the value to get back to the value I expect then.

However, when I connect IOVDD to the analog pin, the value changes to AUX = 646 and voltage = 2.45. I'm expecting 3.3V + 1.66V as the output for it to be correct.

I don't know if this is an issue with the AUX value I am receiving back or if it is an issue with the resolution of each bit. For example, that 200 difference in AUX could be used to to calculate the LSB value and then scale it appropriately to 3.3V. I haven't tried other voltage values yet to determine if that is the case, but it seemed off regardless.

I provided my very minimally modified code to look at.

Code: Select all

#define SAR_AUX2 (0x0 << 8) 
#define SAR_RCAP (0x8 << 8)

s_int16 GetSarValue(register u_int16 channelShifted) {
	// Configure SAR and start the conversion. 
	PERIP(SAR_CF) = SAR_CF_ENA | (10) | channelShifted;
	// Wait until the conversion is complete.
	while (PERIP(SAR_CF) & SAR_CF_ENA);
	// Return the conversion result (0...4095)
	return PERIP(SAR_DAT);
}


void monitorVoltage(void)
{
	u_int16 sar_aux, sar_rcap;
	float volts;

    //while (1)
    //{
        // Read the AUX channel level using the SAR.		
        sar_aux = GetSarValue(SAR_AUX2);
        // Read also the reference voltage using SAR. Since the reference voltage is
        // known, this protects against inaccuracies caused by fluctuations in the
        // analog supply voltage.
        sar_rcap = GetSarValue(SAR_RCAP);
        
        // Remove the commenting to print the raw SAR values.
        //printf("aux=%4d,  rcap=%4d  ",sar_aux,sar_rcap);
        
        // Convert SAR_AUX conversion result to millivolts using the resistor
        // divide factor and a known 1.662V reference voltage (RCAP).
        // Resistor divide factor (1M vs 2M) * bandgap voltage (1.662 millivolts)
        sar_aux = ((s_int32)sar_aux * 1662) / sar_rcap; 
        // Convert integer millivolts to float volts.
        volts = sar_aux * 0.001;	
        printf("Voltage: %2.2f\n",volts);
    //    Delay(FIVE_MINUTES); // Only check voltage once every 5 minutes
    //}
}

int main(char *filespec) {
	FILE *fp = NULL;
	static char fnumMode[10];
    PERIP(ANA_CF1) |= ANA_CF1_SAR_ENA; // Powers and enables the SAR
	ioctl(stdaudioout, IOCTL_AUDIO_SET_VOLUME, (void *)(volume+256));
    
    monitorVoltage();

    ...
}
User avatar
Panu
VSDSP Expert
Posts: 2829
Joined: Tue 2010-06-22 13:43

Re: Using Analog pin for battery voltage detection

Post by Panu »

Any measured voltages are valid only between 0 and AVDD. Can you measure the value of AVDD with a multimeter just to be sure everything is powered up properly?

-Panu
User avatar
pasi
VLSI Staff
Posts: 2120
Joined: Thu 2010-07-15 16:04

Re: Using Analog pin for battery voltage detection

Post by pasi »

Which value do you get when AUX is connected to GND?

If you don't have anything connected to a pin, it probably biases to the reference voltage, which is why you get the same value for the reference voltage and the other input.

And like Panu asks, what are you measuring for IOVDD and AVDD voltages with multimeter?
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
Post Reply