Odd ADC results.

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

I'm using the Tiny84.
ADC clock = 125kHz
PWM is 10-bit Phase correct.
I have a routine that updates the ADMUX, starts a conversion, waits for it to complete, then writes the result to a variable. I'm outputting the ADC count to the OCR1A register, so I can see differences in my scope. I'm also using a PORTB register to trigger another pin for my scope so I can see when things are happening.

This first set of code gives ADC counts that are very irregular. The PWM duty is very jittery. From noise, etc, i'm sure.
That's why I built the for loop, to add averaging.

uint16_t adc2ct = 0;
uint16_t adcsum = 0;
int8_t i;

void setreadADC2()
  {
     PORTB = 0b00000100; 
     ADMUX = 0x82; // 0x82 = ADC2, 1.1 Vref
	adcsum = 0;
	i = 1;
//	for (i = 0; i < 1; i++)
//	{
	  ADCSRA |= _BV(ADSC);
	  while(ADCSRA & _BV(ADSC));
	  adcsum = adcsum + ADC;
//	}
	adc2ct = adcsum/i;

     PORTB = 0b00000000;
  }

However, if I just change the commenting, to the below. The ADC readings are rock solid.

uint16_t adc2ct = 0;
uint16_t adcsum = 0;
int8_t i;
void setreadADC2()
  {
    PORTB = 0b00000100; 
    ADMUX = 0x82; // 0x82 = ADC2, 1.1 Vref
	adcsum = 0;
//	i = 1;
	for (i = 0; i < 1; i++)
	{
	  ADCSRA |= _BV(ADSC);
	  while(ADCSRA & _BV(ADSC));
	  adcsum = adcsum + ADC;
	}
	adc2ct = adcsum/i;

     PORTB = 0b00000000;
  }

Isn't the adcsum still being divided by an int 1?

Jim M., Rank amateur AVR guy.

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

My copy of avr-gcc makes a poor job of optimising the second example (with -Os), it actually performs the division unlike the first code fragment.

Consider the possibility that different execution time may be affecting your circuit or measurements.

And why are adcsum and i global variables?

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

TimothyEBaldwin wrote:
My copy of avr-gcc makes a poor job of optimising the second example (with -Os), it actually performs the division unlike the first code fragment.

Consider the possibility that different execution time may be affecting your circuit or measurements.

And why are adcsum and i global variables?


Not sure. I made all of my variables that way. Should I not?

Jim M., Rank amateur AVR guy.

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

JimmyM wrote:
TimothyBaldwin wrote:
...Why are adcsum and i global variables?
Not sure. I made all of my variables that way. Should I not?
Maybe yes, maybe no. It is usually safer (especially for index variables like "i") to be local to the function in which they are used. After all, if the function foo() contains a for loop on "i", and inside that loop calls bar() which also contains a loop on "i", you can end up with really strange results.

Also, using local variables allows the compiler optimizer to potentially put these variables into registers, making access to them faster and the resulting code smaller.

Finally, global variables can be very confusing. Again, if you call foo() which calls gort() which calls grunge() which tweaks adcsum, and then use adcsum a little later at the top level, it can be easy to forget (or hard to learn, if you're the maintainer instead of the writer) where the value of adcsum is set.

As you may imagine, usage between global and local variables is a somewhat "religious" topic. Some swear that all global variables is the only way to go. Others swear that passing all variables up and down the function chain is the only way. In fact, it is a fine balance.

In the case of adcsum, making it global (at least for now) is probably okay. However, when you start using ISRs and changing global variables inside the ISR, be sure to make those variables "volatile". For the reason, read the AVR-libc Manual: Frequently Asked Questions (first question on the list) or Introduction to the "Volatile" Keyword.

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!