ADC interrupt

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

I want to get conversion of whole channels of ADC with interrupt.

i tried this

ISR(ADC_vect)
{

	if (channel > 7)
	{
		channel = 0;
		adc_complete = 1;
	}
	adc_test[channel] = ADCH;
	adc_test[channel] = (adc_test[channel] << 8);
	adc_test[channel] |= ADCL;
	channel++;
	ADMUX |= (channel & 7);

	if (channel > 7)
	{
		adc_complete = 1;
		channel = 0;
	}
}

but seems not working. values are not updates.

it gives me one value at once and next seems to stop.

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

Wow!   We need a lot more information to be able to help.  For example, what AVR device is this?  There are different ADC configurations depending on the host device.  And, How is the ADC configured?  Is it one shot or re-triggering?  Also, what is the left/right alignment of the data?  If ADCH holds data bits 9-2 then ADCL will hold bits 1:0 of the conversion in its bits 7:6 and the shift-then-OR operation isn't going to give the correct result regardless of the configuration.

  What is the ADC reading?  A bank of potentiometers?  Or just empty pins?

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

AVR: ATmega32

void adc_init(void)
{
	adc_complete = 0;
	channel = 0;
	 ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz
	 ADMUX |= (1 << REFS0); // Set ADC reference to AVCC
	 ADMUX |= (0 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading
	 ADCSRA |= (1 << ADEN);  // Enable ADC
	 ADCSRA |= (1 << ADATE);
	 ADCSRA |= (1 << ADIE);
	 ADCSRA |= (1 << ADSC);  // Start A2D Conversions
	 return;	
}

 

ADC reads potensiometer.

without interrupt works fine.

Last Edited: Sat. Dec 20, 2014 - 12:10 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For one thing, you just keep ORing 1s into ADMUX.  You never clear the channel field, so before you can blink you'll always be reading channel 7 (all 1s) no matter what the channel variable holds.

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

i tried with one channel but nothing...

seems to be stoped. not updated values...

 

ISR(ADC_vect)
{
	adc_test[0] = ADCH;
	adc_test[0] = (adc_test[0] << 8);
	adc_test[0] |= ADCL;
        ADCSRA |= (1 << ADSC);
}

 

Last Edited: Sat. Dec 20, 2014 - 12:28 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

without interrupt works perfectly.

i want to do this (pseudo code)

start adc from ch0

convert ch0

set admux to ch1

convert ch1

set admux to ch2

convert ch2

.... .... ....

set admux to ch7

convert to ch7

set adc_complete flag when all channels be converted

read adc_complete flag and,

get stored data from an uint16 array

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

i found something strange.

im trying to set each conversion after a conversion completes and corresponding interrupt takes effect.

but...

 

ADCSRA |= (1 << ADSC);  Won't work inside ISR(ADC_Vect)

Last Edited: Sat. Dec 20, 2014 - 09:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you haven't shown us enough code to comment. At a guess it is something to do with variables not declared volatile.

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

No,  it is about inappropriate code.

volatile uint8_t adc_complete;
uint16_t adc_test[8];           // somewhere to store results

void adc_init(void)
{
    ADMUX = (1<<REFS0);         // ref AVCC
    ADCSRA = (1<<ADEN)|(1<<ADIE)|(1<<ADSC)|(3<<ADPS0); // enable, start first conversion, div128
    sei();                      // global interrupts
    return;	
}
ISR(ADC_vect)
{
    static uint8_t channel;
    adc_test[channel] = ADCW;   // read whole 10-bits into relevant element of array
    if (++channel >= 8) {
        channel = 0;
        adc_complete = 1;
    }
    ADMUX = (1<<REFS0) | channel;
    _delay_us(10);              // allow a little time for multiplexer to settle
    ADCSRA |= (1<<ADSC);        // start next conversion
}

Untested.    You might want to avoid an 'unnecessary delay':

ISR(ADC_vect)
{
    static uint8_t channel;
    uint8_t old = channel;
    if (++channel >= 8) {
        channel = 0;
        adc_complete = 1;
    }
    ADMUX = (1<<REFS0) | channel; //ready for the next reading
    adc_test[old] = ADCW;       // @ 1MHz,  this will take a few us
    _delay_us(9);               // @ 16MHz,  you still need a little delay
    ADCSRA |= (1<<ADSC);        // start next conversion
}

Of course,  the settling time does depend on the source impedance of your target voltage and any difference in values between targets.

 

David.

Last Edited: Sat. Dec 20, 2014 - 12:47 PM