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.
Dear TI experts,
We are using the example adc_soc_continuous_dma from SDK.
In this example the DMA is configured have a interrupt only once but we are trying to get subsequent interrupt from ADC which is a trigger for DMA.
We need ADC interrupt ---> DMA interrupt that occurs indefinately after every ADC conversion.
So the below changes we have done:
1) Commented the disable trigger from PWM as this is needed for ADC functioning.
2) Commented the function which stops the ADC as shown below in DMA ISR:
3) Performed the Cache Invalidation after DMA completes the transfer and again Validation in the next iteration.
Please find the entrie code below:
/* * Copyright (C) 2022 Texas Instruments Incorporated * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <kernel/dpl/DebugP.h> #include <kernel/dpl/ClockP.h> #include <kernel/dpl/SemaphoreP.h> #include <kernel/dpl/HwiP.h> #include <drivers/epwm.h> #include <drivers/adc.h> #include "ti_drivers_config.h" #include "ti_drivers_open_close.h" #include "ti_board_open_close.h" /* * This example sets up two ADC channels to convert simultaneously. The * results will be transferred by DMA into a buffer in RAM. * * It configures ePWM0 to trigger SOC0 on ADC0 and ADC1. EPWM is only used to * trigger the first ADC conversion. INT0 of ADC0 is configured to generate * interrupt after first conversion and will then disable EPWM SOC generation. * INT1 of both ADC's is configured to enable continuous conversion. * * DMA channel 0 is triggered at EOC0 of ADC0 and will copy conversion result * to a buffer in RAM. DMA channel 1 is triggered at EOC0 of ADC1 and will copy * conversion result to another buffer in RAM. DMA will generate interrupt after * the buffer is filled and will stop conversion on both ADC's. * * The below watch variables can be used to view ADC conversion results. * * External Connections * ADC0_AIN0 and ADC1_AIN0 pins should be connected to signals to be converted. * * Watch Variables * gAdc0DataBuffer - Buffers which stores conversion results from ADC0 * gAdc1DataBuffer - Buffers which stores conversion results from ADC1 */ /* Size of buffer for storing conversion results */ #define RESULTS_BUFFER_SIZE 1024 /* Event queue to be used for EDMA transfer */ #define EDMA_TEST_EVT_QUEUE_NO 0U /* DMA channel number to transfer ADC0 and ADC1 conversion results*/ #define ADC0_EDMA_CHANNEL (DMA_TRIG_XBAR_EDMA_MODULE_0) #define ADC1_EDMA_CHANNEL (DMA_TRIG_XBAR_EDMA_MODULE_1) /* Global variables and objects */ /* Buffers to store conversion results from ADC0 and ADC1 */ uint16_t gAdc0DataBuffer[RESULTS_BUFFER_SIZE]; uint16_t gAdc1DataBuffer[RESULTS_BUFFER_SIZE]; static HwiP_Object gAdcHwiObject; /* Semaphore to indicate transfer completion */ static SemaphoreP_Object gEdmaTransferDoneSem; /* ADC instance base addresses */ uint32_t gAdc0baseAddr = CONFIG_ADC0_BASE_ADDR; uint32_t gAdc1baseAddr = CONFIG_ADC1_BASE_ADDR; /* Function Prototypes */ 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); static void App_adcISR(void *args); static void App_dmach0ISR(Edma_IntrHandle intrHandle, void *args); void adc_soc_continuous_dma_main(void *args) { int32_t status; Edma_IntrObject intrObj; HwiP_Params hwiPrms; uint32_t loopCnt = 0; uint32_t tccAlloc0, tccAlloc1; /* Open drivers to open the UART driver for console */ Drivers_open(); Board_driversOpen(); 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++) { gAdc0DataBuffer[loopCnt] = 0U; gAdc1DataBuffer[loopCnt] = 0U; } /* Perform a cache write back to the result buffers */ CacheP_wb((void *)gAdc0DataBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL); CacheP_wb((void *)gAdc1DataBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL); /* Register & enable interrupt */ HwiP_Params_init(&hwiPrms); hwiPrms.intNum = CSLR_R5FSS0_CORE0_CONTROLSS_INTRXBAR0_OUT_0; hwiPrms.callback = &App_adcISR; status = HwiP_construct(&gAdcHwiObject, &hwiPrms); DebugP_assert(status == SystemP_SUCCESS); /* Create a semaphore to signal EDMA transfer completion */ status = SemaphoreP_constructBinary(&gEdmaTransferDoneSem, 0); DebugP_assert(SystemP_SUCCESS == status); /* 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); App_dmaConfigure(gAdc1DataBuffer, RESULTS_BUFFER_SIZE, gEdmaHandle[0], ADC1_EDMA_CHANNEL, CONFIG_ADC1_RESULT_BASE_ADDR, &tccAlloc1); /* 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(gAdc0baseAddr,ADC_INT_NUMBER2); ADC_clearInterruptStatus(gAdc1baseAddr,ADC_INT_NUMBER1); ADC_clearInterruptStatus(gAdc1baseAddr,ADC_INT_NUMBER2); /* Enable event counter init for SOCA */ EPWM_enableADCTriggerEventCountInit(CONFIG_EPWM0_BASE_ADDR, EPWM_SOC_A); /* Set the event counter init value to 0 */ EPWM_setADCTriggerEventCountInitValue(CONFIG_EPWM0_BASE_ADDR, EPWM_SOC_A, 0); /* Force the event counter init value to event counter */ EPWM_forceADCTriggerEventCountInit(CONFIG_EPWM0_BASE_ADDR, EPWM_SOC_A); EPWM_clearADCTriggerFlag(CONFIG_EPWM0_BASE_ADDR, EPWM_SOC_A); /* Enable ADC Trigger from EPWM to start ADC conversion */ EPWM_enableADCTrigger(CONFIG_EPWM0_BASE_ADDR, EPWM_SOC_A); EPWM_setADCTriggerSource(CONFIG_EPWM0_BASE_ADDR, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO, EPWM_SOC_TBCTR_ZERO); EPWM_setADCTriggerEventPrescale(CONFIG_EPWM0_BASE_ADDR, EPWM_SOC_A, 1); /* * Wait while DMA transfers ADC conversion results to buffer. */ SemaphoreP_pend(&gEdmaTransferDoneSem, SystemP_WAIT_FOREVER); /* Invalidate destination buffer */ CacheP_inv((void *)gAdc0DataBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL); CacheP_inv((void *)gAdc1DataBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL); /* Perform a cache write back to the result buffers */ CacheP_wb((void *)gAdc0DataBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL); CacheP_wb((void *)gAdc1DataBuffer, RESULTS_BUFFER_SIZE*2, CacheP_TYPE_ALL); while() { } DebugP_log("ADC0 : ADC1 Result register value -\r\n"); loopCnt = 0; /* Print few elements from the result buffer */ while(loopCnt < RESULTS_BUFFER_SIZE) { DebugP_log("%d : %d\r\n", gAdc0DataBuffer[loopCnt], gAdc1DataBuffer[loopCnt]); loopCnt += 100; } DebugP_log("ADC Continuous DMA transfer Test Passed\r\n"); DebugP_log("All tests have passed!!\r\n"); Board_driversClose(); Drivers_close(); } 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 baseAddr, regionId; EDMACCPaRAMEntry edmaParam; uint32_t dmaCh, tcc, param; int32_t testStatus = SystemP_SUCCESS; baseAddr = EDMA_getBaseAddr(gEdmaHandle[0]); DebugP_assert(baseAddr != 0); regionId = EDMA_getRegionId(gEdmaHandle[0]); DebugP_assert(regionId < SOC_EDMA_NUM_REGIONS); dmaCh = dma_ch; 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); *tccAlloc = tcc; param = EDMA_RESOURCE_ALLOC_ANY; testStatus = EDMA_allocParam(gEdmaHandle[0], ¶m); DebugP_assert(testStatus == SystemP_SUCCESS); /* Request channel */ 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)); EDMA_setPaRAM(baseAddr, param, &edmaParam); EDMA_enableTransferRegion(baseAddr, regionId, dmaCh, EDMA_TRIG_MODE_EVENT); return testStatus; } void App_adcISR(void *args) { /* Remove ePWM trigger */ //EPWM_disableADCTrigger(CONFIG_EPWM0_BASE_ADDR, EPWM_SOC_A); /* Disable this interrupt from happening again */ //ADC_disableInterrupt(gAdc0baseAddr, ADC_INT_NUMBER1); } void App_dmach0ISR(Edma_IntrHandle intrHandle, void *args) { SemaphoreP_Object *semObjPtr = (SemaphoreP_Object *)args; DebugP_assert(semObjPtr != NULL); /* Stop the ADCs by removing the trigger for SOC0 */ /*ADC_setInterruptSOCTrigger(gAdc0baseAddr, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE); ADC_setInterruptSOCTrigger(gAdc1baseAddr, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);*/ /* Post the semaphore to signal end of DMA transfer */ SemaphoreP_post(semObjPtr); }
Is there any SDK functions which we need to call to get the next DMA interrupt or Clearing after 1st DMA interrupt ?
Hi Prashanth,
Does your modified code trigger DMA transfer after each ADC conversion? If not, I will take a look at your code tomorrow.
Hi QJ Wang,
By default the example code has been configured to trigger DMA transfer after each ADC conversion based on ADC interrupt but I receive a DMA interrupt after the transfer is completed for only one iteration.
We are looking for continuous ADC conversion --> DMA transfer in a loop.
For this reason we have modified the code as shown below in the zip.
Please find the complete project zipped below:
adc_soc_continuous_dma_am263x-cc_r5fss0-0_nortos_ti-arm-clang.zip
Thanks for the reply QJ wang.
Please help us in finding the root cause for continuous DMA transfer after ADC conversion is done.
Hi Prashanth,
Thanks for sharing the project. I am sorry I haven't got time to run the project today, and will do it tomorrow morning.
Each ePWM can generate two ADC start of conversion signals to trigger a start of ADC conversion. I noticed the SOCA or SOCB in ePWM config is not enabled.
But in your ADC configuration, the SOCA is used for ADC conversion:
Hi QJ Wang
Thanks for looking at this. Enabling ADC Trigger from ePWM to start the conversion is done in "adc_soc_continuous_dma.c" example code manually.
ADC conversion starts and runs correctly. Issue is DMA interrupt is not issued after first time. Is there any additional flags to be cleared or configured in DMA?
Thanks
Kumar
Hi QJ Wang,
As Kumar says above,
Enabling ADC Trigger from ePWM to start the conversion is done in "adc_soc_continuous_dma.c" example code manually.
Issue is DMA interrupt occurs only once. Is there any additional flags to be cleared or configured in DMA?