This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430F6736A: ADC10 sometimes stops working

Part Number: MSP430F6736A

Hi,

As I'm using DMA to transfer data from ADC10 to memory, occasionally (only observed twice in the past 6 months) I have noticed ADC module getting stuck and unable to function. I'm not able to determine if this is due to a loss of interrupt or a stuck module. In ADC function watchdog timer is cleared, but it does not recover after watchdog reset, but when I turn off main board power ON and OFF it does recover.  

Below is my code ADC10 -

// Initializing ADC10 module

void initAdc10(void) {
// Disable DMA and ADC
ADC10_A_disable(ADC10_A_BASE);
ADC10_A_clearInterrupt(ADC10_A_BASE, 0xff);
DMA_clearInterrupt(DMA_CHANNEL_0);
DMA_clearNMIAbort(DMA_CHANNEL_0);
DMA_disableInterrupt(DMA_CHANNEL_0);
DMA_disableTransfers(DMA_CHANNEL_0);
/* Delay */
__delay_cycles(2560000);
// Setup P1.2 A0, 1.1 A1, 1.0 A2
P1SEL |= BIT0 | BIT1 | BIT2; // Set P1.0,.1,.2 to non-IO
__disable_interrupt(); // Disable interrupts; Port Map cnfg
PMAPKEYID = PMAPKEY; // Enable access Port Mapping regs
P1MAP2 = PM_ANALOG; // Enable A0
P1MAP1 = PM_ANALOG; // Enable A1
P1MAP0 = PM_ANALOG; // Enable A2
PMAPKEYID = 0; // Disable access Port Mapping regs
__enable_interrupt(); // Re-enable all interrupts

// Setup ADC10
ADC10CTL0 = ADC10SHT_2 | ADC10MSC | ADC10ON; // 16ADCclks, MSC, ADC ON
ADC10CTL1 = ADC10SHP | ADC10CONSEQ_3; // pulse sample mode, repeated sequence
ADC10CTL2 = ADC10RES; // 10-bit resolution
ADC10MCTL0 = ADC10INCH_2; // A0,A1,A2(EoS), AVCC reference

// Setup DMA0 (ADC10IFG trigger)
DMACTL0 = DMA0TSEL_24; // ADC10IFG trigger
/* Read-modify-write disable */
//DMACTL0 = DMARMWDIS;
/* clear DMA interrupt flag */
DMA0CTL &= ~DMAIFG;
DMA0SZ = 192; // 192 conversions
__data20_write_long((uintptr_t) &DMA0SA, (uintptr_t) &ADC10MEM0);
// Source single address
__data20_write_long((uintptr_t) &DMA0DA, (uintptr_t) &ADC_Result[0]);
// Destination array address
DMA0CTL = DMADT_4 | DMADSTINCR_3 | DMASWDW | DMAEN | DMAIE;
}

Interrupt Code:

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=DMA_VECTOR
__interrupt void DMA0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(DMA_VECTOR))) DMA0_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch (__even_in_range(DMAIV, 16))
{
case DMAIV_NONE: break; // No interrupts
case DMAIV_DMA0IFG: // DMA0IFG = DMA Channel 0
ADC10CTL0 &= ~ADC10ENC; // conversions complete
dma_adc_flag = 2;
break;
case DMAIV_DMA1IFG: break; // DMA1IFG = DMA Channel 1
case DMAIV_DMA2IFG: break; // DMA2IFG = DMA Channel 2
case 8: break; // Reserved
case 10: break; // Reserved
case 12: break; // Reserved
case 14: break; // Reserved
case 16: break; // Reserved
default: break;
}
}



Main Function:

int dma_adc_flag = 0;

void Adc10Main(void) {

if (ADC10CTL1 & ADC10BUSY) {
return;
}

if (!dma_adc_flag) {
ADC10CTL0 |= ADC10ENC | ADC10SC; // Sampling and conversion start
dma_adc_flag = 1;
return;
} else if (dma_adc_flag == 1) {
return;
}
dma_adc_flag = 0;

/* Clear Watchdog Timer */
WDT_A_resetTimer(WDT_A_BASE);

}

Could you please help me with this? Thanks in advance.

Rahul

  • Hello Rahul,

    When posting code to the forum, please utilize the "Insert -> </> Code" utility so it can format it correctly for readability. I've already edited your post to reflect this change.

    Since this happens so infrequently, its hard to tell what could be going on. It could be a loss of an interrupt, but can't really tell without more information. If you can find a way to accelerate the issue to happen more frequently that can help. It is sometimes difficult to debug with DMA operations happening, so my suggestion would be to utilize some spare GPIO that you could monitor that you can utilize to figure out what state of your program you are in. Could use one GPIO to tell you if you just finished a DMA transfer or in the DMA interrupt for instance. And another to tell you have you finished you ADC sampling sequence or not. From that information, you can narrow down further the issue. 

  • Hi Jace,

    Thank you for your reply and for formatting the code. Would it be possible to recover it from a soft reset instead of a power reboot so that next time if it happens, the watchdog reset would resolve the issue.  

  • Rahul,

    Ideally that would be the case, but it depends on the error you are having. There are some errata that can cause a latch up or  if your CPU gets corrupted somehow. I didn't see anything at a cursory glance from errata perspective that you could be hitting that could cause that kind of behavior. Without more information about how/where the issue is occuring, there is not much more I can tell you. 

  • Hi Jace,

    Sometimes, I am able to reproduce the issue if I comment the ADC10CTL1 & ADC10BUSY condition in code. The ADC conversion has not completed and I am restarting it, therefore no interrupt is generated.

    void Adc10Main(void) {
    
    // Comment below function to reproduce the issue
    //if (ADC10CTL1 & ADC10BUSY) {
    //return;
    //}
    
    if (!dma_adc_flag) {
    ADC10CTL0 |= ADC10ENC | ADC10SC; // Sampling and conversion start
    dma_adc_flag = 1;
    return;
    } else if (dma_adc_flag == 1) {
    return;
    }
    dma_adc_flag = 0;
    
    /* Clear Watchdog Timer */
    WDT_A_resetTimer(WDT_A_BASE);
    
    }

  • Rahul,

    The issue you are seeing when commenting out is just that, your ADC has not finish conversion and you restart the ADC.  Please refer to teh following good example to move forward: https://dev.ti.com/tirex/explore/node?node=AM2vZTJjOCTLrhlLkBUfYQ__IOGqZri__LATEST 

    You may also want to check out the errata document for the device to see if you are hitting any of those conditions. In particular you should look ADC42, ADC69, and/or DMA7 as they have to do with loss of interrupts or results. 

**Attention** This is a public forum