SAML21 ADC configuration problem with ASF

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

Greetings,

 

I am working off of the adc callback example from the ASF documentation, I am trying to set the ADC up into free running mode with a callback when results are ready.  If I add a line of code to enable free running mode things seem to get messed up.  If free running is enabled, adc_enable() seems to be starting a conversion (after adc_enable() is called INTFLAG RESRDY and OVERRUN are asserted. I don't think this should be happening.  It is causing the interrupt flag to be set before the callbacks and global interrupts are enabled. 

 

I thought a workaround would be to just immediately read results after the callbacks and interrupts were set up using adc_read().  However when I step through things with the debugger it seems like this function call is only clearing the OVERRUN bit in the INTFLAG register but not the RESRDY bit.  I feel like there is something I'm missing here but after two days I can't put my finger on it.  Another odd observation is that if I am halted in the debugger and click on the OVERUNN bit in the processor IO view, it causes the RESRDY bit to clear and vice versa.  I'm not sure why this is happening either, it seems as though clicking on either one should clear that one, not the other bit in the register.  If anyone has any thoughts on what is going on here or what I might be doing wrong I could really use some help.  Thanks in advance, code is posted below:

#include <asf.h>
struct adc_module adc_instance;
#define ADC_SAMPLES 128
uint16_t adc_result_buffer[ADC_SAMPLES];
uint16_t results =0;

volatile bool adc_read_done = false;

void adc_complete_callback(struct adc_module *const module);
void configure_adc(void);
void configure_adc_callbacks(void);

int main (void)
{
 system_init();
 
 configure_adc();
 configure_adc_callbacks();
 system_interrupt_enable_global();
  

  adc_read(&adc_instance,&results);
  adc_read(&adc_instance,&results);
  adc_read(&adc_instance,&results);
 while (adc_read_done == false) 
 {
  /* Wait for asynchronous ADC read to complete */
 }
 while (1) 
 {
  /* Infinite loop */
 }
}
void adc_complete_callback(struct adc_module *const module)
{
 //adc_read(&adc_instance,&results);
 adc_read_done = true;
}

void configure_adc(void)
{
 struct adc_config config_adc;
 adc_get_config_defaults(&config_adc);
 #if (!SAML21) && (!SAML22) && (!SAMC21) && (!SAMR30)
 config_adc.gain_factor     = ADC_GAIN_FACTOR_DIV2;
 #endif
 config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV8;
 config_adc.reference       = ADC_REFERENCE_INTVCC1;
 #if (SAMC21)
 config_adc.positive_input  = ADC_POSITIVE_INPUT_PIN5;
 #else
 config_adc.positive_input  = ADC_POSITIVE_INPUT_PIN6;
 #endif
 config_adc.resolution      = ADC_RESOLUTION_12BIT;
 config_adc.freerunning = true;
 #if (SAMC21)
 adc_init(&adc_instance, ADC1, &config_adc);
 #else
 adc_init(&adc_instance, ADC, &config_adc);
 #endif
 adc_enable(&adc_instance);
}
void configure_adc_callbacks(void)
{
 adc_register_callback(&adc_instance, adc_complete_callback, ADC_CALLBACK_READ_BUFFER);
 adc_enable_callback(&adc_instance, ADC_CALLBACK_READ_BUFFER);
}

 

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

There is nothing in your program to get things going (including nothing to enable the interrupt that will cause the adc_complete_callback to be called). From looking at the ASF source only adc_read_buffer_job is able to do this. Add a call in main, e.g.

    adc_read_buffer_job(&adc_instance, &results, 1);

And repeat that call in the callback. You can request more than one sample obviously, including from more than one input using adc_enable_positive_input_sequence()

/Lars

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

That's part of the issue, I never start the adc yet after initialization in free running mode the results ready irq flag is already set.

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

The ADC is started but the interrupt is not enabled, adc_read_buffer_job does that. adc_read_buffer_job can start the conversion but this is only when the ADC is software triggered (so not with freerunning true).

/Lars

 

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

Lajon wrote:

The ADC is started but the interrupt is not enabled, adc_read_buffer_job does that. adc_read_buffer_job can start the conversion but this is only when the ADC is software triggered (so not with freerunning true).

/Lars

 

Hi Lars,

I am currently using a custom board with Atmel SAMD2016A. So do I need to explicitly enable the interrupt for the ADC? While debugging, I noticed that adc_enable was going for a toss with a non-returning call to adc_is_syncing (Stuck at this point). Please find attached main.c, couldn't insert code. 

Regards,

Jenson

Attachment(s): 

Newbie to the world of Atmel SAM D microcontrollers.

Last Edited: Thu. Jul 13, 2017 - 09:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No you don't need to enable the interrupt, adc_read_buffer_job does that. But it seems your current problem occurs before there is even a chance to call that. I only have a D21 and your main works fine with that (to be clear I did this: created a ASF board project and selected SAMD21J18A custom board, added ADC callback using ASF wizard and replaced the default main.c with your main.c).

/Lars

 

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

Lajon wrote:

No you don't need to enable the interrupt, adc_read_buffer_job does that. But it seems your current problem occurs before there is even a chance to call that. I only have a D21 and your main works fine with that (to be clear I did this: created a ASF board project and selected SAMD21J18A custom board, added ADC callback using ASF wizard and replaced the default main.c with your main.c).

/Lars

 

Hi Lars,

Sorry for the delay, was unwell. So the code works on your board then it means either I have messed up my settings or my hardware has some issues. Do we need to program the fuses too?
 

Could you please zip and attach your ASF project. Do you add anything to your user_board.h or init.c ?

*I noticed that the ISR shows hard fault whenever I try to enable ADC. I'll attach a screen shot with the various registers and call stack.
The ADC INTFLAG value was 0x08.

With regards,

Jenson

Attachment(s): 

Newbie to the world of Atmel SAM D microcontrollers.

Last Edited: Tue. Jul 18, 2017 - 10:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Could it be due to me programming the fuses by mistake? Now I seem to be getting stuck at system_glck_gen_disable !!! I'll double check the conf_clocks.h once again and try. 

Regards,
Jenson

Newbie to the world of Atmel SAM D microcontrollers.