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.

Behaviour of Task_sleep() and Task_yield

Hi

1) Assume I have a task coded as below:

void taskFxn(void)

{

while(1)

{

statement1;

statement2;

Task_yield(); //or Task_sleep(x);

statement3;

}

}

Where does execution resume after Task_yield() or Task_sleep() are called when the task resumes?

2) Suppose now I modify the code as below so that it does not call Task_yield() directly but calls a function that calls task yield() again inside

an infinite loop:

void taskFxn(void)

{

while(1)

{

statement1;

statement2;

FunctionA();

statement3;

}

}

void FunctionA(void)

{

while (1)

{
statementA;

Task_yield();//or Task_sleep(x);

statementB;

}

}

Now in this case again where does execution resume after Task_yield() or Task_sleep() are called when the task resumes?

Regards

  • Hello Nikhil

    This post has got nothing to do with TM4C. TI-RTOS seems to be the correct forum...

    Regards
    Amit
  • Thanks for moving it. I was looking at some reply in the TM4C forum and by mistake posted it there itself.
    Regards
  • Hi Nikhil,

    In both cases execution will resume from the next instruction following the Task_yield()/Task_sleep() call.

    Best,

    Ashish

  • Hi Ashish,

    This was my understanding too. However some of the local variables that are declared and initialized just on entering FunctionA, before the while(1) loop, appear to get re-initialized. This was causing my program not to work as one of the variable was keeping track of task state and this was changing back to zero. The only way this could have happened was that FunctionA was being entered again. The problem disappeared when I declared the variable as static. Now my program works correctly but it does raise the question -why is the local variable changing back to zero when not static.

    The function is supposed to do the following:

    1) A device sends data asynchronously over the serial port in the form <0D>,<0A>,<variable length data>,<0d>,<0A>

    2) Function waits for leading 0D,0A, stores data received in a pointer passed as argument and returns the length. It also removes trailing 0D and 0A from the

    buffer.

    3)The function yields if there is no data in the buffer. It returns only after trailing 0D,0A are received.

    The code is given below: The variable header_rcvd keeps track of state. Note the use of static.

    uint8_t  Mydevice_get_response(char *response)
    {
        uint8_t a=0x41,b=0x41,c=0,count;
        static uint8_t header_rcvd=0;
     while (1)
     {
            UART_control(Uart_Handle[1],UART_CMD_GETRXCOUNT,&count);

            while ((count>0)&&(header_rcvd==0)) //this section identifies header
                {
                    a=b;
                    b=c;
                   count--;
                    if ((a==0x0D)&&(b==0x0A)&&(c!=0x0D))
                        {
                            header_rcvd=1;
                            a=1;
                            *response++=c; //stoe first character
                          }
                }


            while ((count>0) && (header_rcvd==1)) //Get remaining characters till 0x0D is recd
                {
                    UART_read(Uart_Handle[1], (void *)&c, 1);
                    count--;
                    if(c!=0x0D)
                    {
                    *response++=c;
                    a++;
                    } else header_rcvd=2;
                }

            if ((count)&&(header_rcvd==2)) //remove trailing LF from buffer
                {
                UART_read(Uart_Handle[1], (void *)&c, 1);
                count--;
                header_rcvd=0; //reset state for next operation
                return(a); //return no of characters in response field
                }
               Task_yield(); //if no more characters yield for next iteration do not block
        }
              return(0); //never reaches here
    }

    The function does not work if static is removed from declaration of header_rcvd. Initially it was not included but during debugging I discovered that it was being changed to 1 in the first section of the code, that detects and  strips the header but changing back to zero, suggesting that it was being reinitialized when task resumed. I used static in the declaration and everything started working correctly. I tested the function by sending CR+LF from a terminal. entering a string and then again entering CR+LF. In the calling task I print out the characters in the response array.

    It is working for now, but I think the issue needs looking into.

    Regards

  • Hi Nikhil,

    I agree that the issue needs some looking into. The local variables on the stack should stay preserved across calls to Task_yield and Task_sleep. If the value of the local variables is changing then something else may be wrong. I am wondering if one of the task stacks is overflowing or if a function is corrupting the task stack. Can you check the stack peak in Task module's detailed ROV view ?

    Best,
    Ashish
  • Hi Ashish
    1) I was able to solve the problem over the weekend. The function
    UART_control(Uart_Handle[1],UART_CMD_GETRXCOUNT,&count);
    internally casts &count as an int* before assignement. I have declared count and header_rcvd as uint8_t in succession.
    This was causing header_rcvd to be overwritten when count was written to as an integer.
    Declaring header_rcvd as static was causing it to move to the heap and so it was working. I changed count to an int and everything worked fine.

    2) However this brings me to a bigger issue.
    How do I allocate storage for an argument type declared void * in a library function? The function UART_control is prototyped as:
    extern int UART_control(UART_Handle handle, unsigned int cmd, void *arg);
    I have no way of knowing the size of *arg unless I look at the source code( which might not always be available). Are there any general guidelines to avoid pitfalls like this?
    Regards
  • Hi Nikhil,

    Glad to know you found the root cause and resolved it.

    Our recommendation would be to refer the doxygen documentation for the various TI-RTOS driver APIs. The "UART.h" doxygen for example specifies the type "arg" is suppose to point to for the different UART_Control commands.

    The doxygen html files can be found in your TI-RTOS installation: C:\ti\tirtos_tivac_2_12_xx_xx\docs\doxygen\html\index.html

    Best,
    Ashish
  • Hi Ashish,

    Referring to the documentation following is the excerpt for UART_control()

    int UART_control ( UART_Handle   handle,

    unsigned int   cmd,

    void *   arg

    )

    Function performs implementation specific features on a given UART_Handle.

    Precondition

       UART_open() has to be called first.

    Parameters

       handle A UART handle returned from UART_open()

       cmd A command value defined by the driver specific implementation

       arg An optional R/W (read/write) argument that is accompanied with cmd

    Returns

       Implementation specific return codes. Negative values indicate unsuccessful operations.

    See also

       UART_open()


    It would be helpful, if notes regarding function arguments and return types, or references thereof  if present ,elsewhere in the documentation are mentioned as well in the parameters/returns sections.

    In the present case they are mentioned separately but rather difficult to locate unless you go through the whole document. Small notes/links  to the sections would be helpful.

    Regards

  • Hi Nikhil,

    I filed a CQ (bug report) to update the documentation. The CQ requests that the documentation clearly highlight the object type the "void *" arguments will be type cast to point to within the driver functions.

    Here's a link to the CQ:

    https://cqweb.ext.ti.com/cqweb/main?command=GenerateMainFrame&service=CQ&schema=SDO-Web&contextid=SDOWP&entityID=SDOCM00116674&entityDefName=IncidentReport&username=readonly&password=readonly

    Best,

    Ashish

  • Hi Ashish,

    Thanks, for taking it up.

    For some reason the link given above is not opening. I get an error.

    I did mention in my post that ,they are mentioned separately but in a different section. My take , as an end user would be that any defines/details of arguments that are specific to a function should be mentioned along with the function description. Defines/details of arguments that are common to a whole group of functions can be placed separately. This is not a bug technically but something that would be helpful to the end user if implemented. Anyway my problem is solved. (I think many of these problems are due to doxygen generated documentation).

    Secondly speaking of bugs in documentation , if you see the UART API section of doxygen docs , of tirtos_tivac_2_10_01_38 it does not mention that UART_control() is not implemented but gives a clear description of the function.

    However the file UARTTiva.c from the same version of RTOS says that the function is not implemented.

    Moreover the header and body are included, so that end user would not get an error when he uses it.

    This is a bug. It is not even mentioned in the release notes of tirtos_tivac_2_10_01_38 or fixes of tirtos_tivac_2_12_01_33. Following is the excerpt of UART_control from UARTTiva.c of tirtos_tivac_2_10_01_38

    /*
    * ======== UARTTiva_control ========
    * @pre Function assumes that the handle is not NULL
    */
    int UARTTiva_control(UART_Handle handle, unsigned int cmd, void *arg)
    {
    /* No implementation yet */
    return (UARTTiva_CMD_UNDEFINED);
    }

    Regards
  • Hi Nikhil,

    I appended the bug description to request that API documentation mention if a particular API is not implemented on certain device families.

    The CQ (bug) link usually takes several hours before going live. That said, it should have become active by now. Maybe give it another day and try again.

    Best,

    Ashish