interrupt driven adc with multiple channel selection help ..

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

i wanted to test the interrupt routine of the avr adc in which i wrote a simple program where i selected 2 channels of admux and stored the adc converted values of each channel in 1 variable but i got problem, the values of the adc were not consistent , i mean if i change the value of 1 channel , the value for other channel would also change.

IN NORMAL CONVERSION MODE U JUST WAIT UNTIL THE ADIF BIT IS SET BUT SINCE HERE IT IS CLEARED BY HARDWARE I DONT KNOW HOW TO KNOW IF A CONVERSION HAS BEEN MADE AND AN INTERRUPT HAS BEEN CALLED , PLZZ HELP ME SOLVE THIS PROBLEM

the code is like this

# include
#include 
#include
#include

unsigned int a,b,c;

int main(void)
 {
  ADCSRA|=(1<<ADEN)|(1<<ADATE);//enable adc & auto trigger
  ADCSRA|=(1<<ADPS1)|(1<<ADPS0);//set prescaler to 8
  ADCSRA|=(1<<ADIE);//enable interrupts
  SFIOR|=_BV(ADTS2)|_BV(ADTS1)|_BV(ADTS0);/free runnin
  sei();//enable global interrupts
  ADCSRA|=(1<<ADSC);//start adc conversion
  while(1)
   {

    c=1;


    ADMUX=0x61;//select channel 1


     c=2;

    ADMUX=0x62;//select channel 2

   }

	  return(0);
	
  }

  ISR(ADC_vect)
   {

     if(c==1)
	  {
	   a=ADCH;//write adc value of channel1 in a
	  }
	
	 if(c==2)
	  {
	   b=ADCH;//write adc value of channel2 in b

	  }
	}


iam using an atmega16 with internal 1mhz clock

Last Edited: Wed. Apr 9, 2008 - 06:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
while(1) 
   { 
    c=1; 
    ADMUX=0x61;//select channel 1 
     c=2; 
    ADMUX=0x62;//select channel 2 
   } 

This code will continually change the channel that is being read while the adc is doing its conversion. It is anyone's guess as to what the channel was set to when the conversion started. It is a 50-50 chance that the value of c when the the conversion ends is the same as when the conversion began.

Regards,
Steve A.

The Board helps those that help themselves.

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

i realised that but what should i do so that i will be able to update the values of a and b only when the right channel is chosen and only after the conversion ends??

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

isnt there any mechanism via which ill be able to know how to change channels for perfect readings in interrupt driven adc ??

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

I've posted my round-robin code before (for a different compiler brand). A recent post:
https://www.avrfreaks.net/index.p...

Summary of ISR operation:
-- Get the ADC value
-- Store in an array appropriate to the channel just converted
-- Set the ADMUX for the next channel
-- Start the next conversion

For slow-moving signals such as temperature and voltage, I then gather these samples and take a long-term (100ms, 500ms) average. This takes out most ripple. Posted in
https://www.avrfreaks.net/index.p...

There may be other considerations if reading a high-impedance signal.

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

now i read through the datasheet i found out that while in the interrupt mode the only way u can effectively change a channel is when the aden or adate bit is cleared or 1 cycle after the interrupt so i changed the code to this


# include
#include 
#include



unsigned int a,b,c,d;

int main(void)
 {
  ADCSRA|=(1<<ADATE);
  ADCSRA|=(1<<ADPS1)|(1<<ADPS0);
  ADCSRA|=(1<<ADIE);
  SFIOR=(1<<ADTS1);
  sei();
  c=1;
  ADMUX=0x61;

  ADCSRA|=(1<<ADEN);
  ADCSRA|=(1<<ADSC);

      while(1)
       {


	
	
	   }


	  return(0);
	}

ISR(ADC_vect)
   {

     if(c==1)
	  {
	  ADCSRA&=~(1<<ADEN);
	   a=ADCH;
	
	    c=2;
	    ADMUX=0x62;
	    d=ADMUX;
	    ADCSRA|=(1<<ADEN);
	    while(!(ADCSRA&(1<<ADIF)));
	
	
	
	
	
	
	  }
	
	 if(c==2)
	  {
	
	
	     ADCSRA&=~(1<<ADEN);
	   b=ADCH;
	
	    c=1;
	    ADMUX=0x61;
	    d=ADMUX;
	      ADCSRA|=(1<<ADEN);
	
	    while(!(ADCSRA&(1<<ADIF)));
	

	
	
	  }
	}





and it worked fine but i wanted to know will this code be reliable when using it in a very long algorithm where i need frequent adc values..

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

With the code you have now you get no advantage from using the interrupt (and will be spending a lot of time inside it).

  ADCSRA|=(1<<ADATE);

Are you sure you need this? I suggest you don't use auto trigger and manually restart the conversion in the interrupt, i.e., exactly what Lee is doing in the linked examples. There are no issues with updating ADMUX in the interrupt (with ADEN active) when you are not using free running/auto trigger modes.
/Lars

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

Quote:

now i read through the datasheet i found out that while in the interrupt mode the only way u can effectively change a channel is when the aden or adate bit is cleared or 1 cycle after the interrupt so i changed the code to this

Now you've lost me. The sequences that I posted work just fine. Where in the datasheet did you see this information?

I cannot think of a case where ADMUX cannot be changes at any time. Now, if you change it during a conversion, or as you have found out when free-running, it may have undesirable side effects.

ADEN not set? I'll call that simply not correct.
ADATE not set? Hmmm--if you are using an event to trigger a conversion, then you should be set up and waiting. If you "change your mind" then I suppose there could be a race. Do you want ADATE and trigger conversions off of an event, or do you want continuous conversions with the next started in the ISR after the first?
1 cycle after the interrupt? Do you mean "after the current conversion complete"? Then once you are in the ISR it is many cycles after the interrupt.

With normal signal impedances and normal ADC clock rates, you can simply follow the summary that I gave above, and there are code samples in the links.

There is no need to stop the A/D, nor wait for the next conversion to complete. IMO the ADATE is just muddying the waters. When you reach the ISR, the conversion is complete.

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:
Where in the datasheet did you see this information?
For ATmega32, e.g.:
Quote:
If both ADATE and ADEN is written to one, an interrupt event can occur at any time. If
the ADMUX Register is changed in this period, the user cannot tell if the next conversion
is based on the old or the new settings. ADMUX can be safely updated in the following
ways:
1. When ADATE or ADEN is cleared.
2. During conversion, minimum one ADC clock cycle after the trigger event.
3. After a conversion, before the Interrupt Flag used as trigger source is cleared.

Given 1. it is clear that there are no issues with ADMUX updates when auto-trigger is disabled.

Quote:
now i read through the datasheet i found out that while in the interrupt mode...
OP is probably confused about "interrupt mode", i.e., it is not only with auto-trigger enabled that the ADC interrupt is useful.
/Lars

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

When you >>do<< auto-trigger, I'd think one sets the mux for the next after servicing the completion of the current. Using a timer at a decent interval (say, 1ms or longer) there will never be a race. There could be a race with external interrupts but that is always the case. But in general doing everything in the ISR that I posted except starting the next conversion should be fine.

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

now as far as i know free running should be enabled while using interrupt, so in order to that i have to set adate bit and the sfior adps1,2,3 to 0 so i have done that , the only thing that confuses me when to change the channel coz the procedures i fllowed never gave me reliable results so thats the problem

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

Quote:

now as far as i know free running should be enabled while using interrupt,

Why? You are causing yourself a WHOLE rats-nest of problems, as you have seen, for multiple channels. By the time you get to the ISR to service the conversion-complete, the next conversion has already started ON THE SAME CHANNEL and is well on its way--that is wasted effort and now your ISR (as you "solved" the problem) becomes hundreds of microseconds instead of tens.

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 what do i do stop using interrupts?????????

if interrupts are such a problem while using multiple channels , then how come interrupts are thought to be better than normal conversion???

and if i dont use fee running mode then i have to start and stop each conversion and change the channel , so how does that make interrupts better????

I was thinking that interrupts would make my life easy and make my processing faster...

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

Did you at least look at the linked code? You change the channel and restart the conversion inside the interrupt. Not complicated.
/Lars

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

superchiku wrote:
so what do i do stop using interrupts?????????

if interrupts are such a problem while using multiple channels , then how come interrupts are thought to be better than normal conversion???

and if i dont use fee running mode then i have to start and stop each conversion and change the channel , so how does that make interrupts better????

I was thinking that interrupts would make my life easy and make my processing faster...

You do single conversions!!!! At the end of a conversion, the ADC stops, and the ISR is fired. In the ISR, you read the conversion value, change the channel, and start the enxt conversion and then exit the ISR!!!!!!!!

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Gee, I wish that >>I<< would have thought of that. Or maybe posted a summary of the steps involved.

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

You did! ;) Just hoping that if the OP hears it enough times, from enough people, it'll actually sink in.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

so i give up free running then just change the adsc register everytime the isr is fired , so thats the only soln??

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

Quote:

so thats the only soln??

Well, not the >>only<<. It is the simplest and most straightforward, in my opinion, if you want to do continuous conversions on all used channels so you have a very recent (within a few hundred microseconds) result always available.

If you keep your ISR skinny, that method (continuous conversions on all used channels) will take 5% to 10% of your AVR processing time.

If you prefer to use auto-trigger off of a timer tick, then you do everything in the ISR but start the next conversion. Note that this is nearly equivalent to not using the ISR at all--when you see the timer tick the previous conversion should be complete so you can fetch the results of the previous conversion, change the channel, and start the next conversion. Lessee--if you have a 10us ISR and start a conversion every 1ms that would be 1% of CPU time.

There are other scenarios to interleave/overlap a conversion with other operations so that you "know" it is done. For example, you could poll every time through the main loop and if the conversion is done then get the result, change the channel, and start the next.

All of the above are "single conversion"; none are "free-running".

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

so ill do that just change the channel manully and start the conversions manually, but i have another question.

Will this kinda adc operation make interrupt any better than normal conversions without interrupts

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

Quote:
Will this kinda adc operation make interrupt any better than normal conversions without interrupts
As with any interrupt the AVR is free to do other things, it is not busy waiting for the conversion to complete (ADC is rather slow compared to, e.g., an AVR at 16Mhz). Now, if there is nothing else to do then you might as well busy wait.
/Lars

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

well but will this be reliable coz iam going to use it a large code where the avr is going to do manay activities like controlling the 3 timers using the usart and continuosly taing adc readings

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

Yes, it will be ultra reliable :), seriously, no one but you can know that. If you follow the general advice to keep interrupt handlers short and fast there is nothing preventing it from beeing reliable.
/Lars

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

ill do that no problem