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.

EDMA interrupt issue

Other Parts Discussed in Thread: TMS320C6746

With TMS320C6746 , we are using two McBSP channels and one SPI channel in our project. All these are linked to EDMA3 CC0 with sync events 2, 4, 14 and 15.

EDMA register adresses are from Shadow region 0.

Here are the observations:

1. When only 2 McBSP  channels and EDMA running, those are working perfect. (McBSP Frame Completion period is  130usec, ISR execution is around 14usec)

2. When only SPI  and EDMA running, those also working perfect. (Frame completion period is 144 usec, ISR execution is around 7usec)

3. When all the four are enabled, then some interrupts are lost.

Tried below with no success:

1. Tried placing a while loop in EDMA ISR to check IPR before exiting ( as While (IPR & IER) )

2. Set IEVAL bit while exiting.

Some additional inputs:

We are using BIOS. 

There are other HW interrupts running.

Interrupt execution time for all the 4 handlers is less than 50 usec.

My questions:

1. Why some EDMA interrupts are lost when all EDMA events are enabled. How to ensure we don't loose them.

2. Can we use EDMA CC0 for SPI and EDMA CC1 for SPI (As per data sheet we can't because all these are mapped to EDMA CC0)

  • My ISR looks like this,

    EDMA ISR()
    {
    while (IPR & IER)
    {
    check IPR for sync event 2 an d process if set
    check IPR for sync event 4 and process if set
    check IPR for sync event 14 and process if set
    check IPR for sync event 15 and process if set
    }
    }

    This is the highest priority ISR among 5 interrupts, all with Masking option SELF
  • Hi,

    Thanks for your post.

    I would recommend you to set the corresponding EMR bit for a DMA channel to check an event on the particular channel encounters a NULL TR. If any EMR bit is set and other error registers, CCERR the EDMA3CC would generate an error interrupt. Please check for any transfer completion code error or any queue threshold error. In general, the EDMA3CC has a single error interrupt which would be asserted for all error conditions like any DMA/QDMA missed events, threshold error, TCC error etc. For more details, please refer section 16.2.9.4 for error interrupts from C6746 TRM below:

    http://www.ti.com/lit/ug/spruh80a/spruh80a.pdf

    DMA missed events would be latched generally in EMR and event queue error would be latched in CCERR. To know more info. on these registers, kindly refer sections 16.4.2.2.1 & 16.4.2.2.5 from the above TRM.

    Thanks & regards,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------

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

    -------------------------------------------------------------------------------------------------------

  • Hi,

    To address question #2,

    you can't since there is a unique mapping between peripheral events and channel controller queues, so you cannot use the same peripheral's events in both the CC's. Please go as per datasheet for the feasible configuration. The mapping of DMA/QDMA channels and event queues are critical and it cannot be violated to achieve desired performance. Please refer section 16.2.10.1 for channel to event mapping from the C6746 TRM.

    Thanks & regards,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------

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

    -------------------------------------------------------------------------------------------------------

  • Bashkar,

    It is always good to check the EDMA3 error registers (EMR, SER, CCERR) to see if any EDMA3-detected errors have occurred. If EMR or SER have the active channels' bits set, those channels would quit responding at all. Since you seem to continue getting interrupts but miss some in the sequence, EMR/SER are probably not going to be set for these 4 channels.

    One small correction in what Sivaraj said above, the mapping of DMA/QDMA "channels and channel controllers" are critical and cannot be violated to achieve desired performance. However, it can be very helpful to balance the use of the two event queues and their associated Transfer Controllers to allow two DMA operations to run at the exact same time. In fact, my first recommendation is that you balance these by trying it with channels 2 & 4 using CC0_TC0 and channels 14 & 15 using CC0_TC1. This would tend to give you better performance, but it is still unlikely to be the cause of your missed interrupts.

    The most likely cause of the missed interrupts is the handling of clearing the IPR bits and the writing of IEVAL. It is important to follow the procedures described in the TRM section 16.2.9 EDMA3 Interrupts for servicing and evaluating interrupts.

    Attached are EdmaIntDispatcher.c and EdmaIntDispatcher.h which I used with the C674x DSP on a different device. There will be some code in it that you do not need, particularly checking the high-side registers of IPR (IPRH) since the C6748 does not have more than 32 channels. And this code uses CSL that might be 100% compatible (or even available?) with the C6748 code you are using. You can easily make changes to read and write the same registers the way you have been doing it already. I can offer these files as an example but they are not official TI source files; I do believe they work, though, for what that is worth.

    The critical parts are the timing of the writes to ICR and to IEVAL. If you do them differently than how they are placed in this code, then you may end up with some missed interrupts.

    Regards,
    RandyP

    edmaintdispatcher.c
    /*
     * EdmaIntDispatcher.c
     *
     * Interrupt dispatcher for the EDMA3 IPR interrupts to allow a different
     * function/ISR for each bit. 
     *
     * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 
     * 
     * 
     *  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.
     *
    */
    
    /** ============================================================================
     *
     *   @file  EdmaIntDispatcher.c
     *
     *   @path  
     *
     *   @desc This is a utility function used by edma as interrupt dispatcher 
     *
     *   Usage:
     *
     *
     *
     *   In your C source file, use the following:
     *
    #include "EdmaIntDispatcher.h"
    
    main():
    #if EDMA_REGION != CSL_EDMA3_REGION_GLOBAL
        CSL_Edma3CmdDrae            regionAccess;
    #endif
    
       // Open an intc handle for edma interrupt
    #if EDMA_REGION != CSL_EDMA3_REGION_GLOBAL
      #error CSL_INTC_EVENTID_EDMA3CC_GINT must be replaced with the appropriate region interrupt number
    #endif
        vectId = CSL_INTC_VECTID_4;
        hIntcEdma = CSL_intcOpen (&intcObjEdma, CSL_INTC_EVENTID_EDMA3CC_GINT,
                                  &vectId , NULL);
    
    #if ( EDMADISPATCH_METHOD == EDMADISPATCH_IEVAL )
    	// if the faster IEVAL option is chosen for the EdmaIntDispatcher, then this interrupt
    	// should be masked out of the Dropped Interrupt detection to avoid generating INTERR
        CSL_intcHwControl(hIntcEdma,CSL_INTC_CMD_EVTDROPDISABLE,NULL);
    #endif
    
    
    #if EDMA_REGION != CSL_EDMA3_REGION_GLOBAL
    	// Setup the DRAE masks, but not needed for global region
        regionAccess.region = EDMA_REGION ;
    
    	// choose the channels and tcc bits you will use with this region, method 2
    	ullTemp  = (unsigned long long)1 << tccGpio4;
    	ullTemp |= (unsigned long long)1 << tccCh0;
        regionAccess.drae  = _loll(ullTemp);   
        regionAccess.draeh = _hill(ullTemp);
    
        status = CSL_edma3HwControl(hModule,CSL_EDMA3_CMD_DMAREGION_ENABLE, \
                                    &regionAccess); 
        if (status != CSL_SOK) {
            Sys_Count ++;
            return;    
        }
    #endif
    
    
    #if EDMA_REGION != CSL_EDMA3_REGION_GLOBAL
    	 // Disable the region access
        regionAccess.region = EDMA_REGION ;
    
    	// choose the channels and tcc bits you will use with this region, method 2
    	ullTemp  = (unsigned long long)1 << tccGpio4;
    	ullTemp |= (unsigned long long)1 << tccCh0;
        regionAccess.drae  = _loll(ullTemp);   
        regionAccess.draeh = _hill(ullTemp);
    
        status = CSL_edma3HwControl(hModule,CSL_EDMA3_CMD_DMAREGION_DISABLE,
                                    &regionAccess);
    #endif
    
     *
     *   In your BIOS tcf source file, use the following for any HWI_INTn:
     *
    bios.HWI.instance("HWI_INT4").fxn = prog.extern("EdmaIntDispatcher");
    bios.HWI.instance("HWI_INT4").interruptSelectNumber = <EDMA3 int from datasheet>;
    bios.HWI.instance("HWI_INT4").useDispatcher = 1;
    bios.HWI.instance("HWI_INT4").arg = prog.extern("edmaObj"); // must be a global variable
    
     *
     * ============================================================================
     */
    
    #include <ti/csl/csl_edma3.h>
    #include <ti/csl/csl_chip.h>
    #include "EdmaIntDispatcher.h"
    
    
    /* Global Edma Tcc handler table */
    #pragma DATA_SECTION(TccHandlerTable,".far:TccHandlerTable");
    EdmaTccHandler TccHandlerTable[64];
    
    /*
     * =============================================================================
     *   @func  EdmaIntDispatcher
     *  
     *   @arg
     *      handle        - Edma module handle
     *
     *   @desc
     *      This is the interrupt dispatcher routine for edma interrupts
     *
     *   @return
     *      NONE
     *
     * =============================================================================
     */
    void EdmaIntDispatcher (
        void        *handle
    )
    {
        CSL_Edma3Handle     hModule = (CSL_Edma3Handle)handle;
        CSL_Edma3CmdIntr    regionIntr;
        Uint32              tcc;
        Uint32              intr;
        Uint32              intrh;
    	Int32				EdmaRegion;
        
        /* Read the IPR & mask with IER */
    	EdmaRegion = (Int32)EDMA_REGION;
    
        regionIntr.region = EdmaRegion;
        CSL_edma3GetHwStatus(hModule,CSL_EDMA3_QUERY_INTRPEND, &regionIntr);
    
    	// read IER and keep only enabled interrupts from IPR
    	if ( EdmaRegion == CSL_EDMA3_REGION_GLOBAL )
    	{
    	    regionIntr.intr  &= hModule->regs->TPCC_IER;
    	    regionIntr.intrh &= hModule->regs->TPCC_IERH;
    	}
    	else  // get the IER from the shadow region
    	{
    		regionIntr.intr  &= hModule->regs->SHADOW[EdmaRegion].TPCC_IER;
    	    regionIntr.intrh &= hModule->regs->SHADOW[EdmaRegion].TPCC_IERH;
    	}
        
    #if EDMADISPATCH_METHOD == EDMADISPATCH_REREAD_IPR
        while (regionIntr.intr || regionIntr.intrh)
        {
    #endif
            intr  = regionIntr.intr;
            intrh = regionIntr.intrh;
            
    		// clear any set & enabled IPR bits quickly to allow repetition
            CSL_edma3HwControl(hModule,CSL_EDMA3_CMD_INTRPEND_CLEAR,&regionIntr);       
    
            for ( tcc = 0; intr != 0; intr >>= 1, tcc++ )
                if ( intr & 1 )
                    InvokeHandle( tcc );
            
            for ( tcc = 32; intrh != 0; intrh >>= 1, tcc++ )
                if ( intrh & 1 )
                    InvokeHandle( tcc );
            
    #if EDMADISPATCH_METHOD == EDMADISPATCH_REREAD_IPR
    		// re-read IPR
            CSL_edma3GetHwStatus(hModule,CSL_EDMA3_QUERY_INTRPEND,&regionIntr);         
    
    		// read IER and keep only enabled interrupts from IPR
    		if ( EdmaRegion == CSL_EDMA3_REGION_GLOBAL )
    		{
    		    regionIntr.intr  &= hModule->regs->TPCC_IER;
    		    regionIntr.intrh &= hModule->regs->TPCC_IERH;
    		}
    		else  // get the IER from the shadow region
    		{
    			regionIntr.intr  &= hModule->regs->SHADOW[EdmaRegion].TPCC_IER;
    		    regionIntr.intrh &= hModule->regs->SHADOW[EdmaRegion].TPCC_IERH;
    		}
        }           
    #else  // EDMADISPATCH_IEVAL
    		// write to the EVAL bit of the IEVAL register for this region
    		if ( EdmaRegion == CSL_EDMA3_REGION_GLOBAL )
    		{
    		    hModule->regs->IEVAL = 1;
    		}
    		else
    		{
    			hModule->regs->SHADOW[EdmaRegion].IEVAL = 1;
    		}
    #endif
    }
    
    /*
     * =============================================================================
     *   @func  EdmaEventHook
     *  
     *   @arg
     *      tcc        - Tcc number
     *      fxn        - Pointer to function which points to edma isr
     *
     *   @desc
     *      This loads the hook table for the edma interrupt dispatcher
     *
     *   @return
     *      NONE
     *
     * =============================================================================
     */
    void EdmaEventHook (
        Uint16            tcc, 
        EdmaTccHandler    fxn
    )
    {
        TccHandlerTable[tcc] = (fxn);
    }
    
    

    edmaIntDispatcher.h