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.

MCU-PLUS-SDK-AM263X: ADC DMA restart on demand.

Part Number: MCU-PLUS-SDK-AM263X


HI TI team:


I rework adc_soc_continuous_dma.c and implemented 32 reads with some periodicity and it works one time, it triggers DMA interrupt, and it is OK for me.

But I can't figure out how to reload this by demand.

I found another example in edma_interrupt_transfer.c:

    for(loopCnt = 0; loopCnt < (EDMA_TEST_B_COUNT * EDMA_TEST_C_COUNT); loopCnt++)
    {
        EDMA_enableTransferRegion(
            baseAddr, regionId, dmaCh, EDMA_TRIG_MODE_MANUAL);

        SemaphoreP_pend(&gEdmaTestDoneSem, SystemP_WAIT_FOREVER);
    }

And I tried to put this logic to adc_soc_continuous_dma example, but unfortunately, it does not help.

void adc_soc_continuous_dma_main(void *args)
{
    int32_t  status;
    Edma_IntrObject     intrObj;
    uint32_t     loopCnt = 0;
    uint32_t tccAlloc0, tccAlloc1, tccAlloc2;

    DebugP_log("ADC Continuous DMA transfer Test Started ...\r\n");

    /* Initialize both the result buffers with zeroes */
    for(loopCnt = 0U; loopCnt < RESULTS_BUFFER_SIZE; loopCnt++)
    {
        gUnusedBuffer[loopCnt] = 0U;
        gAdc0DataBuffer[loopCnt] = 0U;
        gAdc1DataBuffer[loopCnt] = 0U;
        gAdc2DataBuffer[loopCnt] = 0U;
    }

    /* Perform a cache write back to the result buffers */
    CacheP_wb((void *)gUnusedBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL);
    CacheP_wb((void *)gAdc0DataBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL);
    CacheP_wb((void *)gAdc1DataBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL);
    CacheP_wb((void *)gAdc2DataBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL);

    /* Create a semaphore to signal EDMA transfer completion */
    status = SemaphoreP_constructBinary(&gEdmaTransferDoneSem, 0);
    DebugP_assert(SystemP_SUCCESS == status);

    uint32_t regionId0;
    uint32_t regionId1;
    uint32_t regionId2;
    /* Configure DMA channels to transfer both ADC results */
    App_dmaConfigure_(gAdc0DataBuffer, RESULTS_BUFFER_SIZE, gEdmaHandle[0],
                ADC0_EDMA_CHANNEL, CONFIG_ADC0_RESULT_BASE_ADDR, &tccAlloc0, &regionId0);

    App_dmaConfigure_(gAdc1DataBuffer, RESULTS_BUFFER_SIZE, gEdmaHandle[0],
                ADC1_EDMA_CHANNEL, CONFIG_ADC1_RESULT_BASE_ADDR, &tccAlloc1, &regionId1);

    App_dmaConfigure_(gAdc2DataBuffer, RESULTS_BUFFER_SIZE, gEdmaHandle[0],
                ADC2_EDMA_CHANNEL, CONFIG_ADC2_RESULT_BASE_ADDR, &tccAlloc2, &regionId2);


    /* Register interrupt */
    intrObj.tccNum = tccAlloc0;
    intrObj.cbFxn  = &App_dmach0ISR;
    intrObj.appData = (void *) &gEdmaTransferDoneSem;
    status = EDMA_registerIntr(gEdmaHandle[0], &intrObj);
    DebugP_assert(status == SystemP_SUCCESS);


    /* Clear ADC Interrupt status */
    ADC_clearInterruptStatus(gAdc0baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptStatus(gAdc1baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptStatus(gAdc2baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptOverflowStatus(gAdc0baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptOverflowStatus(gAdc1baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptOverflowStatus(gAdc2baseAddr, ADC_INT_NUMBER1);


    /* RTI timer for trigering SOC ADC */
    TimerP_Params timerParams;
    TimerP_Params_init(&timerParams);
    timerParams.periodInUsec = 0;
    timerParams.periodInNsec = 1116;
    TimerP_setup(gTimerBaseAddr[CONFIG_TIMER_AI_MON], &timerParams);


    TimerP_start(gTimerBaseAddr[CONFIG_TIMER_AI_MON]);

    /*
     * Wait while DMA transfers ADC conversion results to buffer.
    */
    SemaphoreP_pend(&gEdmaTransferDoneSem, SystemP_WAIT_FOREVER);

    DebugP_log("test %u passed!!\r\n", __LINE__);
    loopCnt = 0;
    /* Print few elements from the result buffer */
    while(loopCnt < RESULTS_BUFFER_SIZE)
    {
        DebugP_log("%d : %d : %d\r\n", gAdc0DataBuffer[loopCnt], gAdc1DataBuffer[loopCnt], gAdc2DataBuffer[loopCnt]);
        loopCnt += 1;
    }
    memset(gAdc0DataBuffer, 0, sizeof(gAdc0DataBuffer));
    memset(gAdc1DataBuffer, 0, sizeof(gAdc0DataBuffer));
    memset(gAdc2DataBuffer, 0, sizeof(gAdc0DataBuffer));


    /* Clear ADC Interrupt status */
    ADC_clearInterruptStatus(gAdc0baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptStatus(gAdc1baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptStatus(gAdc2baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptOverflowStatus(gAdc0baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptOverflowStatus(gAdc1baseAddr, ADC_INT_NUMBER1);
    ADC_clearInterruptOverflowStatus(gAdc2baseAddr, ADC_INT_NUMBER1);


    EDMA_enableTransferRegion(EDMA_getBaseAddr(gEdmaHandle[0]), regionId0, ADC0_EDMA_CHANNEL,
                              EDMA_TRIG_MODE_EVENT);
    EDMA_enableTransferRegion(EDMA_getBaseAddr(gEdmaHandle[0]), regionId1, ADC1_EDMA_CHANNEL,
                                  EDMA_TRIG_MODE_EVENT);
    EDMA_enableTransferRegion(EDMA_getBaseAddr(gEdmaHandle[0]), regionId2, ADC2_EDMA_CHANNEL,
                                      EDMA_TRIG_MODE_EVENT);
    TimerP_start(gTimerBaseAddr[CONFIG_TIMER_AI_MON]);

    /*
     * Wait while DMA transfers ADC conversion results to buffer.
    */
    SemaphoreP_pend(&gEdmaTransferDoneSem, SystemP_WAIT_FOREVER);

//
//
//
// Can not reach there
//
//
//

    DebugP_log("test %u passed!!\r\n", __LINE__);
    loopCnt = 0;
    /* Print few elements from the result buffer */
    while(loopCnt < RESULTS_BUFFER_SIZE)
    {
        DebugP_log("%d : %d : %d\r\n", gAdc0DataBuffer[loopCnt], gAdc1DataBuffer[loopCnt], gAdc2DataBuffer[loopCnt]);
        loopCnt += 1;
    }
    
    
}

uint16_t App_dmaConfigure_(
        const uint16_t *table, uint16_t table_size,
        EDMA_Handle dma_handle, uint32_t dma_ch,
        uint32_t adc_base, uint32_t *tccAlloc, uint32_t *regionId)
{

    uint32_t            baseAddr;
    EDMACCPaRAMEntry    empty_edmaParam, edmaParam;
    uint32_t            empty_dmaCh, dmaCh, empty_tcc, tcc, empty_param, param;
    // EDMACCPaRAMEntry    empty_edmaParam;
    // uint32_t            empty_dmaCh, empty_tcc, empty_param;
    int32_t             testStatus = SystemP_SUCCESS;

    /* Enable only TC and ITC chaining on dmaCh0.
       TC and ITC interrupt enable not required. */
    uint32_t chainOptions = (EDMA_OPT_TCCHEN_MASK |
                             EDMA_OPT_ITCCHEN_MASK);

    baseAddr = EDMA_getBaseAddr(gEdmaHandle[0]);
    DebugP_assert(baseAddr != 0);

    *regionId = EDMA_getRegionId(gEdmaHandle[0]);
    DebugP_assert(*regionId < SOC_EDMA_NUM_REGIONS);

    empty_dmaCh = dma_ch;
    testStatus = EDMA_allocDmaChannel(gEdmaHandle[0], &empty_dmaCh);
    DebugP_assert(testStatus == SystemP_SUCCESS);

    /* typically allocates the next available channel */
    empty_tcc = EDMA_RESOURCE_ALLOC_ANY;
    testStatus = EDMA_allocTcc(gEdmaHandle[0], &empty_tcc);
    DebugP_assert(testStatus == SystemP_SUCCESS);

    empty_param = EDMA_RESOURCE_ALLOC_ANY;
    testStatus = EDMA_allocParam(gEdmaHandle[0], &empty_param);
    DebugP_assert(testStatus == SystemP_SUCCESS);

    dmaCh = EDMA_RESOURCE_ALLOC_ANY;
    testStatus = EDMA_allocDmaChannel(gEdmaHandle[0], &dmaCh);
    DebugP_assert(testStatus == SystemP_SUCCESS);

    tcc = EDMA_RESOURCE_ALLOC_ANY;
    testStatus = EDMA_allocTcc(gEdmaHandle[0], &tcc);
    DebugP_assert(testStatus == SystemP_SUCCESS);
    /* Passing back the Channel parameter to register the interrupt ISR*/
    *tccAlloc = tcc;

    param = EDMA_RESOURCE_ALLOC_ANY;
    testStatus = EDMA_allocParam(gEdmaHandle[0], &param);
    DebugP_assert(testStatus == SystemP_SUCCESS);

    /* Request channel */
    EDMA_configureChannelRegion(baseAddr, *regionId, EDMA_CHANNEL_TYPE_DMA,
         empty_dmaCh, empty_tcc, empty_param, EDMA_TEST_EVT_QUEUE_NO);

    /* Program Param Set */
    EDMA_ccPaRAMEntry_init(&empty_edmaParam);
    empty_edmaParam.srcAddr       = (uint32_t) SOC_virtToPhy((void *)(adc_base+CSL_ADC_RESULT_ADCRESULT0));
    empty_edmaParam.destAddr      = (uint32_t) SOC_virtToPhy((void *)gUnusedBuffer);
    empty_edmaParam.aCnt          = (uint16_t) 2;
    empty_edmaParam.bCnt          = (uint16_t) table_size;
    empty_edmaParam.cCnt          = (uint16_t) 1;
    empty_edmaParam.bCntReload    = 0;
    empty_edmaParam.srcBIdx       = (int16_t) EDMA_PARAM_BIDX(0);
    empty_edmaParam.destBIdx      = (int16_t) EDMA_PARAM_BIDX(2);
    empty_edmaParam.srcCIdx       = (int16_t) 0;
    empty_edmaParam.destCIdx      = (int16_t) 0;
    empty_edmaParam.linkAddr      = 0xFFFFU;
    empty_edmaParam.srcBIdxExt    = (int8_t) EDMA_PARAM_BIDX_EXT(0);
    empty_edmaParam.destBIdxExt   = (int8_t) EDMA_PARAM_BIDX_EXT(2);
    empty_edmaParam.opt           = (EDMA_OPT_TCINTEN_MASK | EDMA_OPT_ITCINTEN_MASK |
                              ((((uint32_t)empty_tcc) << EDMA_OPT_TCC_SHIFT) & EDMA_OPT_TCC_MASK));
    /* Enabling in options for the,
        the Transfer-complete Interrupt          --> After total data is transferred
    ,   Intermediate transfer complete interrupt --> After each A data chunk transfer is comeplete
            this will be used for the chaining of the actual transfer.
    */

    EDMA_setPaRAM(baseAddr, empty_param, &empty_edmaParam);

    EDMA_configureChannelRegion(baseAddr, *regionId, EDMA_CHANNEL_TYPE_DMA,
            dmaCh, tcc, param, EDMA_TEST_EVT_QUEUE_NO);

    /* Program Param Set */
    EDMA_ccPaRAMEntry_init(&edmaParam);
    edmaParam.srcAddr       = (uint32_t) SOC_virtToPhy((void *)(adc_base+CSL_ADC_RESULT_ADCRESULT0));
    edmaParam.destAddr      = (uint32_t) SOC_virtToPhy((void *)table);
    edmaParam.aCnt          = (uint16_t) 2;
    edmaParam.bCnt          = (uint16_t) table_size;
    edmaParam.cCnt          = (uint16_t) 1;
    edmaParam.bCntReload    = 0;
    edmaParam.srcBIdx       = (int16_t) EDMA_PARAM_BIDX(0);
    edmaParam.destBIdx      = (int16_t) EDMA_PARAM_BIDX(2);
    edmaParam.srcCIdx       = (int16_t) 0;
    edmaParam.destCIdx      = (int16_t) 0;
    edmaParam.linkAddr      = 0xFFFFU;
    edmaParam.srcBIdxExt    = (int8_t) EDMA_PARAM_BIDX_EXT(0);
    edmaParam.destBIdxExt   = (int8_t) EDMA_PARAM_BIDX_EXT(2);
    edmaParam.opt           = (EDMA_OPT_TCINTEN_MASK |
                              ((((uint32_t)tcc) << EDMA_OPT_TCC_SHIFT) & EDMA_OPT_TCC_MASK));
    /* Enabling the Interrupt for Transfer complete of all the data */
    EDMA_setPaRAM(baseAddr, param, &edmaParam);

    /* Chain the empty transfer to the actual transfer.
    Chain options include Total transfer completion and intermediate channel completion flags
    from empty channel*/

    EDMA_chainChannel(baseAddr, empty_param, dmaCh, chainOptions);

    /* Enabling the transfer region for empty channel for the trigger mode set in the Syscfg through
    the DMA Xbars adn DMA TRIG Xbars.*/
    EDMA_enableTransferRegion(baseAddr, *regionId, empty_dmaCh,
                              EDMA_TRIG_MODE_EVENT);

    return testStatus;
}

void App_dmach0ISR(Edma_IntrHandle intrHandle, void *args)
{
    SemaphoreP_Object *semObjPtr = (SemaphoreP_Object *)args;
    DebugP_assert(semObjPtr != NULL);

    TimerP_stop(gTimerBaseAddr[CONFIG_TIMER_AI_MON]);

    /* Post the semaphore to signal end of DMA transfer */
    SemaphoreP_post(semObjPtr);
}

Why App_dmach0ISR() calling once?

How to reload the transfer configuration? Or we should re-allocate resources for reinitialization DMA configuration and interrupt config, I doubt it is the correct way.

Regards!

  • Hey Oleg,

    Is the issue that App_dmach0ISR() is only being called once? I also see a commented section in your code that says "Can not reach there". Does the SemaphoreP_pend function not return?

    What do you mean by "reload this by demand"?

    I don't think you should need to reload your transfer configuration every time, however I am looping in our EDMA expert for some additional feedback.

    Best Regards,

    Zackary Fleenor

  • Hi Fleenor!
    The App_dmach0ISR() function calls once and successfully posts binSemaphore at line 73. After that, I need to repeat this procedure by demand, but in this example, I provided I simplified it, and trying to repeat ADC reading 32 times immediately after line 73. But how to do it correctly I can not figure out.

  • Hello Oleg,

    Let me reach out to our DMA expert for additional feedback here to trigger repeated adc results reading. Thank you for your patience.

    Best Regards,

    Zackary Fleenor

  • Hi Oleg,

    You have not understood the EDMA example correctly. The EDMA example EDMA_enableTransferRegion is a manual trigger whereas in case of ADC_CONTINOUS_DMA example it is event based. The trigger is generated via ADC_INT configured in syscfg whereas in EDMA example the manual trigger are in-between triggers in a A-Sync Transfer.

    You calling it again will not change anything. Also the PaRAM set you have been using is all used up and you need to reconfigure your region and paRam set again in the ISR.

    I hope this helps.

    Best Regards,
    Aakash