1

In the simple example below I just software trigger an ADC acquisition and then set the builtin LED's digital out in the interrupt handler. I don't know why the program appears to halt however.


void setup() {
  Serial.begin(115200);

  pinMode(13,OUTPUT);
  digitalWrite(13,LOW);

  adc_enable_channel(ADC, ADC_CHANNEL_6);
  adc_enable_interrupt(ADC, ADC_IER_EOC6);
  pmc_enable_periph_clk(ID_ADC);
  NVIC_EnableIRQ(ADC_IRQn);
    
  Serial.println("GO");     
}

void loop() 
{
  Serial.println("RUNNING");
  adc_start(ADC);
}

void ADC_Handler(void)
{
  digitalWrite(13,HIGH);  
  adc_get_status(ADC);
}

I know the handler gets called because the LED lights. The main loops appears to stop running after this as it lo longer prints out anything. If I don't trigger an acquision in the main loop it runs forever. Likewise if I don't enable the interrupt or the NVIC.

I can't explain this behavior.

3
  • There's no reference to ADC_Handler in your setup code, so I doubt this is really called.
    – PMF
    Commented Oct 20, 2021 at 6:04
  • Possible duplicate: arduino.stackexchange.com/questions/19924/…
    – PMF
    Commented Oct 20, 2021 at 6:07
  • @PMF As with other ISRs, it overrides a weak reference in Arduino15\packages\arduino\hardware\sam\1.6.12\cores\arduino\coretex_handlers.c It is definitely called because the LED lights up only if that digitalWrite is there. Commented Oct 20, 2021 at 12:28

1 Answer 1

2

The freeze will occur unless unless ADC_ISR bits 0-15 are 0 at the end of the interrupt handler. In this case, ISR returns bit 6 set for the enabled channel (6). For many interrupts, the bit can be reset to 0 by simply reading ADC_ISR. However for end-of-conversion interrupts the converted data register for that channel must be read for the ISR bit to be set to 0.

Therefore this code will not halt. (I included some extra printouts to make clear the register values at each point in time.)

volatile uint32_t LAST = 0;
volatile uint32_t CHAN6 = 0;
volatile uint32_t ISR1 = 0;
volatile uint32_t ISR2 = 0;

void setup() {
  Serial.begin(115200);

  adc_enable_channel(ADC, ADC_CHANNEL_6);

  adc_enable_interrupt(ADC, ADC_IER_EOC6);

  pmc_enable_periph_clk(ID_ADC);
    
  NVIC_ClearPendingIRQ(ADC_IRQn);
  NVIC_EnableIRQ(ADC_IRQn);
    
  Serial.println("GO");
  adc_configure_trigger(ADC, ADC_TRIG_SW,0);
}

void loop() 
{
  Serial.println(ISR1,BIN); 
  Serial.println(ISR2,BIN); 

  adc_start(ADC);
  delay(1000);
}

void ADC_Handler(void)
{   
  ISR1 = adc_get_status(ADC); // chan 6 bit =1
  LAST = adc_get_latest_value(ADC); 
  ISR1 = adc_get_status(ADC); // chan 6 bit =1 (still)
  
  CHAN6 = adc_get_channel_value(ADC, ADC_CHANNEL_6);
  ISR2 = adc_get_status(ADC); // chan 6 bit = 0
}

However, I will note that the datasheet for the chip says on page 1322 Reading one of the ADC_CDR registers clears the corresponding EOC bit. Reading ADC_LCDR clears the DRDY bit and EOC bit corresponding to the last converted channel.

This appears to be false. Reading ADC_LCDR does not clear the status bit and will cause a hang. ADC_CDR6 must be read specifically to avoid a hang.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.