# ADC on a SAMD21 always gives zero values, except when using breakpoints in its interrupt

I started experimenting with the ADC on a SAMD21, and strangely, the result I get is always 0.

I initialized it like this (using the temperature sensor to get some values without external hardware):

SYSCTRL->VREF.bit.TSEN = 1;  // enable temperature sensor

GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK2 | GCLK_CLKCTRL_ID_ADC;  // base clock GCLK2 = 1MHz
PM->APBCMASK.bit.ADC_ = 1; // Enable bus clock

ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val;   // internal 1V reference
ADC->AVGCTRL.bit.SAMPLENUM = ADC_AVGCTRL_SAMPLENUM_4_Val; // average from 4 samples
ADC->SAMPCTRL.bit.SAMPLEN = 49; // for approx. 100 us/sample with a 4x prescaler on the 1MHz clock
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_16BIT_Val;     // to support averaging

ADC->INPUTCTRL.bit.MUXPOS = 0x18;  // temperature sensor

ADC->INTENSET.bit.RESRDY = 1;           // result ready interrupt



I checked that the clocks are working as they should, and made sure the ADC interrupts get regularly triggered, by toggling a portpin in the ADC interrupt.

After that, I tried reading some values.

volatile int debug_adc[201];
int debug_adc_c = 0;

{
volatile int result = ADC->RESULT.bit.RESULT;

if (debug_adc_c >= 200)
{
}
}


I let it run for a while, and when I stop it, the array is full of zeroes, and the RESULT register in the I/O view is also zero.

However, if I place a breakpoint inside the interrupt handler, I see non-zero values, both in the array in the Watch screen and in the I/O view.

I don't touch the ADC anywhere else in my code. I also tried it without averaging (ADC->AVGCTRL.bit.SAMPLENUM = 0), nothing changed.

The datasheet recommends performing one manual conversion at the beginning, even if I use the freerunnig mode: ADC->SWTRIG.bit.START = 1;. I did it, but it didn't change anything.

Did I miss something obvious?

• I have not worked with SAMD21 but when ever I get ADC result always zero, I go and check the pin definition to confirm I have defined the respective pin to be used as ADC! And well keil simulation doesn't care about pin definitions Feb 16, 2018 at 7:47
• @MaNyYaCk : yes, the SAMD21 does have a port/pin multiplexer, but the temperature sensor is internal and not connected to a physical pin, so it shouldn't be an issue. However, thanks for the comment, I'll deepen my experiments regarding the port multiplexer as well. Please note, that I'm not using a simulation, but a physical microcontroller.
– vsz
Feb 16, 2018 at 7:58

The ADC has both negative and positive inputs, but it seems it is not just merely an optional extra feature. I have to specify a negative input, even if I only use the positive one. (the datasheet is a little unclear here, it only mentions both inputs being used in the calculation if I choose differential input in CTRLB.DIFFMODE, which wasn't the case here)

After setting the negative input to the internal ground,

ADC->INPUTCTRL.bit.MUXNEG = 0x18;


everything works as expected.

I still don't understand why it was working when a breakpoint was set, but at least the code works as it should.

• Since you found the cause, you can accept your own answer. Perfectly fine thing to do.
– JRE
Feb 16, 2018 at 11:49
• @JRE : I know, but there is still a 2 days waiting period.
– vsz
Feb 16, 2018 at 13:43
• Fixed my issue too, which was even more bizarre: some ADC channels worked periodically without 0x18 on MUXNEG, but others didn't work at all, with various failure modes. AIN0 read low noise values. AIN13 read all zeroes. AIN10 and AIN11 had been working periodically.
– Akh
Jun 26, 2018 at 6:09