ADC issue with xmega32A4

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

Yes I know there seems to be lots of questions on xmega ADC...I have read the forum threads and it seems my code is similar to the ones out there but still not working :(
I have been reading the app notes as well. Would anyone be happy to read the following code see if there is any obvious mistakes I have made?

AdcInit(void)
{
   //setup the ADC pins as inputs
   ADC_PORT->DIRCLR = (1 << 0) | (1 << 1) | 
                      (1 << 2) | (1 << 3) | 
                      (1 << 4);
   //aref in port B is used
   ADC_PORT_EXTRA->DIRCLR = (1 << AREF_PIN);		

   //configure the ADC module
   struct adc_config adcConf = {
      .ctrla = 0x00,   //default
      .ctrlb = ADC_SIGN_ON | ADC_RES_12,  //signed, 12 bit right adjusted
      .refctrl = ADC_REFSEL_AREFB_gc,    //do not use internal 1.0V reference, instead external aref from port B
      .evctrl = ADC_SWEEP_012_gc  | 
                ADC_EVSEL_0123_gc |
                ADC_EVACT_NONE_gc,   //no event sweep active
      .prescaler = ADC_PRESCALER_DIV16_gc,   //pre-scaler of 16 to give less than 1MHz sampling
      .cmp = 0xFFFF  //compare value is not in use
   };
   adc_write_configuration(ADC, &adcConf);
   
   //setup channel 0
   ADC->CH0.CTRL = ADC_CH_GAIN_1X_gc |      //no gain, ie: x1
                   ADC_CH_INPUTMODE_SINGLEENDED_gc;
   ADC->CH0.MUXCTRL = ADC_PIN0 << ADC_CH_MUXPOS_gp;
   ADC->CH0.INTFLAGS = 0x00;
   ADC->CH0.INTCTRL = ADC_CH_INTMODE_COMPLETE_gc |   //raise interrupt on conversion complete
                      ADC_CH_INTLVL_MED_gc;

   //setup channel 1
   ADC->CH1.CTRL = ADC_CH_GAIN_1X_gc |      //no gain, ie: x1
                   ADC_CH_INPUTMODE_SINGLEENDED_gc;
   ADC->CH1.MUXCTRL = ADC_PIN3 << ADC_CH_MUXPOS_gp;
   ADC->CH1.INTFLAGS = 0x00;
   ADC->CH1.INTCTRL = ADC_CH_INTMODE_COMPLETE_gc |   //raise interrupt on conversion complete
                      ADC_CH_INTLVL_MED_gc;

   //setup channel 2
   ADC->CH2.CTRL = ADC_CH_GAIN_1X_gc |      //no gain, ie: x1
                   ADC_CH_INPUTMODE_SINGLEENDED_gc;
   ADC->CH2.MUXCTRL = ADC_PIN4 << ADC_CH_MUXPOS_gp;
   ADC->CH2.INTFLAGS = 0x00;
   ADC->CH2.INTCTRL = ADC_CH_INTMODE_COMPLETE_gc |   //raise interrupt on conversion complete
                      ADC_CH_INTLVL_MED_gc;
}

   adc_enable(ADC);


//my ADC conversion complete interrupts
ISR(ADCA_CH0_vect)
{
   //print statement
}

ISR(ADCA_CH1_vect)
{
   //print statement
}
ISR(ADCA_CH2_vect)
{
   //print statement
}



from main I start the conversion using:

ADC->CTRLA |= (ADC_CH2START_bm | ADC_CH1START_bm | ADC_CH0START_bm);

but it seems my ISR routines never get fired :(
Any thoughts?

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

Ahhh grrrr I hate the ASF codes they give you! They are too crazy. Inside their adc_write_configuration() at the end of it they disable the ADC clock!!!

So all the changes to the registers I apply doesnt seem to do anything and hence I get no results.

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

Did you solve it ? I'm with you in hating the ASF functions and thus implemented it all on my own. First of all before doing any init you should probably enable the ADC:

#define ADC ADCA
ADC.CTRLA = 0x01;
// now init the stuff
ADC.CTRLB = ADC_RESOLUTION_12BIT_gc | (ADC_MODE << 4) ;  // 12 bit right adjusted
// and so on
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yes I solved it....the problem was in the adc_write_configuration() from asf as mentioned in my previous post...so I got rid of it and manually changed all the config registers. :)

Now I am trying to do the conversion from events generated from timer 0 (port C). I can get the interrupt method working, but event method not working yet...investigating further... :)

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

Note there is a bugzilla for ASF - anything "not right" should be reported - it's the only way they'll improve it.

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

I am not too impressed with this event system...it seems if I use interrupt routine at every OVF of timer and set the start flag for a ADC conversion the micro does it pretty well and fast!

But if I setup say channel 7 to carry the event for timer OVF and use the event to trigger a sweep of ADC conversion on channel 0, 1 and 2, it seems the micro is 'busy' doing God knows what. I say this because I am running a print statement in my main routine with 300 ms delay. This prints the ADC values. Now this printing slows down heavily if I use the event method. Must faster in interrupt method.

Why could this be happening?

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

ok I found the problem..
Looks like I had to initialize the EVENTSYS clocking as well using :

sysclk_enable_module(SYSCLK_PORT_GEN, SYSCLK_EVSYS);

Its a touch faster than the interrupt method.
One more thing is that the ADC conversion happens in a pipeline method...so if I am only using 3 channels ADC and raise interrupt only for the 3rd channel, then I am ultimately gauranteed that the first 2 conversions had also finished. Is that correct?

In that case I should only have interrupt set on the 3rd one.

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

New problem!
I designed my pcb with single ended measurement and I can measure analogue values fine with full scale 2047 it seems...although min value seems to jump around between -5 to 0. I could probably live with that. Also the the reading seems to jump around as well (for any input level) within about 20-40 ish of the raw value.

I then configure the code for differential with gain (cant do diff without gain as my pins are taken up in my pcb design) and the readings seem to get better slightly, however the maximum I can get is capped at about 1850 ish instead of the 2047. Any idea why this could be happening?

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

IMHO, the only way to get linearity, stability, and 12 bit resolution from the "old" adc is to use an external reference, and only use the signed differential mode without gain. I'm getting rock solid performance this way. There is quite a bit of discussion on the forum about all of this.

Tom Pappano
Tulsa, Oklahoma

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

Yes I have read a few discussions as well... I was just hoping differential with gain of 1 would be similar to differential without gain. But looks like it isnt, according to your experience. I might have to get the board redesigned then.

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

I have my ADC configured to be triggered using timer 0 CCD compare match event. It does get triggered. However my code once in a while when required performs a flush on the ADC. Does this mean the conversion will start immediately after a flush? Or after a flush it waits for an event and then when event is raised, it does the conversion?