Level 2
Level 2

Hi,

I have a 3.7V LiPo battery powering a PCB using a PSoC 6 MCU. I am trying to implement a simple battery voltage check in firmware, but for some reason when I scan the battery's channel, I am getting values like 1.07V, when measuring the battery by hand is giving ~4.13V.

My project has a lot of code separate from this issue, but I will try to share what I can.

I have

#define BATT_V_SCAN_CHANNEL 0

then in main loop I am calling

as far as I am aware, that is the basic code needed to get the output. I will also share my Scan_ADC config:

From what I know, it seems like it should be scanning the battery level in a range from 0.0V to 6.6V (0 to 2*Vref), and then converting the value to volts for reading, but the value I am receiving is much lower than the actual battery voltage.

I would really appreciate any advice!

1 Solution

Level 9
Level 9

Noah,

Two things to consider.

#1

The PSoC6 maximum operational voltage is 3.6V.  for VDDD and VDDA

VDDA and all analog inputs such not exceed VDDA.  Therefore your battery voltage input of 4.13V will have issues.  This is because any voltages on GPIO pins higher than VDDA will start to conduct current through the ESD diodes limiting the voltage at the pin to no more than VDDA+0.6V.  Additionally the input impedance will change and the worst thing is that you can damage the input (blowing the ESD diode due to excess current).

Yes.  I understand that 2*vref is allowed.  Assuming vref is set to VDDA and VDDA = 3.3V then one would assume 2*vref = 6.6V  Actually ... no.

The 2*vref is really to be used with vref = 1.024V which is a self-regulating band-gap reference.  Therefore in this case, 2*vref = 2.048V.  This is why the the 2*vref setting is available.

If you need to measure voltages higher than VDDA, you should use a resistor divider scheme to bring the resultant input voltage within VDDA range.   Using this the result then needs to be multiplied be the resistor divider factor.

For example :

If AIN = 4V then AIN_scaled = 2V.   Res_div factor = 2.

Once you read the ADC count you would need to multiply by Res_div to recover the actual voltage.

#2

Anyone who needs to have a relatively accurate ADC count output should never use VDDA as the vref for the ADC.  This is particularly true when you are using a battery powered PSoC.

The main reason is that the ADC uses the magnitude of vref to determine the ADC count.   The count is 'ratiometric' to the magnitude of VDDA.

For example: If VDDA is 3.6V (which can happen on freshly charged Li-Ion batteries), then a 1V analog input will have the ADC count of (1V/3.6V) *( 2^12) = 1137  for a 12-bit ADC.

However, if after many hours of use, VDDA drops to 2.0V then the ADC count = (1V/2.0V) * (2^12) = 2048 for the same 12-bit AC.

However if you use a band-gap vref like 1.024V, this voltage self-regulates very close to 1.024V across temperature.  The good thing is that this band-gap remains the same even if VDDA is 1.8V or up to 3.6V.   This keeps the ratiometric measurement of the ADC count consistent across the range of VDDA.

The band-gap vref is the closest thing you're going to get to an absolute reference.

Len
"Engineering is an Art. The Art of Compromise."
4 Replies

Moderator
Moderator

Hi Noah,

Your Vneg for Single Ended(S/E) is connected to reference voltage, which is VDDA in your case. Can you change that to VSSA and see whether you are getting expected results ?

Best Regards,
Vasanth

Level 2
Level 2

With this new configuration,

I am getting ADC_GetResult16 returning ~1290 and ADC_CountsTo_Volts returning ~2.09V, so still not quite the ~4.13V I am expecting.

Is the PSoC able to scan voltages above 3.3V?

Level 9
Level 9

Noah,

Two things to consider.

#1

The PSoC6 maximum operational voltage is 3.6V.  for VDDD and VDDA

VDDA and all analog inputs such not exceed VDDA.  Therefore your battery voltage input of 4.13V will have issues.  This is because any voltages on GPIO pins higher than VDDA will start to conduct current through the ESD diodes limiting the voltage at the pin to no more than VDDA+0.6V.  Additionally the input impedance will change and the worst thing is that you can damage the input (blowing the ESD diode due to excess current).

Yes.  I understand that 2*vref is allowed.  Assuming vref is set to VDDA and VDDA = 3.3V then one would assume 2*vref = 6.6V  Actually ... no.

The 2*vref is really to be used with vref = 1.024V which is a self-regulating band-gap reference.  Therefore in this case, 2*vref = 2.048V.  This is why the the 2*vref setting is available.

If you need to measure voltages higher than VDDA, you should use a resistor divider scheme to bring the resultant input voltage within VDDA range.   Using this the result then needs to be multiplied be the resistor divider factor.

For example :

If AIN = 4V then AIN_scaled = 2V.   Res_div factor = 2.

Once you read the ADC count you would need to multiply by Res_div to recover the actual voltage.

#2

Anyone who needs to have a relatively accurate ADC count output should never use VDDA as the vref for the ADC.  This is particularly true when you are using a battery powered PSoC.

The main reason is that the ADC uses the magnitude of vref to determine the ADC count.   The count is 'ratiometric' to the magnitude of VDDA.

For example: If VDDA is 3.6V (which can happen on freshly charged Li-Ion batteries), then a 1V analog input will have the ADC count of (1V/3.6V) *( 2^12) = 1137  for a 12-bit ADC.

However, if after many hours of use, VDDA drops to 2.0V then the ADC count = (1V/2.0V) * (2^12) = 2048 for the same 12-bit AC.

However if you use a band-gap vref like 1.024V, this voltage self-regulates very close to 1.024V across temperature.  The good thing is that this band-gap remains the same even if VDDA is 1.8V or up to 3.6V.   This keeps the ratiometric measurement of the ADC count consistent across the range of VDDA.

The band-gap vref is the closest thing you're going to get to an absolute reference.

Len
"Engineering is an Art. The Art of Compromise."