ISR not working for ADC Conversion Complete interrupt

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

Hey everyone, 

 

I'm fairly new to the Interrupts, I am trying to set up the interrupt routine to trigger when ADC conversion is complete on my XMega256A3BU. After digging into the docs I came up with the following ISR:

 

//interrupt routine
ISR(ADCA_CH2_vect)
{
			//when conversion is complete, display results
			result = ADCA.CH2RES;
			//convert the int to a string
			sprintf(str_res, "%d", result);

			//clear the LCD screen
			Clear_Display();

			//write the result to the LCD output
			LCDstr(str_res);

			delay_ms(1000);
}

I did enable the interrupts in my main routine using sei() function.

 

if it helps, following is my ADC config:

//to be edited, for now, static settings
void adcA_config(void)
{
	//ADC Configuration
	ADCA.CH2.CTRL |= 0x01; //set inputmode bits to 1 (single-ended)

	//selecting the input  --- bits [6:3] define the input from 0(0000) - 15(1111)
	ADCA.CH2.MUXCTRL |= 0b00101000; //selecting ADC5 as input

	//Enable 12-bit resolution (bit 0&1 define this setting)
	ADCA.CTRLB &= 0b11111100;

	//Set the Vref bits 4-6 (000- int1v 1V 001- intvcc/1.6 010-Aref on portA 011- ArefB 100-Vcc/2)
	ADCA.REFCTRL |= 0b01000000; //Vref = Vcc/2

	//selecting 2 MHz clock
	clock_config(0);
	//set the clock rate (Prescaler)
	ADCA.PRESCALER |= 0x03; //writing msb to 0 unused bits per guide and lsb to 3 to select /32 prescale

	//config interrupts
	// Ensure the conversion complete flag is cleared
	ADCA.INTFLAGS = ADC_CH2IF_bm; // 0x01

	// Enable Conversion Complete Interrupt with high priority
	ADCA.CH2.INTCTRL |= ADC_CH_INTLVL1_bm | ADC_CH_INTLVL0_bm; // 0x03

	PMIC_CTRL |= 0x01; // enable interrupts
}

Oh and how I know the interrupt isnt triggering is because I set a breakpoint in the code. (I'm using AVR Dragon as debugger)

 

Any suggestion would be highly appreciated! :) 

Soul

Last Edited: Fri. Feb 3, 2017 - 03:40 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sprintf() and LCD output in an ISR() ? You sure about that? Even on a lowly tiny/mega ADC conversion interrupts can be occurring as often as every 66us and the Xmega has a higher performance ADC so that number might be something like 1us (ie 1MHz). You don't have time at that rate for doing things like printing to displays. If you do call sprintf() and LCD functions while in the ISR it will take 1,000's and 1,000's of microseconds so you will miss thousands of ADC conversion results.

 

A better idea is simply to have the interrupt readings (perhaps a "running average"?) and then from time to time the slow code in main() presents the "latest" to the human (who can only really process updates about once every 100,000us anyway!)

 

As for why the debugger shows that no interrupts occur two ideas (though one is related to the other anyway):

 

1) When Xmega first came out Atmel penned a bunch of app notes with AVR13xx numbers like AVR1301, AVR1302 etc. One of those (perhaps more) will be about the ADC. It explains how to use it and comes with sample code

 

2) meanwhile over in Studio 7 there is "ASF". It's a terrible code library but at least it has examples that ultimately work. There is a strong chance it has ADC for Xmega examples. (as it happens you may well find the code you find there is closely related to the AVR13xx code anyway as I think it was "absorbed" into ASF).

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

clawson said:

sprintf() and LCD output in an ISR() ?

 

What about the 

delay_ms(1000);

in the same ISR?  That's just crazy!

 

Soulistic, where are you enabling interrupts, i.e., setting the I bit in the status register?  If you are just enabling interrupt levels in the PMIC, you are NOT enabling interrupts.  You must use something like cpu_irq_enable() or sei() to do that.

 

Greg Muth

Portland, OR, US

Xplained/Pro/Mini Boards mostly

 

Make Xmega Great Again!

 

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

Greg_Muth wrote:

clawson said:

sprintf() and LCD output in an ISR() ?

 

What about the 

delay_ms(1000);

in the same ISR?  That's just crazy!

 

Soulistic, where are you enabling interrupts, i.e., setting the I bit in the status register?  If you are just enabling interrupt levels in the PMIC, you are NOT enabling interrupts.  You must use something like cpu_irq_enable() or sei() to do that.

 

 

Hey!

 

Thanks for the response. firstly, since both of you mentioned, I wanted to clear up that the delay, sprintf and LCD were all just for troubleshooting purposes and wont exist in the prod version. I set sei() in the main function when it begins. then the adc config is called. do you think that would pose a problem? should I add it within the function?

 

Thanks again guys! :) 

Soul

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

I think I found it:

	// Enable Conversion Complete Interrupt with high priority
	ADCA.CH2.INTCTRL |= ADC_CH_INTLVL1_bm | ADC_CH_INTLVL0_bm; // 0x03

	PMIC_CTRL |= 0x01; // enable interrupts

You are setting the CH2 interrupt priority to high (3) but you are only enabling the low (1) interrupt priority.  The interrupt will never be acknowledged.  BTW, the header files define nice symbols that are much friendlier than the ones you are using:

 

    ADCA.CH2.INTCTRL = ADC_CH_INTLVL_HI_gc;
/* also
    ADC_CH_INTLVL_OFF_gc
    ADC_CH_INTLVL_LO_gc
    ADC_CH_INTLVL_MED_gc
*/

    PMIC.CTRL = PMIC_LVL_HIGH;
/* also
	PMIC_LVL_LOW
	PMIC_LVL_MEDIUM
*/

 

edit: typos

Greg Muth

Portland, OR, US

Xplained/Pro/Mini Boards mostly

 

Make Xmega Great Again!

 

Last Edited: Mon. Feb 6, 2017 - 06:38 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Greg_Muth wrote:

I think I found it:

	// Enable Conversion Complete Interrupt with high priority
	ADCA.CH2.INTCTRL |= ADC_CH_INTLVL1_bm | ADC_CH_INTLVL0_bm; // 0x03

	PMIC_CTRL |= 0x01; // enable interrupts

You are setting the CH2 interrupt priority to high (3) but you are only enabling the low (1) interrupt priority.  The interrupt will never be acknowledged.  BTW, the header files define nice symbols that are much friendlier than the ones you are using:

 

    ADCA.CH2.INTCTRL = ADC_CH_INTLVL_HI_gc;
/* also
    ADC_CH_INTLVL_OFF_gc
    ADC_CH_INTLVL_LO_gc
    ADC_CH_INTLVL_MED_gc
*/

    PMIC.CTRL = PMIC_LVL_HIGH;
/* also
	PMIC_LVL_LOW
	PMIC_LVL_MEDIUM
*/

 

edit: typos

 

 

Hey ! Thanks again for the help! I actually caught this error earlier and it still didn't work! I apologize for not updating the code! 

Soul