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.

MSP432P401R ADC+DMA issue

Hello experts,

Since MSP432 is quite new for our local team here, one of my customers Schneider Electric is using MSP432P401R LaunchPad for their new project, they have an ADC+DMA issue pending couple days as described below, does anyone know how to fix this?

Thank you very much!

Issue description:
ADC + DMA:
1. ADC works in 1M sampling frequency and repeat sequence mode
2. DMA is triggered by ADC to move ADC samples to memory and work in PINGPONG mode
3. No MCU intervention

Currently ADC is working correct, but it seems that it does not trigger successfully DMA to transfer data to memory.
I am not sure if there is some bugs in the firmware to cause the issue.

I also found out ADC53 issue below in a document downloaded in TI website

  • Hello Yan,

    You are correct in suggesting that the ADC53 errata is the source of your customer's issue, this bug has no workaround but is planned to be fixed for the RTM revision. Meanwhile your customer can use an ADC ISR to manually request a DMA transfer or operate the ADC in sequence-of-channels mode and manually start conversions repeatedly.

    Regards,
    Ryan
  • Hello Ryan
    I am the customer Yan mentioned.
    Now i modified my code below, and ADC is working in single-repeat mode. (Hardware is MSP432p401R launchpad)

    /* DMA Control Table */
    #ifdef ewarm
    #pragma data_alignment=256
    #else
    #pragma DATA_ALIGN(controlTable, 256)
    #endif
    uint8_t controlTable[256];

    #define ADC_BUFSIZE 128
    #define ADC_SAMPLE_TYPE uint32_t

    static ADC_SAMPLE_TYPE recBuffer[ADC_BUFSIZE*2];

    #define ADC_MEM0_ADDR ((void*)(0x40012098))

    int main(void)
    {
    /* Halting the Watchdog */
    MAP_WDT_A_holdTimer();

    memset(recBuffer, 0xFF, ADC_BUFSIZE * 2 * sizeof(ADC_SAMPLE_TYPE));

    /* Configuring pins for peripheral/crystal usage and LED for output */
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,
    GPIO_PIN3 | GPIO_PIN4, GPIO_PRIMARY_MODULE_FUNCTION);
    MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);

    /* Setting the external clock frequency. This API is optional, but will
    * come in handy if the user ever wants to use the getMCLK/getACLK/etc
    * functions
    */
    CS_setExternalClockSourceFrequency(32000,48000000);

    /* Starting HFXT in non-bypass mode without a timeout. Before we start
    * we have to change VCORE to 1 to support the 48MHz frequency */
    MAP_PCM_setCoreVoltageLevel(PCM_VCORE1);
    MAP_FlashCtl_setWaitState(FLASH_BANK0, 2);
    MAP_FlashCtl_setWaitState(FLASH_BANK1, 2);
    CS_startHFXT(false);

    /* Initializing MCLK to HFXT (effectively 48MHz) */
    MAP_CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);

    /* for debug */
    uint32_t fre_smclk = CS_getSMCLK();
    uint32_t fre_mclk = CS_getMCLK();

    /*****************************ADC initialization*******************************/
    /* Initializing ADC (MCLK/4/6) */
    MAP_ADC14_enableModule();
    MAP_ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,
    0);
    /* Configuring GPIOs (5.5 A0) */
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN5,
    GPIO_TERTIARY_MODULE_FUNCTION);

    /* Configuring ADC Memory */
    MAP_ADC14_configureSingleSampleMode(ADC_MEM0, true);
    MAP_ADC14_configureConversionMemory(ADC_MEM0, ADC_VREFPOS_AVCC_VREFNEG_VSS,
    ADC_INPUT_A0, false);

    MAP_ADC14_enableSampleTimer(ADC_AUTOMATIC_ITERATION);
    //MAP_ADC14_enableSampleTimer(ADC_MANUAL_ITERATION);
    /******************************************************************************/

    /*****************************DMA initialization*******************************/
    /* Configuring DMA module */
    MAP_DMA_enableModule();
    MAP_DMA_setControlBase(controlTable);

    // Assigning Channel 7 to adc14
    MAP_DMA_assignChannel(DMA_CH7_ADC12C);

    // Disabling channel attributes */
    MAP_DMA_disableChannelAttribute(DMA_CH7_ADC12C,
    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
    UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK);

    // Setting Control Indexes
    MAP_DMA_setChannelControl(UDMA_PRI_SELECT | DMA_CH7_ADC12C,
    UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_ARB_1);
    MAP_DMA_setChannelTransfer(UDMA_PRI_SELECT | DMA_CH7_ADC12C,
    UDMA_MODE_PINGPONG/*UDMA_MODE_BASIC*/,
    ADC_MEM0_ADDR, (void*)recBuffer,
    ADC_BUFSIZE);

    MAP_DMA_setChannelControl(UDMA_ALT_SELECT | DMA_CH7_ADC12C,
    UDMA_SIZE_32 | UDMA_SRC_INC_NONE | UDMA_DST_INC_32 | UDMA_ARB_1);
    MAP_DMA_setChannelTransfer(UDMA_ALT_SELECT | DMA_CH7_ADC12C,
    UDMA_MODE_PINGPONG/*UDMA_MODE_BASIC*/,
    ADC_MEM0_ADDR, (void*)&recBuffer[ADC_BUFSIZE],
    ADC_BUFSIZE);

    /* Assigning/Enabling Interrupts */
    MAP_DMA_assignInterrupt(DMA_INT1, DMA_CH7_ADC12C);
    MAP_DMA_clearInterruptFlag(DMA_CH7_ADC12C);

    /* Now that the DMA is primed and setup, enabling the channels. The EUSCI
    * hardware should take over and transfer/receive all bytes */
    MAP_DMA_enableChannel(DMA_CH7_ADC12C);

    MAP_Interrupt_enableInterrupt(INT_DMA_INT1);
    /******************************************************************************/

    /* Enabling/Toggling Conversion */
    MAP_ADC14_enableConversion();
    MAP_ADC14_toggleConversionTrigger();

    /* Enabling MASTER interrupts */
    MAP_Interrupt_enableMaster();

    while (1)
    {
    MAP_PCM_gotoLPM0();
    }
    }

    /* DMA INT1 interrupt handler */
    void dma_1_interrupt(void)
    {
    DMA_clearInterruptFlag(DMA_CH7_ADC12C);

    // Check if the ping-pong "A" transfer is complete.
    uint32_t ui32Mode = MAP_DMA_getChannelMode( DMA_CH7_ADC12C | UDMA_PRI_SELECT);
    if (ui32Mode == UDMA_MODE_STOP)
    {
    MAP_DMA_setChannelTransfer(UDMA_PRI_SELECT | DMA_CH7_ADC12C,
    UDMA_MODE_PINGPONG/*UDMA_MODE_BASIC*/,
    ADC_MEM0_ADDR, (void*)recBuffer,
    ADC_BUFSIZE);
    }

    // Check if the ping-pong "B" transfer is complete.
    ui32Mode = MAP_DMA_getChannelMode( DMA_CH7_ADC12C | UDMA_ALT_SELECT);
    if (ui32Mode == UDMA_MODE_STOP)
    {
    MAP_DMA_setChannelTransfer(UDMA_ALT_SELECT | DMA_CH7_ADC12C,
    UDMA_MODE_PINGPONG/*UDMA_MODE_BASIC*/,
    ADC_MEM0_ADDR, (void*)(&recBuffer[ADC_BUFSIZE]),
    ADC_BUFSIZE);
    }

    MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
    }

    New issue is:
    In interrupt handler, ping-pong "A" and "B" are reset only once, but interrupt routine keeps being entered. I checked the controlTable
    A and B keep 'not completed' status. I don't know what happened.
    Could you please help me to check my code to find some clues?
  • Hello bj Wang,

    Please refer to the following E2E thread in which Tim explains how to properly set up the MSP432 DMA for ping-pong communication: e2e.ti.com/.../425881

    Do you have a specific reason to use ping-pong mode? Basic mode seems sufficient for your application.

    Regards,
    Ryan
  • Hello Ryan
    we use ping-pong buffer to avoid missing data because we want to sample the data in 1M HZ, and these data will happend in a very short time( 20~30us ) once. Sampling frequency is so high, we hope that ADC can work automatically and repeatly without MCU intervention and Timer trigger.Meanwhile ADC can trigger DMA to transfer data after got a new sample.
    Regarding the thread you suggest, my code is based on it about ping-pong buffer setting.
  • Hello Ryan
    I found out the root cause that DMA stops working. It seems that it is because i set break point in interrupt handler.
    Thank you for your reply

**Attention** This is a public forum