ADC en un SAMD21 siempre da valores cero, excepto cuando se usan puntos de interrupción en su interrupción

2

Comencé a experimentar con el ADC en un SAMD21 y, extrañamente, el resultado que obtengo es siempre 0 .

Lo inicialicé así (usando el sensor de temperatura para obtener algunos valores sin hardware externo):

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.PRESCALER = ADC_CTRLB_PRESCALER_DIV4_Val;
ADC->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_16BIT_Val;     // to support averaging
ADC->CTRLB.bit.FREERUN = 1;

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

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

ADC->CTRLA.bit.ENABLE = 1;

NVIC_EnableIRQ( ADC_IRQn );

Verifiqué que los relojes funcionen como deberían y me aseguré de que las interrupciones de ADC se activen regularmente, al alternar un puerto en la interrupción de ADC.

Después de eso, intenté leer algunos valores.

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

void ADC_Handler()
{
    volatile int result = ADC->RESULT.bit.RESULT;

    debug_adc[debug_adc_c++] = result;
    if (debug_adc_c >= 200) 
    {
        debug_adc_c = 0;
    }
}

Lo dejé correr por un tiempo, y cuando lo detengo, la matriz está llena de ceros y el registro de RESULTADO en la vista de E / S también es cero.

Sin embargo, si coloco un punto de interrupción dentro del controlador de interrupciones, veo valores distintos de cero, tanto en la matriz en la pantalla de visualización como en la vista de E / S.

No toco el ADC en ninguna otra parte de mi código. También lo probé sin promediar ( ADC->AVGCTRL.bit.SAMPLENUM = 0 ), nada cambió.

La hoja de datos recomienda realizar una conversión manual al principio, incluso si uso el modo freerunnig: ADC->SWTRIG.bit.START = 1; . Lo hice, pero no cambió nada.

¿Me perdí algo obvio?

    
pregunta vsz

1 respuesta

4

El ADC tiene entradas tanto negativas como positivas, pero parece que no es simplemente una característica adicional opcional. Tengo que especificar una entrada negativa, incluso si solo uso la positiva. (La hoja de datos no está muy clara aquí, solo menciona las entradas que se están utilizando en el cálculo si elijo la entrada diferencial en CTRLB.DIFFMODE, que no fue el caso aquí)

Después de configurar la entrada negativa a la tierra interna,

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

todo funciona como se espera.

Todavía no entiendo por qué funcionaba cuando se estableció un punto de interrupción, pero al menos el código funciona como debería.

    
respondido por el vsz

Lea otras preguntas en las etiquetas