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.

SPI EDMA ping-pong data receiving on the DSP side

Other Parts Discussed in Thread: OMAPL138

 Hi All!

 I want to use SPI EDMA data receiving on the DSP side from external 8ch 16bit ADC. ADC indicates that data of one conversation is ready by the negative edge of BUSYpin. After the event from BUSY-pin EDMA should receive 16 bytes (8ch 16bit) of data and put it to the ping buffer. Ping/pong buffer has 128 samples of each channels (128*16*8/8 = 2048 samples).

When ping buffer is full EDMA should start to fill pong buffer, and data from the ping buffer should copy to third buffer(with increment). After pong buffer is full, EDMA should fill ping buffer and copy data from the pong buffer to third buffer(with increment). Third buffer is more large than ping and pong buffer and should be fill by the circle.

 My understanding how to realize it:

Initialize EDMA with shadow region 1 for interrupts. Ch7 as GPIO Bank1 Event and Ch18 as SPI1 Receive Event

For dummy SPI data transmission use Ch7 (GPIO1 Bank event) ParamSet with follow parameters:

         Use A-sync

         ACnt = 16; //2 bytes per channel

         BCnt = 128; // 1 time transmission

         CCnt = 1; // 1 time transmission

For real SPI data receiving I would use Ch18 ParamSet with follow parameters:

Use A-sync

         ACnt = 16; //2 bytes per channel

         BCnt = 128; // 1 time transmission

         CCnt = 1; // 1 time transmission

 When EDMA received all 2048 bytes EDMA interrupt is calling and reinitialize destination pointer(from ping to pong buffer and etc.) in the ISR.

 So, I planing to use two ParamSet (1 for receive dummy data and one for receive true data). 

 whether this is the best way for my objective? 

  • Hi Dimitry,

    Thanks for your post.

    Programing Sequence for DMA Mode, please refer the below wiki page.
    http://processors.wiki.ti.com/index.php/StarterWare_SPI
    http://processors.wiki.ti.com/index.php/StarterWare_01.10.01.01_User_Guide

    The examples for C674x are based on DSP/BIOS drivers: PSP (platform support package).
    Getting started with C6748 DSP on the OMAPL138 is described here:
    http://processors.wiki.ti.com/index.php/Getting_Started_Guide_for_C6748

    If you are looking for register CSL kind of examples, you can find that under pspdrivers_xx_xx_xx\packages\ti\pspiom\cslr\evm6748\examples.
    There is a SPI example in the PSP package which configures the peripheral in master mode.

    Also, please refer the below E2E posts:

    http://e2e.ti.com/support/dsp/tms320c6000_high_performance_dsps/f/115/t/213724.aspx

    http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/t/30083.aspx

    Thanks & regards,
    Sivaraj K

    -------------------------------------------------------------------------------------------------------
    Please click the Verify Answer button on this post if it answers your question.
    -------------------------------------------------------------------------------------------------------

  •  Thank you for response, Sivaraj!


    Link was very helpful

    So,  now I have just one question.

    I have function such as bellow:

    void edmaRecvReload(void)
    {
    	unsigned int shadowRegionId = 1;	// Shadow region used for interrupts
    	unsigned int edmaRecvChNum = 18;	// Ch18 is SPI1 Receive Event
    	unsigned int edmaTxEvtQNum = 0;		// Event Queue used
    	unsigned short edmaRecvACnt = 1;		// 2048 1-byte transmissions
    	unsigned short edmaBCnt = 2048;		// 1 time transmission
    	unsigned short edmaCCnt = 1;		// 1 time transmission
    	unsigned short edmaRecvSrcBIdx = 0;	// Don't want to change the src count offset
    	unsigned short edmaRecvDesBIdx = 1;	// Increment on destination count offset by one byte
    	unsigned short edmaRecvSrcCIdx = 0;	// Don't want to change the src count offset
    	unsigned short edmaRecvDesCIdx = 0;	// Don't want to change the destination count offset
    	unsigned short edmaBCntReload = 0;	// Don't want to reload B count
        unsigned int writeAddr;
        volatile unsigned int *ds;
        unsigned int *sr;
        unsigned int i = 0;
    
        // Set up DMA Recv channel //////////////////////////////////////////////////////////
    
        getWriteBufferAddr(&writeAddr);
    
        // Associate DMA Channel to Event Queue
        HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_DMAQNUM((edmaRecvChNum) >> 3u)) &=
                             EDMA3CC_DMAQNUM_CLR(edmaRecvChNum);
    
        HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_DMAQNUM((edmaRecvChNum) >> 3u)) |=
                      EDMA3CC_DMAQNUM_SET((edmaRecvChNum), edmaTxEvtQNum);
    
        // Enable the Event Interrupt
        HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_IESR(shadowRegionId)) |= (0x01u <<  edmaRecvChNum);
    
        HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_OPT(edmaRecvChNum)) &= EDMA3CC_OPT_TCC_CLR;
        HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_OPT(edmaRecvChNum)) |= EDMA3CC_OPT_TCC_SET(edmaRecvChNum);
    
        /* Fill the PaRAM Set with transfer specific information */
        recvParamSet.srcAddr    = (unsigned int)&HWREG(SOC_SPI_1_REGS + SPI_SPIBUF);
        recvParamSet.destAddr   = (unsigned int)writeAddr;
    
        recvParamSet.aCnt = edmaRecvACnt;
        recvParamSet.bCnt = edmaBCnt;
        recvParamSet.cCnt = edmaCCnt;
    
        // Setting up the SRC/DES Index
        recvParamSet.srcBIdx = edmaRecvSrcBIdx;
        recvParamSet.destBIdx = edmaRecvDesBIdx;
            /* A Sync Transfer Mode */
        recvParamSet.srcCIdx = edmaRecvSrcCIdx;
        recvParamSet.destCIdx = edmaRecvDesCIdx;
    
    
        // 0x4000 is starting add.  8 32 bit register values per channel.  Using ch32.  So 8*4*32+0x4000 = 0x4400
        recvParamSet.linkAddr = (unsigned short)0xFFFF;
        recvParamSet.bCntReload = edmaBCntReload;
    
        // Initialize the options register
        recvParamSet.opt = 0u;
    
        // Program the TCC
        recvParamSet.opt |= ((edmaRecvChNum << EDMA3CC_OPT_TCC_SHIFT) & EDMA3CC_OPT_TCC);
    
    //    /* Enable Intermediate & Final transfer completion interrupt */
    //    paramSet.opt |= (1 << EDMA3CC_OPT_ITCINTEN_SHIFT);
    //	recvParamSet.opt |= (1 << EDMA3CC_OPT_TCINTEN_SHIFT);
    
    	// Set for A-B synchronized transfer
    //    txParamSet.opt |= (1 << EDMA3CC_OPT_SYNCDIM_SHIFT);
        // End Set up DMA Recv channel //////////////////////////////////////////////////////
    
    
        // Write the parameter set for origional Recv set
        sr = (unsigned int *)&recvParamSet;
        ds = (unsigned int *)(SOC_EDMA30CC_0_REGS + EDMA3CC_OPT(edmaRecvChNum));
    
        for(i=0; i < EDMA3CC_PARAM_ENTRY_FIELDS; i++)
        {
            *ds = *sr;
            ds++;
            sr++;
        }
    //    // Write parameter set for linked set.  Exactly like Tx parameter set
    //    sr = (unsigned int *)&txParamSet;
    //    // Set the destination address for the linked set to be channel 32
    //    ds = (unsigned int *)(SOC_EDMA30CC_0_REGS + EDMA3CC_OPT(32));
    //
    //    for(i=0; i < EDMA3CC_PARAM_ENTRY_FIELDS; i++)
    //    {
    //        *ds = *sr;
    //        ds++;
    //        sr++;
    //    }
    //
        // End Write parameter sets /////////////////////////////////////////////////////////
    
        // clear SECR to clean any previous NULL request
        HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_SECR(shadowRegionId)) = (0x01u << edmaRecvChNum);
    
        // clear EMCR to clean any previous NULL request
        HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_EMCR) |= (0x01u <<  edmaRecvChNum);
    
        // (EESR) - set corresponding bit to enable DMA event
    	HWREG(SOC_EDMA30CC_0_REGS + EDMA3CC_S_EESR(shadowRegionId)) |= (0x01u <<  edmaRecvChNum);
        /////////////////////////////////////////////////////////////////////////////////////
    }

    Same function I have for initialize each of ParamSet ( in all 4 function - two for receive/transmit and two for linking ParamSet for filling ping-pong buffers). Mentioned function I called just in the EDMA initialization routine. Question^ should I call all four function in EDMA_ISR routine?

  • Hi,

    Thanks for your update.

    In general, EDMA_ISR routine holds good only for receive/transmit and not for linking ParamSet functions since it is taken care in the EDMA intialization routine. You need to ensure Tx. & Rx. interrupts should be mapped to appropriate interrupt event nos. and the interrupt needs to be registerd with the EDMA transfer completion ISR. Usually in EDMA_ISR call, we will check the transmit and receive DMA completed through getting the EDMA_SPI Tx. & Rx. interrupt status.

    Thanks & regards,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------
    Please click the Verify Answer button on this post if it answers your question.
    --------------------------------------------------------------------------------------------------------