ADCB interrupt didn't fire--but now it does...

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

I inherited a partially-done Xmega '128A3U app, and I'm not much of an Xmega person yet.

 

There are two ADC setup routines below, one for ADCA and the other for ADCB.  There are a couple of "interesting" differences, but nearly identical.  A debug session seems to indicate ADCB set up per the code.

 

Once ADCA is set up, the ADCA ISRs fire and results are as expected.  ADCB ISRs, however, never fire.

 

Can someone peek at these routines and try to help?  Perhaps something with the event system, and not properly set up for ADCB?  [I'm a novice at the event system, too.]

 

And/or tell me what more information is needed.  TIA

 

// ADCB initialization

// Variable used to store the ADC offset
// for 12 Bit Unsigned conversion mode
unsigned char adcb_offset;

void adcb_init(void)
{
	unsigned char i;
	unsigned int offs;

	// ADCB is enabled
	// Resolution: 12 Bits
	// Load the calibration value for 12 Bit resolution
	// from the signature row
	ADCB.CALL=read_calibration_byte(PROD_SIGNATURES_START+ADCBCAL0_offset);
	ADCB.CALH=read_calibration_byte(PROD_SIGNATURES_START+ADCBCAL1_offset);

	// Free Running mode: Off
	// Gain stage impedance mode:
	// Current consumption:
	// Conversion mode: Unsigned
	ADCB.CTRLB=(0<<ADC_IMPMODE_bp) | ADC_CURRLIMIT_NO_gc | (0<<ADC_CONMODE_bp) | ADC_RESOLUTION_12BIT_gc;

	// Clock frequency: 6000.000 kHz
	ADCB.PRESCALER=ADC_PRESCALER_DIV4_gc;

	// Reference: AREF pin on PORTA
	// Temperature reference: Off
	ADCB.REFCTRL=ADC_REFSEL_AREFA_gc | (0<<ADC_TEMPREF_bp) | (1<<ADC_BANDGAP_bp);

	// Read and save the ADC offset using channel 0
	// ADC11 pin connected to GND
	ADCB.CH0.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_INPUTMODE_SINGLEENDED_gc;
	ADCB.CH0.MUXCTRL=ADC_CH_MUXPOS_PIN11_gc;
	// Enable the ADC in order to read the offset
	ADCB.CTRLA|=ADC_ENABLE_bm;
	// Insert a delay to allow the ADC common mode voltage to stabilize
	delay_us(2);
	// Perform several offset measurements and store the mean value
	offs=0;
	for (i=0; i<16; i++)
	{
		// Start the AD conversion on channel 0
		ADCB.CH0.CTRL|= 1<<ADC_CH_START_bp;
		// Wait for the AD conversion to complete
		while ((ADCB.CH0.INTFLAGS & ADC_CH_CHIF_bm)==0);
		// Clear the interrupt flag
		ADCB.CH0.INTFLAGS=ADC_CH_CHIF_bm;
		// Read the offset
		offs+=(unsigned char) ADCB.CH0.RESL;
	}
	// Disable the ADC
	ADCB.CTRLA&= ~ADC_ENABLE_bm;
	// Store the mean value of the offset
	adcb_offset=(unsigned char) (offs/16);

	// Initialize the ADC Compare register
	ADCB.CMPL=0x00;
	ADCB.CMPH=0x00;

	// ADC channel 0 gain: 1
	// ADC channel 0 input mode: Single-ended positive input signal
	ADCB.CH0.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc;

	// ADC channel 0 positive input: ADC9 pin
	// ADC channel 0 negative input: GND
	ADCB.CH0.MUXCTRL=ADC_CH_MUXPOS_PIN9_gc;

	// ADC channel 1 gain: 1
	// ADC channel 1 input mode: Single-ended positive input signal
	ADCB.CH1.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc;

	// ADC channel 1 positive input: ADC10 pin
	// ADC channel 1 negative input: GND
	ADCB.CH1.MUXCTRL=ADC_CH_MUXPOS_PIN10_gc;

	// ADC channel 2 gain: 1
	// ADC channel 2 input mode: Internal positive input signal
	ADCB.CH2.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_INTERNAL_gc;

	// ADC channel 2 positive input: Bandgap Voltage
	// ADC channel 2 negative input: GND
	ADCB.CH2.MUXCTRL=ADC_CH_MUXINT_BANDGAP_gc;

	// ADC channel 3 gain: 1
	// ADC channel 3 input mode: Internal positive input signal
	ADCB.CH3.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_INTERNAL_gc;

	// ADC channel 3 positive input: Bandgap Voltage
	// ADC channel 3 negative input: GND
	ADCB.CH3.MUXCTRL=ADC_CH_MUXINT_BANDGAP_gc;

	// Event system channel: 3 sweeps ADC channel(s): 0, 1
	// The AD conversion will be synchronized on event to ensure accurate timing
	ADCB.EVCTRL=ADC_SWEEP_01_gc | ADC_EVSEL_3456_gc | ADC_EVACT_SYNCHSWEEP_gc;

	// Channel 0 interrupt: High Level
	// Channel 0 interrupt mode: Conversion Complete
	ADCB.CH0.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_HI_gc;
	// Channel 1 interrupt: High Level
	// Channel 1 interrupt mode: Conversion Complete
	ADCB.CH1.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_HI_gc;
	// Channel 2 interrupt: Disabled
	ADCB.CH2.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc;
	// Channel 3 interrupt: Disabled
	ADCB.CH3.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_OFF_gc;

	// Enable the ADC
	ADCB.CTRLA|=ADC_ENABLE_bm;
	// Insert a delay to allow the ADC common mode voltage to stabilize
	delay_us(2);
}

// ADCB channel 0 interrupt service routine
// Interrupt mode: Conversion Complete
interrupt [ADCB_CH0_vect] void adcb_ch0_isr(void)
{
	unsigned int data;

	// Read the AD conversion result
	((unsigned char *) &data)[0]=ADCB.CH0.RESL;
	((unsigned char *) &data)[1]=ADCB.CH0.RESH;
	// Compensate the ADC offset
	if (data>adcb_offset) data-=adcb_offset;
	else data=0;

	// Place your code here to process the ADC result stored in 'data'
	adcb_data[0] = data;

}

// ADCB channel 1 interrupt service routine
// Interrupt mode: Conversion Complete
interrupt [ADCB_CH1_vect] void adcb_ch1_isr(void)
{
	unsigned int data;

	// Read the AD conversion result
	((unsigned char *) &data)[0]=ADCB.CH1.RESL;
	((unsigned char *) &data)[1]=ADCB.CH1.RESH;
	// Compensate the ADC offset
	if (data>adcb_offset) data-=adcb_offset;
	else data=0;

	// Place your code here to process the ADC result stored in 'data'
	adcb_data[1] = data;

}
// ADCA initialization

// Variable used to store the ADC offset
// for 12 Bit Unsigned conversion mode
unsigned char adca_offset;

void adca_init(void)
{
	unsigned char i;
	unsigned int offs;

	// ADCA is enabled
	// Resolution: 12 Bits
	// Load the calibration value for 12 Bit resolution
	// from the signature row
	ADCA.CALL=read_calibration_byte(PROD_SIGNATURES_START+ADCACAL0_offset);
	ADCA.CALH=read_calibration_byte(PROD_SIGNATURES_START+ADCACAL1_offset);

	// Free Running mode: Off
	// Gain stage impedance mode:
	// Current consumption:
	// Conversion mode: Unsigned
	ADCA.CTRLB=(0<<ADC_IMPMODE_bp) | ADC_CURRLIMIT_NO_gc | (0<<ADC_CONMODE_bp) | ADC_RESOLUTION_12BIT_gc;

	// Clock frequency: 6000.000 kHz
	ADCA.PRESCALER=ADC_PRESCALER_DIV4_gc;

	// Reference: AREF pin on PORTA
	// Temperature reference: Off
	ADCA.REFCTRL=ADC_REFSEL_AREFA_gc | (0<<ADC_TEMPREF_bp) | (0<<ADC_BANDGAP_bp);

	// Read and save the ADC offset using channel 0
	// ADC11 pin connected to GND
	ADCA.CH0.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_INPUTMODE_SINGLEENDED_gc;
	ADCA.CH0.MUXCTRL=ADC_CH_MUXPOS_PIN11_gc;
	// Enable the ADC in order to read the offset
	ADCA.CTRLA|=ADC_ENABLE_bm;
	// Insert a delay to allow the ADC common mode voltage to stabilize
	delay_us(2);
	// Perform several offset measurements and store the mean value
	offs=0;
	for (i=0; i<16; i++)
	{
		// Start the AD conversion on channel 0
		ADCA.CH0.CTRL|= 1<<ADC_CH_START_bp;
		// Wait for the AD conversion to complete
		while ((ADCA.CH0.INTFLAGS & ADC_CH_CHIF_bm)==0);
		// Clear the interrupt flag
		ADCA.CH0.INTFLAGS=ADC_CH_CHIF_bm;
		// Read the offset
		offs+=(unsigned char) ADCA.CH0.RESL;
	}
	// Disable the ADC
	ADCA.CTRLA&= ~ADC_ENABLE_bm;
	// Store the mean value of the offset
	adca_offset=(unsigned char) (offs/16);

	// Initialize the ADC Compare register
	ADCA.CMPL=0x00;
	ADCA.CMPH=0x00;

	// ADC channel 0 gain: 1
	// ADC channel 0 input mode: Single-ended positive input signal
	ADCA.CH0.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc;

	// ADC channel 0 positive input: ADC2 pin
	// ADC channel 0 negative input: GND
	ADCA.CH0.MUXCTRL=ADC_CH_MUXPOS_PIN2_gc;

	// ADC channel 1 gain: 1
	// ADC channel 1 input mode: Single-ended positive input signal
	ADCA.CH1.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc;

	// ADC channel 1 positive input: ADC4 pin
	// ADC channel 1 negative input: GND
	ADCA.CH1.MUXCTRL=ADC_CH_MUXPOS_PIN4_gc;

	// ADC channel 2 gain: 1
	// ADC channel 2 input mode: Single-ended positive input signal
	ADCA.CH2.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc;

	// ADC channel 2 positive input: ADC5 pin
	// ADC channel 2 negative input: GND
	ADCA.CH2.MUXCTRL=ADC_CH_MUXPOS_PIN5_gc;

	// ADC channel 3 gain: 1
	// ADC channel 3 input mode: Single-ended positive input signal
	ADCA.CH3.CTRL=(0<<ADC_CH_START_bp) | ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc;

	// ADC channel 3 positive input: ADC7 pin
	// ADC channel 3 negative input: GND
	ADCA.CH3.MUXCTRL=ADC_CH_MUXPOS_PIN7_gc;

	// Event system channel: 2 sweeps ADC channel(s): 0, 1, 2, 3
	// The AD conversion will be synchronized on event to ensure accurate timing
	ADCA.EVCTRL=ADC_SWEEP_0123_gc | ADC_EVSEL_2345_gc | ADC_EVACT_SYNCHSWEEP_gc;

	// Channel 0 interrupt: High Level
	// Channel 0 interrupt mode: Conversion Complete
	ADCA.CH0.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_HI_gc;
	// Channel 1 interrupt: High Level
	// Channel 1 interrupt mode: Conversion Complete
	ADCA.CH1.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_HI_gc;
	// Channel 2 interrupt: High Level
	// Channel 2 interrupt mode: Conversion Complete
	ADCA.CH2.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_HI_gc;
	// Channel 3 interrupt: High Level
	// Channel 3 interrupt mode: Conversion Complete
	ADCA.CH3.INTCTRL=ADC_CH_INTMODE_COMPLETE_gc | ADC_CH_INTLVL_HI_gc;

	// Enable the ADC
	ADCA.CTRLA|=ADC_ENABLE_bm;
	// Insert a delay to allow the ADC common mode voltage to stabilize
	delay_us(2);
}

// ADCA channel 0 interrupt service routine
// Interrupt mode: Conversion Complete
interrupt [ADCA_CH0_vect] void adca_ch0_isr(void)
{
	unsigned int data;

	// Read the AD conversion result
	((unsigned char *) &data)[0]=ADCA.CH0.RESL;
	((unsigned char *) &data)[1]=ADCA.CH0.RESH;
	// Compensate the ADC offset
	if (data>adca_offset) data-=adca_offset;
	else data=0;

	// Place your code here to process the ADC result stored in 'data'
	
	    //vac_cnv_cnt++;
	    //cnv_per_tock++;
	    //vac = data;
		adca_data[0] = data;
		adca_cnv_cnt[0]++;

}

// ADCA channel 1 interrupt service routine
// Interrupt mode: Conversion Complete
interrupt [ADCA_CH1_vect] void adca_ch1_isr(void)
{
	unsigned int data;

	// Read the AD conversion result
	((unsigned char *) &data)[0]=ADCA.CH1.RESL;
	((unsigned char *) &data)[1]=ADCA.CH1.RESH;
	// Compensate the ADC offset
	//if (data>adca_offset) data-=adca_offset;
	//else data=0;

	// Place your code here to process the ADC result stored in 'data'
	adca_data[1] = data;
	adca_cnv_cnt[1]++;

}

// ADCA channel 2 interrupt service routine
// Interrupt mode: Conversion Complete
interrupt [ADCA_CH2_vect] void adca_ch2_isr(void)
{
	unsigned int data;

	// Read the AD conversion result
	((unsigned char *) &data)[0]=ADCA.CH2.RESL;
	((unsigned char *) &data)[1]=ADCA.CH2.RESH;
	// Compensate the ADC offset
	if (data>adca_offset) data-=adca_offset;
	else data=0;

	// Place your code here to process the ADC result stored in 'data'
	adca_data[2] = data;
	adca_cnv_cnt[2]++;

}

// ADCA channel 3 interrupt service routine
// Interrupt mode: Conversion Complete
interrupt [ADCA_CH3_vect] void adca_ch3_isr(void)
{
	unsigned int data;

	// Read the AD conversion result
	((unsigned char *) &data)[0]=ADCA.CH3.RESL;
	((unsigned char *) &data)[1]=ADCA.CH3.RESH;
	// Compensate the ADC offset
	if (data>adca_offset) data-=adca_offset;
	else data=0;

	// Place your code here to process the ADC result stored in 'data'
	adca_data[3] = data;
	adca_cnv_cnt[3]++;

}

 

 

This topic has a solution.

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.

Last Edited: Wed. Apr 15, 2015 - 09:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

frog = ADCB.INTFLAGS;

"frog" remains zero.

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.

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

Got it!

 

	ADCB.EVCTRL=ADC_SWEEP_01_gc | ADC_EVSEL_2345_gc | ADC_EVACT_SYNCHSWEEP_gc;
//	ADCA.EVCTRL=ADC_SWEEP_0123_gc | ADC_EVSEL_2345_gc | ADC_EVACT_SYNCHSWEEP_gc;

I had to learn a bit about the event system, and decode the differences between ADCA and ADCB init.

 

ADCA is triggered by event 2, which is a timer overflow.

ADCB was set to trigger on event 3, which wasn't happening.  [That was a pin change.  As the app gets closer to completion ADCB may well be triggerred differently than ADCA, but for now I can proceed, verify channel values, and such.]

 

Thanks for looking.  Any further comments or advice welcome.

 

 

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.