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.

SIO_reclaim task state

Hello,

I am trying to run a DSP BIOS (5.41.7) application which consists of 2 different threads of the same priority (8) in a DM6446 device. These threads are transfering/receiving data to/from the DSP to/from the GPP through a DSPLink connection. Both threads open an SIO channel and write and read data from a buffer using an issue and reclaim scheme.

The first of the threads executes SIO_reclaim() functions (with timeout SYS_FOREVER) and, as the GPP is not sending data to it, the thread should suspend. In the meantime, the second thread should send data to the GPP (issue and reclaim once more).

The problem that I am experiencing is that, because of the fact that the first thread gets 'stucked' in the SIO_reclaim, the second thread never executes.

Could you tell me what is the reason of this behaviour? What it the state of the first thread that executed SIO_reclaim? Blocked? How can I prevent this situation to happen, given that the 2 threads have the same priority?

Thank you very much for your help.

Kind regards,

Pablo Colodron

  • Hi Pablo,

    Which version of DSPLink are you using? Can you check ROV to see the state of the threads?

    Todd

  • Hi Todd,

    Thank you for answering so fast, this is a critical issue for me.

    I am using DSPLink 1.65.03.

    Regarding to the ROV, the problem is that I dont know how to check it because what I am doing know is running an embedded Linux in my DM6446. What I do is using my Linux PC for building the GPP and the DSP applications using Linux TI compiler tools.

    Kind regards,

    Pablo

  • Are you using the same channel/stream to send data to the different tasks.

    It not clear but you must ensure you have two separate channels created/opened (CHNL on GPP, SIO on DSP).  SIO_reclaim will block the current running task and allow any other ready task in the system of equal or lower priority to run.

  • I am using one stream for transfering GPP->DSP and another stream for DSP->GPP.

    I have checked and I have realised that the TSK_sleep function does not work either. I have read in some forums that this might be caused by not having an appropriate timer configuration. Could you tell me what is the typical timer configuration for a device like DaVinci that runs Linux in the GPP (I heard that you have to share the timer between the GPP and the DSP)?

    In addition to this, is it possible that the fact that I am not configuring the timer properly makes that the functions TSK_yield() and the task preemption in general does not work? It sound extrange that with 2 threads of the same priority, one thread gets stucked in SIO_reclaim() and the other thread does not get the control of the processor. Could be a problem with the task scheduler?

    Thank you one more time.

    Regards,

    Pablo

  • It seems that the task manager works because if I create the tasks like this:

    attrs = TSK_ATTRS; /* Default task attributes */
    attrs.priority = 8;

        
        tskLoopRxTask = TSK_create(tskLoopRx, &attrs);
        if (tskLoopRxTask != NULL) {
            LOG_printf(&trace, "Create TSKLOOPRx: Success\n");
        }
        else {
            LOG_printf(&trace, "Create TSKLOOPRx: Failed.\n");
            return;
        }

    attrs.priority = 9;
        tskLoopTxTask = TSK_create(tskLoopTx,&attrs);
        if (tskLoopTxTask != NULL) {
            LOG_printf(&trace, "Create TSKLOOPRx: Success\n");
        }
        else {
            LOG_printf(&trace, "Create TSKLOOPRx: Failed.\n");
            return;
        }

    The second task takes the control of the processor. However, If both tasks have priority 8, the first task takes the control.

    I hope this helps.

    Regards,

    Pablo

  • Pablo,

    I'm assuming that you are creating the tasks in main()...when the two tasks have the same priority, the one that was created first will run first. If they have different priorities, the one with the higher priority runs first.

    Todd

  • Hi Todd,

    But if they are the same priority, I should be able to switch between them by means of using TSK_yield() function right? This part is the one which is not working for me. In my tcf I have the following:

    /*  ============================================================================
     *  Load generic DSP/BIOS Link configuration
     *  ============================================================================
     */
    utils.importFile("dsplink-dm6446gem-base.tci");
    utils.importFile("dsplink-iom.tci");
    utils.importFile("dsplink-zcpydata-swi.tci");
    utils.importFile("dsplink-dio.tci");
    utils.importFile("loop.tci");

    bios.enableRealTimeAnalysis(prog);
    bios.enableMemoryHeaps(prog);
    bios.enableRtdx(prog);    
    bios.enableTskManager(prog);

    /*  ============================================================================
     *  Set all code and data sections to use DDR2
     *  ============================================================================
     */
    bios.setMemCodeSections(prog, DDR2);
    bios.setMemDataNoHeapSections(prog, DDR2);
    bios.setMemDataHeapSections(prog, DDR2);

    /*  ============================================================================
     *  MEM : Global
     *  ============================================================================
     */
    prog.module("MEM").BIOSOBJSEG = DDR2;
    prog.module("MEM").MALLOCSEG  = DDR2;

    /*  ============================================================================
     *  TSK : Global
     *  ============================================================================
     */
    prog.module("TSK").STACKSEG = DDR2;

    bios.TSK.PRIORITY = 8;
    bios.TSK.ENABLETSK = true;
    bios.TSK.STACKSEG = prog.get("DDR2");
    bios.TSK.OBJMEMSEG = prog.get("DDR2");
    bios.TSK.STACKSIZE = 8000;

    bios.CLK.TIMERSELECT = "Timer 1";
    bios.CLK.RESETTIMER = true;          /* Take the selected timer our of reset */
    bios.CLK.MICROSECONDS = 1000;
    bios.CLK.ENABLEHTIME = 1;

    Do you have any suggestion why TSK_yield() may not work?

    Thanks Todd,

    Regards

    Pablo

  • Yes, if there are two tasks with the same priority and one is running and the other is ready to run, a call to TSK_yield() by the running TSK will cause the other ready TSK, with the same priority, to run. Are you positive the other TSK is in the ready to run state?

    Todd

  • Todd your are giving me very good points. I thought that TSK_yield() would pass the control to a task that was suspended or ready, not only ready.

    The reason why I am playing with TSK_yield() is because I have problems with the function SIO_reclaim(). I will show you a piece of code of my 2 threads:

    TASK 1:

    for (i = 0 ;
             (   ((info->numTransfers == 0) || (i < info->numTransfers))
              && (status == SYS_OK)) ;
             i++) {

            status = SIO_issue(info->inputStream,
                               buffer,
                               info->bufferSize,
                               arg) ;
            if (status == SYS_OK) {
                nmadus = SIO_reclaim (info->inputStream,
                                      (Ptr *) &buffer,
                                      &arg) ;
                if (nmadus < 0) {
                    status = -nmadus ;
                    SET_FAILURE_REASON (status) ;
                }
                else {
                    info->receivedSize = nmadus ;
                }
            }
            else {
                SET_FAILURE_REASON(status);
            }

        }

    TASK 2:

    for (i = 0 ;
             (   ((info->numTransfers == 0) || (i < info->numTransfers))
              && (status == SYS_OK)) ;
             i++) {  
            if (status == SYS_OK) {
                status = SIO_issue(info->outputStream,
                                   buffer,
                                   info->receivedSize,
                                   arg);

                if (status == SYS_OK) {
                    nmadus = SIO_reclaim (info->outputStream,
                                          (Ptr *) &(buffer),
                                          &arg) ;
                    if (nmadus < 0) {
                        status = -nmadus ;
                        SET_FAILURE_REASON (status) ;
                    }
                }
                else {
                    SET_FAILURE_REASON (status) ;
                }
            }  
        }

    GPP Application:

    status = CHNL_issue (processorId, CHNL_ID_OUTPUT, &LOOP_IOReq) ;
            if (DSP_FAILED (status)) {
                LOOP_1Print ("CHNL_issue failed (output). Status = [0x%x]\n",
                              status) ;
            }

            /*
             *  Reclaim 'empty' buffer from the channel
             */
            if (DSP_SUCCEEDED (status)) {
                status = CHNL_reclaim (processorId,
                                       CHNL_ID_OUTPUT,
                                       WAIT_FOREVER,
                                       &LOOP_IOReq) ;
                if (DSP_FAILED (status)) {
                    LOOP_1Print ("CHNL_reclaim failed (output). Status = [0x%x]\n",
                                 status) ;
                }
            }

            /*
             *  Receive data from DSP
             *  Issue 'empty' buffer to the channel.
             */
            if (DSP_SUCCEEDED (status)) {
                status = CHNL_issue (processorId, CHNL_ID_INPUT, &LOOP_IOReq) ;
                if (DSP_FAILED (status)) {
                    LOOP_1Print ("CHNL_issue failed (input). Status = [0x%x]\n",
                                 status) ;
                }
            }

            /*
             *  Reclaim 'filled' buffer from the channel
             */
            if (DSP_SUCCEEDED (status)) {
                status = CHNL_reclaim (processorId,
                                       CHNL_ID_INPUT,
                                       WAIT_FOREVER,
                                       &LOOP_IOReq) ;
                if (DSP_FAILED (status)) {
                    LOOP_1Print ("CHNL_reclaim failed (input). Status = [0x%x]\n",
                                 status) ;
                }
            }

    The 2 SIO channels are created with the attr timeout=SYS_FOREVER. According to what I know, this code would execute with no problem, given that when the task 1 enters, it will execute SIO_reclaim() and as the GPP is not sending anything to it, it will suspend. In this way, task 2 would enter and go to SIO_reclaim trying to write the output channel that sends data to the GPP. Once the GPP receives these data, I sends data to task 1 channel, so task 2 will suspend and task 1 would wake up for receiving the data.

    This sequence of events is correct or I am missing something?

    Regards,

    Pablo

  • Pablo,

    Sorry, it's not entirely clear what you want to do. Who is driving the application, the host or the dsp? It looks like the DSP wants to send data to the host and then wait for a response. Is this correct? If so, why have two Tasks on the DSP? It the communication is serialized, you can have one Task on the DSP like you do on the host.

    DSP Task
    loop
        SIO_issue empty buffer (input channel)
        SIO_issue full buffer  (output channel)
        SIO_reclaim sent buffer (output channel)
        SIO_reclaim received buffer (input channel)

    Host Task
    loop
        CHNL_issue empty buffer (input channel)
        CHNL_reclaim empty buffer (input channel)
        act on data...
        CHNL_issue full buffer (output channel)
        CHNL_reclaim sent buffer (output channel)

    I'm assuming that the Host is providing back some useful data for the DSP. If not, you don't need two channels. If the DSP is just sending data to the Host, there can be an output channel on the DSP and an input channel on the Host. The reclaim on the output channel on the DSP will get back a sent buffer that you can start to fill up again.

    Todd

  • Todd,

    Sorry, my explanations were not really good. I will explain to you. My hardware architecture is a DM6446 connected with an FPGA through VPSS. What I would like to do is exchanging data between the Host and the FPGA, using the DSP only as a bridge.

    My idea is having 2 threads executing in the DSP:

    DSP Task 1
    loop
        SIO_issue empty buffer (input channel)   
        SIO_reclaim received buffer (input channel)

         Write to FPGA


    DSP Task 2
    loop

    Read from FPGA

    SIO_issue full buffer  (output channel)
    SIO_reclaim sent buffer (output channel)

    The host is doing what you said:

    Host Task
    loop
        CHNL_issue empty buffer (input channel)
        CHNL_reclaim empty buffer (input channel)
        act on data...
        CHNL_issue full buffer (output channel)
        CHNL_reclaim sent buffer (output channel)

    Both Host and FPGA provide useful data to each other, that is why I need 2 channels. The APIs that write and read from the FPGA suspend the DSP task until it can read or write the data, that is why I need 2 tasks in the DSP. How do you see it?

    Regards

    Pablo

  • Pablo,

    Thanks. The flow makes sense now. Yes, this should work. Are you making sure the input and output buffers are different for the two channels on the DSP?

    Could you attach the SIO creation code for the DSP (might as well attach the CHNL creation code also).

    Todd

  • Todd,

    Attached I send you the files of the project for the DSP and the host. I have included the configuration files of the DSP, because maybe I am doing something wrong in that step.

    As you will see, in the test that I am doing, the 2 DSP threads are not connected as in a typical loop application that would receive a buffer from the host and send it back.

    The execution flow that I would expect is the following:

    The Host loads the DSP application and enters in a loop in which tries to send data to the DSP.

    When the DSP starts, the thread that Received from the Host is created first and then the thread that Sends the buffer to the Host is created.

    The RX thread in the DSP has the control, so it receives the data from the Host. Then, the host would wait until data from the DSP is received.

    In the DSP, as the Host is not sending more data, the RX thread would execute SIO_reclaim and would suspend. In this moment, the TX thread would take the control and send data to the Host. This last step is the one that is not working.

    If you need any additional information, please ask and I will send you inmediately.

    One more time, thank you very much.

    Regards

    Pablo

  • Todd,

    I have found out something. In task 2, the function TSKLOOP_create_streamTx() executes the instruction:

    *infoPtr = MEM_calloc (DSPLINK_SEGID,
                               sizeof (TSKLOOP_TransferInfo),
                               DSPLINK_BUF_ALIGN) ;

    Using the LEDs of the board for debugging the application, I found out that the task crashes when trying to allocate this memory. This is why the second task does not take the control of the DSP.

    Do you know what could be causing this problem? Not enough heap memory in the DSP? The structure TSKLOOP_TransferInfo seems quite small for causing a heap allocation problem.

    Thank you and best regards!

  • Sorry Todd, I made I mistake there is no error when executing MEM_calloc. I keep debugging...

  • Pablo,

    What type is infoPtr?

    You can use the MEM_stat call before this and determine how much free memory there is. Make sure to look at the max sized free block. This is in the length field of the MEM_Stat structure.

    Todd

  • Todd, now i found it. It fails in functions pool_alloc, when creating the task 2 (function TSKLOOP_create_streamTx):

    numBuffers=2;

    if (status == SYS_OK) {
            for (i = 0 ; (i < info->numBuffers) && (status == SYS_OK) ; i++) {
                status = POOL_alloc (SAMPLE_POOL_ID,
                                     (Ptr *) &(info->buffers [i]),
                                     info->bufferSize) ;

                if (status != SYS_OK) {
                    for (j = 0 ; j < i ; j++) {
                        POOL_free (SAMPLE_POOL_ID,
                                   info->buffers [i],
                                   info->bufferSize) ;
                        info->buffers [j] = NULL ;
                    }
                    status = SYS_EALLOC ;
                }
            }
        }

    'info' pointer is the following:

    typedef struct TSKLOOP_TransferInfo_tag {
        SIO_Handle inputStream;
        SIO_Handle outputStream;
        Uint16     numTransfers;
        Uint32     bufferSize;
        Uint16     receivedSize;
        Uint16     numBuffers;
        Char *     buffers [MAX_BUFFERS];
    } TSKLOOP_TransferInfo;

    MAX_BUFFERS is 100;

    This kind of errors can be caused by a small Pool size? Could you give me any advice for troubleshooting this problem? Thanks again.

    Regards

    Pablo

  • Pablo,

    So are you using MSGQ also?

    Are you freeing the POOL msgs? If you keep allocating, you'll evidently run out of memory.

    Todd