Measure Vcc with ADC

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

Hi,

 

I implemented this application note to measure Vcc http://ww1.microchip.com/downloads/en/AppNotes/00002447A.pdf however I need to use 10bit resolution to be able to use it. If I use 8 bits resolution there are voltage levels where ADC doesn't change the ADC0.RES value and I can't understand why this happens.

 

Thank you

This topic has a solution.
Last Edited: Mon. Dec 2, 2019 - 05:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tell what voltage levels you are reading.  Show a complete test program that exhibits the symptoms. AVR model, toolchain, version, build settings, how you are testing, ...

 

Are you using ADLAR?

 

There is a very extensive thread, titled something like "avrs measure their own supply voltage but do it badly".  Check that out.  Lessee...

https://www.avrfreaks.net/forum/...

 

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

metRo_ wrote:
there are voltage levels where ADC doesn't change

What voltage levels are those???

Not sure why you would not use the full resolution of the ADC to get the most accurate voltage reading.

Jim

 

 

 

 

 

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

metRo_ wrote:
If I use 8 bits resolution there are voltage levels where ADC doesn't change the ADC0.RES value

Taking this to the extreme fictitious limit you could have written:

If I use 1 bit resolution there are voltage levels where ADC doesn't change the ADC0.RES value.

 

You should not be surprised about this behaviour.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint16_t ADC0_read(void) {
  /* Start ADC conversion */
  ADC0.COMMAND = ADC_STCONV_bm;

  /* Wait until ADC conversion done */
  while (!(ADC0.INTFLAGS & ADC_RESRDY_bm)) {
    ;
  }

  /* Clear the interrupt flag by writing 1: */
  ADC0.INTFLAGS = ADC_RESRDY_bm;

  return ADC0.RES;
}

void ADC_init() {
  VREF.CTRLA = VREF_ADC0REFSEL_1V1_gc;
  ADC0.CTRLC = ADC_REFSEL_VDDREF_gc | ADC_PRESC_DIV2_gc;
  ADC0.CTRLA = 1 << ADC_ENABLE_bp | ADC_RESSEL_8BIT_gc;
  ADC0.CTRLD = ADC_INITDLY_DLY128_gc;
  ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc;
  _delay_ms(10);
  /*ADC0_read();
  _delay_ms(10);*/
}

I'm using an Attiny402 with avr-gcc.

 

With 8 bits I should have Vcc/resolution = 3V/255 = 0.0117V and ADC.RES change on steps of ~0.2V

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

Where are you actually measuring the input voltage and how? Hopefully a DMM actually on the Vcc pin?

 

BTW if you use:

uint16_t ADC0_read(void) {
  /* Start ADC conversion */
  ADC0.COMMAND = ADC_STCONV_bm;

  /* Wait until ADC conversion done */
  while ((ADC0.COMMAND & ADC_STCONV_bm)) {
    ;
  }

  return ADC0.RES;
}

where you wait on ADC_STCONV_bm returning to 0, then the flag is "self clearing" (unlike the intflag). This is an exact parallel with the ADSC bit in the ADCRA register in traditional AVRs.

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

metRo_ wrote:
I'm using an Attiny402 with avr-gcc.

 

Yes and the example you mentioned doesnt work with tiny402. its not supported, please read carefully the appendix at page 14.

http://ww1.microchip.com/downloa...

 

It works only with some Tiny1 series. other than this you need to follow the normal way and put a voltage divider 1M ohm // 200K, something like this...

 

Dont waste your time, its mentioned its not supported.

 

Regards,

Moe

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

ofcurse it would be good to add also a smal cap at the input pin for measuring the voltage, something like 10nF....

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

Moe123 wrote:

metRo_ wrote:
I'm using an Attiny402 with avr-gcc.

 

Yes and the example you mentioned doesnt work with tiny402. its not supported, please read carefully the appendix at page 14.

http://ww1.microchip.com/downloa...

 

It works only with some Tiny1 series. other than this you need to follow the normal way and put a voltage divider 1M ohm // 200K, something like this...

 

Dont waste your time, its mentioned its not supported.

 

Regards,

Moe

 

It is working. This App Note isn't update since 2017 and Attiny402 support Vbg as input and VCC as VREF.

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

clawson wrote:

Where are you actually measuring the input voltage and how? Hopefully a DMM actually on the Vcc pin?

 

I have a DMM measuring the Vcc pin. It is working nicely with 10bits but the behavior with 8 bits is not expected.

 

clawson wrote:

BTW if you use:

uint16_t ADC0_read(void) {
  /* Start ADC conversion */
  ADC0.COMMAND = ADC_STCONV_bm;

  /* Wait until ADC conversion done */
  while ((ADC0.COMMAND & ADC_STCONV_bm)) {
    ;
  }

  return ADC0.RES;
}

where you wait on ADC_STCONV_bm returning to 0, then the flag is "self clearing" (unlike the intflag). This is an exact parallel with the ADSC bit in the ADCRA register in traditional AVRs.

 

Can you elaborate on this please?

 

Thank you

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


ATtiny402

 

 

 

ATtiny817

 

so....

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


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

metRO_ :

1- take a deep look at the pictures

2- Its written exactly in the app not that your chip is not supported.

 

I used your chip before and it was there since late 2016 I think, so saying the app note is old (2017) is not relevant here.

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

metRo_ wrote:
Can you elaborate on this please?
Not sure what you mean.

 

It's always been the case in all AVR that you have TWO ways to wait for ADC completion. One looks like:

int adc_read() {
    set_start_bit
    while(!int_flag);
    reset int_flag
    return reading;
}

the other is:

int adc_read() {
    set_start_bit
    while(start_bit);
    return reading;
}

The latter is simply "easier" as it relies on the fact that once set the start conversion bit remains set while the conversion is going on then that bit automatically resets itself (reads 0) when the conversion is complete. So, unlike doing it with the int_flag, there's no need for an additional "now clear flag" step at the end as the flag auto-cleared anyway.

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

metRo_ wrote:
With 8 bits I should have Vcc/resolution = 3V/255 = 0.0117V and ADC.RES change on steps of ~0.2V

Incorrect I'm afraid.

 

          1.1 * 255

Vdd = -----------------

           Counts

 

So picking 2 adjacent count values:

 

  1.1 * 255                                        1.1 * 255    

------------ == 3.016     ;     ------------ == 2.984

     93                               94

 

 

3.016 - 2.984 = 0.032

 

So my calculations mostly agree with your actual measurements. (The variation on 1.1V may well account for the difference of course)

 

 

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

N.Winterbottom wrote:
So my calculations mostly agree with your actual measurements.
How is 0.032 close to the " steps of ~0.2V " he says he observed. That's the best part of an entire order of magnitude out ? If you calculate 0.32 not 0.032 or he saw steps of 0.02 and not 0.2 then it could be considered "close"

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

Drat - drat and double drat. I blame tired eyes and hurried posting.

 

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


I did some measures for both 8bits and 10bits and the behavior is the same. For some reason I thought that for 10bits it was working as expected. Left is for 8bits resolution and left for 10bits.

 

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

Can't help noticing that your ADC data points are expressed as float. As the ADC actually returns a plain integer value (0..255 or 0..1023) then presumably you are post processing the data values in some way? Could that be in error?

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


clawson wrote:

Can't help noticing that your ADC data points are expressed as float. As the ADC actually returns a plain integer value (0..255 or 0..1023) then presumably you are post processing the data values in some way? Could that be in error?

 

I edit to show the ADC reg value:

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you tried slowing the ADC clock to see what effect that has on the accuracy?

 

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

Chuck99 wrote:

Have you tried slowing the ADC clock to see what effect that has on the accuracy?

 

I'll try it.

 

As you can see between 3.15V and 2.89V the ADC.RES register outputs always the same value.

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


Chuck99 wrote:

Have you tried slowing the ADC clock to see what effect that has on the accuracy?

 

 

CPU clock is 10MHz and before I was using a presacler of 2 now with 64 it is working as expected.

 

Thank you