Read Vcc using Bandgap problem

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi there,

I need to measure the Vcc voltage using the intrnal Bandgap voltage. It's my first time I am doing this, so please correct me if I am saying something wrong, because I am not experienced in this mechanism.

Some info. about my circuit:
uC: AT90USB647-16AU
AREF pin: externally connected to an 100nF only.
AVCC pin: externally connected to an 100nF and also to VCC via a 10uH.
CPU clock: external crystal 8MHz

The Vcc varies from 4.0V up to 5.5V and I need to know this, that's why I am using this mechanism. Also I need to tell you that there is no need of high resolution.

My test code is:

adc_init(ADC_CHANNEL_BANDGAP, ADC_BITS_8, ADC_AVCC, NO_ADC_PIN, CPU_CLOCK_8MHz);

while(1){
	unsigned char index = 0;
	unsigned char array[16];

	array
= adc_8bit(ADC_CHANNEL_BANDGAP); if (++index > 16){ index = 0; } }

The function adc_init set the peripheral registers as:
ADMUX = 0x7E (Single Ended Input: Band Gap 1.1V, 8bit results, Reference: AVcc with external Cap on AREF pin)
ADCSRA = 0x86 (Input clock F: 125KHz, ADC Enable)
ADCSRB = 0x00
DIDR0 = 0x00
and also makes a dummy measurement on the sellected channel.

The results of my code are:

for Vcc = 4V:

array[0] = 85
array[1] = 77
array[2] = 73
array[3] = 72
array[4] = 72
array[5] = 72
array[6] = 72
array[7] = 72
array[8] = 72
array[9] = 72
array[10] = 72
array[11] = 72
array[12] = 72
array[13] = 72
array[14] = 72
array[15] = 72
for Vcc = 4.5V:

array[0] = 78
array[1] = 69
array[2] = 65
array[3] = 64
array[4] = 63
array[5] = 63
array[6] = 63
array[7] = 63
array[8] = 63
array[9] = 63
array[10] = 63
array[11] = 63
array[12] = 63
array[13] = 63
array[14] = 63
array[15] = 63
for Vcc = 5V:

array[0] = 74
array[1] = 63
array[2] = 58
array[3] = 57
array[4] = 57
array[5] = 56
array[6] = 56
array[7] = 56
array[8] = 56
array[9] = 56
array[10] = 57
array[11] = 56
array[12] = 56
array[13] = 56
array[14] = 56
array[15] = 56
for Vcc = 5.5V:

array[0] = 71
array[1] = 59
array[2] = 54
array[3] = 52
array[4] = 52
array[5] = 52
array[6] = 52
array[7] = 52
array[8] = 52
array[9] = 52
array[10] = 52
array[11] = 52
array[12] = 52
array[13] = 52
array[14] = 56
array[15] = 56

I have almost red this popular thread:
https://www.avrfreaks.net/index.p...

But I still have some questions:

1. How is it possible for the measurements to decreased as the Vcc increases. Is this Ok or I am doing wrong?
2. The measurement span is too small. For Vcc = 4V the ADC counts are 72 and for 5.5V they are 56. This means that there is only 1 count decrement for 100mV incement. Is this Ok? Is there any way of using all the 8bit result span (255 counts)?

Looking forward to hearing your suggestions.

Thank you.

Michael.

User of:
IAR Embedded Workbench C/C++ Compiler
Altium Designer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With an 8-bit read, the max count is 255, which represents AVcc.

Remember that the 1.1V is a nominal value; it might be 1.0 or 1.2. If important, you can do a one-time cal with a known AVcc value during "production". (that's what we do in one app to get a little closer than +/-10%.)

Vbg/Vcc = COUNTSbg/COUNTSvcc

Vcc = Vbg*Cvcc/Cbg
Vcc = Vbg*255/72
Vcc = 1.1*255/72
Vcc = 3.9V

As the first two terms are constant, for rough work 280 or 281 can be used.

280/63 = 4.4
280/56 = 5
280/52 = 5.4

There is always discussion on whether to use 255 or 256 in a case like this.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Is there any way of using all the 8bit result span (255 counts)?

Why don't you use all 10 bits of the ADC result?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, my functions are working ok.

Ok, there is no problem to use 10 bit results. I was thinking of using 8 bits just to save some RAM, because I need some measurements to make an average. But, Ok there is no problem. I am switching to 10 bits.

I still don't understand what the constant value 280 is???

Michael.

User of:
IAR Embedded Workbench C/C++ Compiler
Altium Designer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I still don't understand what the constant value 280 is???

I did the equation step-by-step above...check it out.

As you now know the characteristics of "waiting" for a good value, you can do something like discard a few conversions, and then do ten or 16 or 50 and simply add the conversion result to a total. At the end, use the average or the total itself. No SRAM usage to speak of.

//
//	"Raw" ADC sample parked here by the ISR
//
unsigned int			adc_raw;

//
//	n-sample total.
unsigned int			adc_total;

// Holding area for A/D value -- averaged over n samples
unsigned int			ad_value;

...
("rolling average" example)
// Rev. "k"  Try a much less sensitive average -- 1/16
	adc_total -= adc_total / 16;		// keep 15/16
	adc_total += adc_raw;				// and add in 1/16 from the new sample
	ad_value = adc_total / 16;			// and use composite rolling average

...

("accumulated total" example)
//
//	"Raw" ADC samples parked here by the ISR
//
unsigned int			adc_raw[ADC_CHANNELS];

//
//	50-sample total.  Every 10 ms."tick", adc_raw[] is added to adc_total[].
//	Every 500ms. "tock" (50 samples), the average is calculated and the area
//	used in the application code, ad_value[], is updated.
//
unsigned int			adc_total[ADC_CHANNELS];

...
(every 10ms)
//
// ***********
// ADC Data
// ***********
//
//	By every 10ms. there should be a fresh A/D reading on each of the channels.
//	(In fact, with the 57.6kHz ADC clock there are 72 conversions/tick, less
//		any ISR latency.  Even the 200kHz max. should work nicely.)
//
//	Add the raw sample to a running total for each 500 ms. tock.  Since there
//	will be 50 samples to average and each is 10 bits, it fits nicely into 16 bits.
//
		for (looper = 0; looper < ad_count; looper++)
			{
			#asm("cli");
			adc_total[looper] += adc_raw[looper];
			adc_raw[looper] = 0;
			#asm("sei");
			}

...
(every 500ms)
// ***********
// ADC Value
// ***********
//
//	adc_total[] now has a 50-conversion total.  Calculate the average into
//	ad_value[] for processing.
//
		for (looper = 0; looper < ad_count; looper++)
			{
			ad_value[looper] = adc_total[looper]/TICKS_PER_TOCK;
			adc_total[looper] = 0;
			}
//	Convert the signal average in A/D counts into units used for processing
//	svac -- supply VAC -- Volts AC
//	motor_current -- centiamps
//	temp_barrel & temp_storage -- degrees F * 10
...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok. Sorry for this stupid question.

Yes, for sure the first measurements are discarded.

Ok, I got it all.

theusch,

Thank you very much for all your help and time.

Michael.

User of:
IAR Embedded Workbench C/C++ Compiler
Altium Designer