Go Down

Topic: Arduino M0 pro ADC free running with interrupt (Read 518 times) previous topic - next topic

parsec326

I'm trying to program the ADC on the M0 pro. My goal is to capture an ADC sample every 0.5ms on 6 channels. But right now I'm trying to implement an ADC interrupt on just one channel AIN[0].

I've been following the code samples at: https://forcetronic.blogspot.com/2016/10/utilizing-advanced-adc-capabilities-on.html

The problem I'm having in my code is that ADC interrupt is not triggered at all. I'm not sure what I'm doing wrong. I'm setting up the clocks, and then initializing the ADC and then setting up the interrupt. But when I try to test the interrupt by toggling a I/O pin, the interrupt is NOT triggered. Any guidance is much appreciated. Thank you!!!
Code: [Select]


void adc_init(void){
// Configure clock source and clock generators (gclk.h)------------------------   
    GCLK->GENDIV.reg =  GCLK_GENDIV_ID(5) |   // Select GLCK5
                        GCLK_GENDIV_DIV(1);   // Select prescalar 1
    while (GCLK->STATUS.bit.SYNCBUSY);        // Wait for SYNC

    GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(5) |        // Select GCLK5
                        GCLK_GENCTRL_SRC_DFLL48M |  // Select GCLK SRC
                        GCLK_GENCTRL_IDC |          // Improve duty cycle for odd div factors
                        GCLK_GENCTRL_GENEN;         // Enable GCLK5
    while (GCLK->STATUS.bit.SYNCBUSY);        // Wait for SYNC

    GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK5 |  // Select GLCK5
                        GCLK_CLKCTRL_ID_ADC |     // Connect to ADC
                        GCLK_CLKCTRL_CLKEN;
    while (GCLK->STATUS.bit.SYNCBUSY);        // Wait for SYNC
   
// Configure power manager (pm.h)-------------------------------------------
    PM->APBCMASK.reg =  PM_APBCMASK_ADC;   // Setup Power manager for ADC peripheral
    PM->APBCSEL.reg = PM_APBCSEL_APBCDIV_DIV1; // Select prescalar 1

// ADC configuration (adc.h) ----------------------------------------------
    ADC->CTRLA.reg &= ~ADC_CTRLA_ENABLE; // Disable ADC peripheral
    while(ADC->STATUS.bit.SYNCBUSY);  // Wait of sync
   
    ADC->REFCTRL.reg = ADC_REFCTRL_REFCOMP |    // REF buffer offset compensation enable
                       ADC_REFCTRL_REFSEL_INT1V;  //1.0V REF selected
 
    ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1;
   
    ADC->SAMPCTRL.reg = ADC_SAMPCTRL_SAMPLEN(0x00);

    ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV4 | // ADC CLK prescalar 4
                     ADC_CTRLB_RESSEL_12BIT | // 12-bit ADC result
                     ADC_CTRLB_FREERUN; // ADC free run mode                     
    while(ADC->STATUS.bit.SYNCBUSY);

    ADC->WINCTRL.reg = ADC_WINCTRL_WINMODE_DISABLE; // Disable window monitor mode
    while(ADC->STATUS.bit.SYNCBUSY);

    ADC->INPUTCTRL.reg = ADC_INPUTCTRL_GAIN_1X | // ADC gain factor x1
                         ADC_INPUTCTRL_INPUTSCAN(0x0)| // Number of channels included in scan
                         ADC_INPUTCTRL_MUXPOS_PIN0 | // Positive MUX input selection
                         ADC_INPUTCTRL_MUXNEG_GND;
    while(ADC->STATUS.bit.SYNCBUSY);

// Configure ADC interrupts ------------------------------------------
    ADC->INTENCLR.reg = ADC_INTENCLR_RESRDY; // Clear result ready interrupt
    ADC->INTENSET.reg = ADC_INTENSET_RESRDY; // Set result ready interrupt
    NVIC_SetPriority(ADC_IRQn, 3);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TCC1 to 0 (highest)
    NVIC_EnableIRQ(ADC_IRQn);         // Connect ADC to Nested Vector Interrupt Controller (NVIC)

// Input and output pins---------------------------------------------------
    PORT->Group[PORTA].PINCFG[2].bit.PMUXEN = 1; // Peripheral mux enable PWM
    PORT->Group[PORTA].PMUX[1].reg = PORT_PMUX_PMUXE_B;  // Enable PMUX group B Even pins

// Enable ADC--------------------------------------------------------------
    ADC->CTRLA.reg = ADC_CTRLA_ENABLE; // Enable ADC peripheral
    while(ADC->STATUS.bit.SYNCBUSY);  // Wait of sync

    ADC->SWTRIG.reg = ADC_SWTRIG_START; // Start ADC conversion
    while(ADC->STATUS.bit.SYNCBUSY); // Wait for sync

}

void ADC_Handler(void){
   PORT->Group[PORTA].OUTTGL.reg = PORT_PA21;
   if (ADC->INTFLAG.bit.RESRDY && ADC->INTENSET.bit.RESRDY) {  // A overflow caused the interrupt
         ADCresult = ADC->RESULT.reg;
         ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;   // reset interrupt flag
    }
}



parsec326

I think I have figured out what's happening. I'm initializing two timers (TCC0, TCC1) and the external interrupt controller (EIC) along with the ADC and IO ports. And I found out that the order of initialization matters. So this works:
Code: [Select]

void setup(void){
    timer_init();
    adc_init();
    eic_init();
    port_init();
}


but this does not

Code: [Select]

void setup(void){
    timer_init();
    eic_init();
    adc_init();
    port_init();
}




parsec326

@pert:

I tried to delete my post in the Microcontroller forum, but I don't have the permission to delete. Sorry for the double post! This is the correct forum for my question.

pert

If you need to have a thread moved you can click the "Report to moderator" button and ask nicely for them to move it but it's best to take the time to find the best forum section before posting because the mods have plenty of work to do already.

Go Up