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.
1 Answer 1
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.
ADC_Handler
in your setup code, so I doubt this is really called.Arduino15\packages\arduino\hardware\sam1円.6.12\cores\arduino\coretex_handlers.c
It is definitely called because the LED lights up only if that digitalWrite is there.