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.

How to control three TCP3d instances in one DSP core?

Dear all,

     Now I use one TCP3d by one DSP core to decode 25 blocks using 1600K cycle. But the time is to long and I cannot do anything in the core because the coes is serving the EDMA to put the data into TCP3d with the PDK example. So I met a question that how to reduce the 1600K time and free the core to do other thing while the TCP3d is also decoding the blocks?

    Now the program I use is changed by the program of  C:\Ti\pdk_C6670_1_1_2_5\packages\ti\drv\tcp3d\example. 

   I think I should  divde the 25 blocks into 3 instances that each one decodes 8 blocks is OK. But I can run three TCP3d  in one DSP core at the same time. And I also use the BCP to do the Rate Dematching work. Should I Combine the Rate Dematching blocks to simulate the EDMA in order to free the cDSP core?

   Thank you in advanced and I wish I can get help here!

PS: I think I find the same  task with http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/t/322217.aspx. But it is also provide a solution in detial.

Xie Chen (Beijing, China)

    

  • The code I use changed from the example. The program go wrong in the allInit() API.  The instance I use is EDMA Tcc instances 2 , TCP3d_A for region 3 and  CP3d_B for region 2. 

    {
    getTestSetCB(&codeBlockSet0, &codeBlockSet1, &RDOUT_CONFIG, &TDOUT_CONFIG);
    
    for (i = 0; i < codeBlockSet0.maxNumCB ;i++)
    {
    /* Prepare fixed IC registers using the inCfgParams of first block*/
    Tcp3d_prepFixedConfigRegs(codeBlockSet0.cbData[i]->inCfgParams, codeBlockSet0.cbData[i]->inCfg);
    
    /* Prepare block size dependent params */
    prepareBlockSizeDepICParams(codeBlockSet0.cbData[i]);
    }
    
    for (i = 0; i < codeBlockSet1.maxNumCB ;i++)
    {
    /* Prepare fixed IC registers using the inCfgParams of first block*/
    Tcp3d_prepFixedConfigRegs(codeBlockSet1.cbData[i]->inCfgParams, codeBlockSet1.cbData[i]->inCfg);
    
    /* Prepare block size dependent params */
    prepareBlockSizeDepICParams(codeBlockSet1.cbData[i]);
    }
    
    semRcvDone0 = Semaphore_create(0, &semParams, NULL);
    semSendBlock0 = Semaphore_create(0, &semParams, NULL);
    semSendWait0 = Semaphore_create(0, &semParams, NULL);
    allInit(CSL_TCP3D_A);
    
    semRcvDone1 = Semaphore_create(0, &semParams, NULL);
    semSendBlock1 = Semaphore_create(0, &semParams, NULL);
    semSendWait1 = Semaphore_create(0, &semParams, NULL);
    allInit(CSL_TCP3D_B);
    
    /**
    * Create the send and receive tasks for each test using the default
    * tak parameters.
    *
    * NOTE: No need to do the Task_delete() as these tasks have exits.
    */
    taskParams.priority = 7;
    taskParams.arg0 = CSL_TCP3D_A;
    TDsndBlock0 = Task_create((Task_FuncPtr)sndBlockTaskFunc0, &taskParams, NULL);
    taskParams.priority = 6;
    taskParams.arg0 = CSL_TCP3D_B;
    TDsndBlock1 = Task_create((Task_FuncPtr)sndBlockTaskFunc1, &taskParams, NULL);
    
    
    
    /* Start the Send task first */
    Semaphore_post(semSendBlock0);
    Semaphore_post(semSendBlock1);
    
    /* Wait for the Receive task to complete */
    Semaphore_pend(semRcvDone0, BIOS_WAIT_FOREVER);
    allDeInit(CSL_TCP3D_A);
    Semaphore_pend(semRcvDone1, BIOS_WAIT_FOREVER);
    allDeInit(CSL_TCP3D_B);
    
    /**
    * Delete the semaphores each time, so that there is no left over count.
    * See the explanation at the beginning of this loop where the create
    * semaphore calls are present.
    */
    Semaphore_delete(&semSendWait0);
    Semaphore_delete(&semSendBlock0);
    Semaphore_delete(&semRcvDone0);
    Task_delete(&TDsndBlock0);
    Semaphore_delete(&semSendWait1);
    Semaphore_delete(&semSendBlock1);
    Semaphore_delete(&semRcvDone1);
    Task_delete(&TDsndBlock1);
    }
    
    Void allInit(instNum)
    {
    
    if(instNum == 0)
    {
    tpccNum = 2;
    tpccRegionUsed = 3;
    }
    else
    {
    tpccNum = 2;
    tpccRegionUsed = 2;
    }
    
    hEdma[instNum] = edma3init (instNum, tpccNum,
    &edmaResult,
    dspCoreID,
    tpccRegionUsed);
    
    .....
    
    
    /* Open channels for one instance */
    openEdmaChannels (hEdma[instNum], instNum, &edmaConfig[instNum]);

  • still waiting for help and advice!

  • still waiting for help and advice!

  • Hi Chen,

    I am working with expert to answer this post. Thank you for your patience.

  • Hi Chen,

    Once you setup the EDMA during initialization and trigger the TCP3d enqueue code block during run time, your DSP core is idle since EDMA does not utilize DSP resources. Since it is semaphore based and the TCP3d driver can provide a completion interrupt after the 25 code blocks, you should be able to use the DSP resources for other tasks in the system during that time(For example BCP task). 

    Regards,

    Arun

     

  • In case you're still interested to do multiple instances, the current TCP3d driver example does not show how to operate multiple TCP3d hardware instances from the same DSP core. In order to do that, all your code needs to be multiple instances compatible. So essentially all your global variables will need to be instance based. For example, pingComplete[instanceId], pongComplete[instanceId] etc. 

    allinit is opening the EDMA channels for the required TCP3d operation. So in your case, all the APIs should support multiple instances as well.

    Regards,

    Arun

  • Dear Arun,

    Firstly thank you very much for answering my questions!!

    Yesterday I check the code for waiting the completion interrupt as follow:

      /**
         * Check for pending Pauses and waiting for the last block to be decoded 
         */
        while ( 1 )
        {
            /* Pending on Semaphore to run the loop */
            Semaphore_pend(semSendWait0, BIOS_WAIT_FOREVER);
    
            /* Received both the completion events, so exit send task */
            if ( (tcp3dEventCntr0 >= 2) || (pauseIntr0 >= 4) )
            {
                break;
            }else if ( tcp3dEventCntr0 == 1 )
            {
                /* one code block test case */
                if ( codeBlockSet0.maxNumCB == 1 )
                {
                    break;
                }
                else if ( codeBlockSet0.mode == TEST_MODE_SPLIT )
                {
                }
            }
    
            if ( TCP3D_DRV_NO_ERR != Tcp3d_start(inst, TCP3D_DRV_START_AUTO) )
            {
                System_printf("Tcp3d_start function returned error\n");
                System_exit(0);
            }
    
        }

    as the revt0 and revt  also post hte semaphore semSendWait0 to triger the next block transfer by EDMA, which means the MCSDK emxaple does not use the EDMA chain between the revt0 and the next EDMA transmit data to TCP3d. And if I delete the above code, the TCP3d will not give back the completion interrupt. So the DSP core is not idle because it needs to do the TCP3d_start() when TCP3d send back one block decode completion by REVT . Is what I understood right? I am using the TCP3d example under the PDK_1_1_2_5. 

    when I put the breakpoint in the three semaphore post code:

    Void revt0ChCallback(Void)
    {
        /* Increment the ISR counter */
        pauseIntr0++;
    
        if ( sendBlockCnt0 >= codeBlockSet0.maxNumCB )
            Semaphore_post(semSendWait0);
        else
        	Semaphore_post(semSendBlock0);
    }
    
    /*******************************************************************************
     ******************************************************************************/
    Void revt1ChCallback(Void)
    {
        /* Increment the ISR counter */
        pauseIntr0++;
    
        if ( sendBlockCnt0 >= codeBlockSet0.maxNumCB )
            Semaphore_post(semSendWait0);
        else
        	Semaphore_post(semSendBlock0);
    }
    /*******************************************************************************
     ******************************************************************************/
    Void tcp3dEventISR0(UInt32 testEvtNum)
    {
        tcp3dEventCntr0++;
    
        if ( sendBlockCnt0 >= codeBlockSet0.maxNumCB )
        {
        	Semaphore_post(semSendWait0);
        }
        else
        {
        	Semaphore_post(semSendBlock0);
            System_printf("eventISR block\n");
        }
    }
    

    the revt0 breaks 2 times,revt1 breaks 2 times, tcp3dEventISR0 breaks 2 times. 

    The tcp3dEventISR0 represents the completion so 2 times is ok for Ping and  Pong. But Why revt0 only 2 times, I think it should be 11 or 12 times in my situation of 25 Blocks. Was I wrong on understanding this point?

    Regaards,

    Xie

  • About the second question:

    Now I am using one TCP3d to decode 25 blocks (size of each is 6016) in 1600K cycle. So I want to use 3 TCP3d instances at the same time. Then I can finish the decode module in near 500K cycle.

    Now I have already change the code into multiple instances compatible, which maybe meets something wrong.

     

    Void allInit(instNum)
    {
        Tcp3d_Result        tcp3dResult = TCP3D_DRV_NO_ERR;
        EDMA3_DRV_Result    edmaResult = EDMA3_DRV_SOK;
    
        /* Initialize EDMA3 first */
        hEdma[instNum] = NULL;
    
        if(instNum == 0)
        {
            tpccNum = 2;
            tpccRegionUsed = 3;
        }
        else
        {
            tpccNum = 2;
            tpccRegionUsed = 2;
        }
    
        hEdma[instNum] = edma3init (instNum, tpccNum,
                            &edmaResult,
                            dspCoreID,
                            tpccRegionUsed);
    
    
        /* Open channels for one instance */
        openEdmaChannels (hEdma[instNum], instNum, &edmaConfig[instNum]);
    
        if(instNum == 0)
        {
            /* Register call backs */
            EDMA3_DRV_registerTccCb(hEdma[instNum], edmaConfig[instNum].pingChRes[0].chNo, (EDMA3_RM_TccCallback)&revt0ChCallback, NULL);
            EDMA3_DRV_registerTccCb(hEdma[instNum], edmaConfig[instNum].pongChRes[0].chNo, (EDMA3_RM_TccCallback)&revt1ChCallback, NULL);
    
            /* Fill call back details */
            edmaConfig[instNum].pingChRes[0].cbFunc  = (EDMA3_RM_TccCallback)&revt0ChCallback;
            edmaConfig[instNum].pingChRes[0].cbData  = NULL;
            edmaConfig[instNum].pongChRes[0].cbFunc  = (EDMA3_RM_TccCallback)&revt1ChCallback;
            edmaConfig[instNum].pongChRes[0].cbData  = NULL;
    
            /* Initialize the TCP3D first */
            tcp3dDrvInst[instNum] = tcp3dSampleInit (drvHeap,
                                            instNum,
                                            testMaxCodeBlocks,
                                            codeBlockSet0.mode,
                                            codeBlockSet0.doubleBuffer,
                                            codeBlockSet0.lteCrcSel,
                                            dspCoreID,
                                            hEdma[instNum],
                                            tpccRegionUsed,
                                            &edmaConfig[instNum],
                                            &tcp3dResult);
            pingComplete0 = 0;
            pongComplete0 = 0;
            pauseIntr0 = 0;
            tcp3dEventCntr0 = 0;
        }
        else
        {
            /* Register call backs */
            EDMA3_DRV_registerTccCb(hEdma[instNum], edmaConfig[instNum].pingChRes[0].chNo, (EDMA3_RM_TccCallback)&revt2ChCallback, NULL);
            EDMA3_DRV_registerTccCb(hEdma[instNum], edmaConfig[instNum].pongChRes[0].chNo, (EDMA3_RM_TccCallback)&revt3ChCallback, NULL);
    
            /* Fill call back details */
            edmaConfig[instNum].pingChRes[0].cbFunc  = (EDMA3_RM_TccCallback)&revt2ChCallback;
            edmaConfig[instNum].pingChRes[0].cbData  = NULL;
            edmaConfig[instNum].pongChRes[0].cbFunc  = (EDMA3_RM_TccCallback)&revt3ChCallback;
            edmaConfig[instNum].pongChRes[0].cbData  = NULL;
    
            /* Initialize the TCP3D first */
            tcp3dDrvInst[instNum] = tcp3dSampleInit (drvHeap,
                                            instNum,
                                            testMaxCodeBlocks,
                                            codeBlockSet1.mode,
                                            codeBlockSet1.doubleBuffer,
                                            codeBlockSet1.lteCrcSel,
                                            dspCoreID,
                                            hEdma[instNum],
                                            tpccRegionUsed,
                                            &edmaConfig[instNum],
                                            &tcp3dResult);
            pingComplete1 = 0;
            pongComplete1 = 0;
            pauseIntr1 = 0;
            tcp3dEventCntr1 = 0;
        }
    
        /**
         * Update the information to use with local EDMA ISR 
         * (NOTE: This function must be called after the channels are opened)
         */
        updateAllocatedTccsLoc(&edmaConfig[instNum]);
    
        /* Register the Notification Event for TCP3D */
        registerTcp3dEvent(instNum);
    }

    Now I cannot establish the second EDMA handle suceesfully because the EDMA3_DRV_open() API in the edma3init(). If I add the second EDMA hadle in the same instances the API will return wrong code -165.

    So it means I need to see the EDMA lld in detail to solve this question or I am somthing wrong in the following operations. 

    Thank you very much again for these two quesitons sincerely!

    Best regards,

    Xie

  • In your application, I don't think you will need revt0 and revt1 ISR callback functions to be registered (you can disable this in the allinit API). These are more for profiling and debugging purposes. You just need to hook up the tcp3deventISR for a completion event. Depending on how often you would like your higher layer to be notified, you can set the interrupt flag accordingly in the tcp3denqueue function. Some of our customers only set the flag for the very last CB. It depends to your application. 

    Also, you can set the START_CMD_PERIOD so that the tcp3d_start execution starts after N blocks and your code blocks will be chained by EDMA. The only CPU processing that happens is when the driver reaches PAUSE state and you will have to restart the driver by re-issuing a tcp3d_start again. This only takes a few hundred cycles. 

    The cycle count of 1600K is not entirely hogged by the CPU. It is just the time taken by TCP3d to finish processing (with a few hundred cycles of CPU processing.)

  • Regarding EDMA Init, yes there is a sample_cfg.c file in the tcp3d example which shows you how to set up your EDMA PaRAM regions. Look for sampleInstInitConfig[][] structure in it and you will notice that it has regions and resources defined per EDMA instance. 

    So in your case, you are setting tpccnum = 2 and tpccregionused = 2 or 3. You should be looking at the EDMA3 INSTANCE# 2 and the region 2/3/4 accordingly. The ownPaRAMSets is basically the channels being allocated for that particular tcp3d hardware instance. Look at region 2 and try programming region 3 similar to it. You have to make sure that the tcp3d revt events are owned by that region in this structure. There are additional PaRAMs for data transfer used by the driver. You can allocate any common EDMA channels (EDMA channels 0-63 are hooked up to hardware events).

    Regards,

    Arun 

  • Dear Arun,

    Yes,in my applicaiton only using the tcp3deventISR for a completion event is OK. But, after I only disable the REVT0 and REVT1 ISR in the allinit API, the whole system does not work well because it can receive the final ISR. Is the TCP3d cannot finish the whole 25 blocks in this situation? (I try and find it stop in the loop of the edma3ComplHandlerLoc() API) Can you test this method in the lab and do you meet this problem? 

            /* Register call backs */
    //        EDMA3_DRV_registerTccCb(hEdma[instNum], edmaConfig[instNum].pingChRes[0].chNo, (EDMA3_RM_TccCallback)&revt0ChCallback, NULL);
    //        EDMA3_DRV_registerTccCb(hEdma[instNum], edmaConfig[instNum].pongChRes[0].chNo, (EDMA3_RM_TccCallback)&revt1ChCallback, NULL);
    
            /* Fill call back details */
            edmaConfig[instNum].pingChRes[0].cbFunc  = NULL;//(EDMA3_RM_TccCallback)&revt0ChCallback;//
            edmaConfig[instNum].pingChRes[0].cbData  = NULL;
            edmaConfig[instNum].pongChRes[0].cbFunc  = NULL;//(EDMA3_RM_TccCallback)&revt1ChCallback;//
            edmaConfig[instNum].pongChRes[0].cbData  = NULL;

    Thank you for the information about the interrupt flag and the CPU cycles. I have undetood these two points now.

    Xie

  • Yes, I have noticed the sampleInstInitConfig[][] structure and it is for different TCP3d instance. And I initial the region 3 the same code as the the region 2, but it can go throgh the EDMA3_DRV_open (edma3Id, (void *) &initCfg, &edma3Result) API, which is before the TCP3d revt code. 

    So, I will cost more time on this quesiton and you can run the 

    hEdma = edma3init ( tpccNum,
    &edmaResult,
    dspCoreID,
    tpccRegionUsed);

    twice maybe you will meet the same problem as I discribed.

    Thank you again and I admit it is a complex task in releasing my application.

    Xie

  • I think you are right. When I disable revt callbacks, the program hangs in the EDMA local completion ISR handle. You can leave them enabled for now. 

    But going back to the original issue, are you still having issue with configuring the edma3init for 3 instances?

    Regards,

    Arun

  • You mentioned that region 3 and region 2 has the exact same setup. They should be mutually exclusive. For example, if you are setting up region 2 for tcp3d_0 and region 3 for tcp3d_1 then the channels that are used for tcp3d_0 should not be used for tcp3d_1. Similarly for tcp3d_2 as well. It should be mutually exclusive with the other 2 regions. 

  • Dear Arun,

    Yes, I am still in the initial problem. The initial process is only the edma3init API and it is still many problem for 3 instances. 

    Thank you for mention the different channel for different instacne. Now I am in the problem of the initial process, so the next step is opening the channels and I have not reach that stage. 

     

    Thank you ! Wish you have a good weekend. See you next week!

    Xie