Go Down

Topic: ADC init and interrupt stops SerialUSB communication (Read 300 times) previous topic - next topic

parsec326

I'm trying to debug and verify my ADC input by echoing it back in the programming port serial communcation channel. I'm seeing a weird bug where when I initialize the ADC in free running mode and start the ADC RESRDY interrupt, the serial communication drops out. Even more interesting is that when I tried to figure out what's happening apparently, it looks like the processor does not enter the loop() at all when my ADC is initialized and operational. My ADC init and interrupt code:
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(64);   // 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(0x01);

    ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV64 | // 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 ADC
    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){
    if (ADC->INTFLAG.bit.RESRDY && ADC->INTENSET.bit.RESRDY) {  // A overflow caused the interrupt
         ADCresult = ADC->RESULT.reg;
         while(ADC->STATUS.bit.SYNCBUSY);
         ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;   // reset interrupt flag
    }
}


My main code:
Code: [Select]

unsigned int ADCresult = 0;

void setup() {
  // adc_init();
   port_init();
   Serial.begin(9600,SERIAL_8N1);
}

void loop() {
  Serial.println("ADCresult");
  delay(100);
}

Any theories on why this is happening? Serial comm works fine when I comment out the adc_init() section.

AloyseTech

Hi,

Have you tried to enable the IRQ after enabling the ADC?

parsec326

Thanks for the reply AloyseTech!

I did try to initialize the interrupt AFTER starting the ADC. Same result. The processor does not step into the loop() code at all if the ADC is initialized and running (even once!). But if I disable the ADC, then the processor steps through the loop() code.

BTW, I tried turning OFF the Free run mode, so that the ADC is essentially doing one conversion and then stop. Even in this case, the processor does not step through the loop() code.

My suspicion is that Serial.begin() and Serial.println() functions are doing something weird. Do you think this would be a good place to look for the problem?

AloyseTech

You could try the following things :
- change interrupt priority (Serial use interrupt too AFAIK)
- try clearing interrupt using NVIC_ClearPendingIRQ
- Use the EDBG to debug your code
- Use SerialUSB instead of Serial

parsec326

Thank you AloyseTech, your directions really helped!

- change interrupt priority - set ADC interrupt as highest (0) and low (8 ) - no effect
- try clearing interrupt using NVIC_ClearPendingIRQ(ADC_IRQn) - no effect
- EDBG to debug the code - I need more information about how to use the EDBG with Arduino IDE. There is nothing in the IDE that points out a debugger interface. Can you point me to any references that discuss this scenario?

- Use SerialUSB instead of Serial - THIS WORKS!!! I can see that the controller is actually stepping into the loop() code. Now how do I (safely) read the serial data? Can I connect a second USB cable to the native port and start listening? I cannot use the  Arduino IDE Serial monitor in this case, correct? I'm guessing I'll have to use different tool like PuTTY.

AloyseTech

You can use the Native port for programming and Serial communication instead of the EDBG/"Programming port". In this case, you only have to call SerialUSB instead of Serial. You can still use the Serial monitor of the Arduino IDE normally. What exactly is your application?

parsec326

My end application is inverter control but in this particular situation I want to sample the ADC in the M0 pro to capture a 60 Hz AC signal with sufficient number of samples. So I need to verify the ADC sampled data before I do any further calculation.

BTW, dp you know if Arduino have any plans to release a debugger interface for the IDE? Or if there are third party alternatives to use the EDBG on the M0 pro?

AloyseTech

This is an awaited feature indeed. I'm sure there is plan to add debugging interface ine the IDE, but the question is when will it be available. In the meantime, you can use this guide from Adafruit. There is also people claiming debugging works using Eclipse IDE but haven't tried it yet.

Go Up