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.

TM4C129ENCPDT: TI RTOS goes to abort when using mailboxes to manage command line interface to/from UART

Part Number: TM4C129ENCPDT
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

Hello,

I am using TI RTOS, and I have two tasks that need to exchange data: cliTask and uartTask. There are dedicated mailboxes for each direction: cli-to-uart, and uart-to-cli to address the uart tx and uart rx functionalities, respectively.

In testing, the CLI has the user to enter the number "1" (I am using TeraTerm). If the input is correct, the CLI displays "You are cool!", and if the input is anything else the CLI reports that the input is not recognized.

There problem appears when I intentionally enter the wrong input. I see the wrong character come in on the UART Rx callback, and I see it post to the correct mailbox, then I see the CLI determine that this is an incorrect input. When the CLI posts the failure message to the UART, the RTOS triggers the abort function.

In the console, I see the following:

FSR = 0x0000
HFSR = 0x40000000
DFSR = 0x0000000b
MMAR = 0xe000ed34
BFAR = 0xe000ed38
AFSR = 0x00000000
Terminating execution...

How can I troubleshoot this? I am using breakpoints, and following execution; however, it seems like there is good information in these codes, and/or other tools that I can use to narrow this down.

Thank you!

  • Hi,

      I'm not sure what is causing the problem. Please note that the Mailbox Object is strictly defined as a static size and length. Mailbox is copy-based - both Thread A and Thread B must allocate memory to hold the contents of the message. I don't know how are you passing the message. Are you passing a pointer or perhaps an array that is larger than the allocated mailbox size? Have you tried to increase the mailbox size to see if it makes a difference? In any case, refer to the below links to diagnose the problem. 

    Debugging

  • Charles,

    Thank you for the response. I have confirmed that the byte size of the two mailboxes is equal to the byte size of the messages being passed: 44 bytes, which includes an array of 32 uint8_t and some "header" variables in a struct.

    After troubleshooting this more, I have located the exact function call in the Mailbox.c library where this occurs. It is in line 238 within the "Mailbox_pend" function. I am including a screen shot of the local variables. Interestingly, the "heap" variable in one of the structures shows zero.

    The sequence of events that leads to this error are as follows:

    1) the CLI task posts strings to the UART_Tx task, and then the CLI task pends for data coming in from the UART_Rx task.

    2) The UART_Tx task outputs the strings, and then pends for more messages from the CLI.

    3) This allows the UART_Rx task to run. When it receives a message from the user, it posts to the CLI task.

    4) The CLI task interrupts the data and then posts a response to the UART_Tx task. Because the CLI task and the UART_Tx task have the same priority, the UART_Tx task does not resume right away.

    5) The CLI task pends for more data coming in from the UART_Rx task. This should allow the UART_Tx task to write the response from the CLI; however, the abort function is called.

    For this situation described above, CLI task has a priority of 6, UART_Tx has a priority of 5, and UART_Rx has a priority of 4.

    Just tested changing the task priorities. For this new test:  CLI task has a priority of 5, UART_Tx has a priority of 6, and UART_Rx has a priority of 4.

    For this situation, the abort function was still called, but it was for the transition between the CLI task and the UART_Tx task (as opposed to the UART_Rx task). So, the issue occurs when there's change of the tasks. Still not sure what the driving problem is, but I feel that I'm getting close.

  • Hi Noah,

      Can you please take a look at this mailbox example? This example resembles to certain degree what you are currently implementing. This example also uses two tasks to communicate through a mailbox. Although this example is for MSP432E, MSP432E is the actually the same silicon as TM4C129. I hope it is some configuration that led to your problem. At the moment I have no reason to think there is a bug in the Mailbox_pend function. 

  • Charles,

    Thank you! This is the example I used when implementing the mailbox functionality. One thing I do not understand is how to properly use multiple mailboxes. In my application, I've implemented 2 instances of 5 mailboxes (5 for CLI-to-UART and 5 for UART-to-CLI). What I do not understand is must I always go through all 5 mailboxes for all transactions? Not all 5 mailboxes are used for every transaction.

    Some transactions only require 1 or 2 of these. I assumed these mailboxes were like FIFO locations, where I could have "up to 5" mailboxes, but this line suggests differently: t loops for NUMMSGS iterations; placing a message in the mailbox. The values that are put in the mailbox are also print to the console.

    I'll try iterating through all mailboxes every time.

  • Hi Noah,

    What I do not understand is must I always go through all 5 mailboxes for all transactions? Not all 5 mailboxes are used for every transaction.

    That is correct. If a given transaction will take up more than one mailbox then you will have a problem. 

      Can you refer to the SYS/BIOS user's guide on section 4.4 for Mailboxes usage? You can also refer to the online user's guide at this link. https://dev.ti.com/tirex/content/tirtos_tivac_2_16_00_08/products/bios_6_45_01_29/docs/cdoc/ti/sysbios/knl/Mailbox.html#per-instance_creation

  • Charles,

    I am completely confused as to what is going and will be sharing snippets of my code for support.

    First of all, I have confirmed that the message size when each mailbox is constructed matches the message size for all Pend and all Post usages. This size is 36 bytes.

    Now, unlike the example my MsgObj consists of an int and an array of unsigned char:

    typedef struct
    {
        Int currentMsgSize;
        UChar  buff[MAILBOX_MESSAGES_SIZE];
    } MsgObj;

    MAILBOX_MESSAGES_SIZE = 32

    This makes sense to me, since 4 bytes for the Int + 32 byes for the unsigned char = 36 bytes.


    Question: can an array be used within the MsgObj type? This deviates from the example, but I need to be able to pass multiple bytes and prefer not to do this one byte at a time.

    The rest of my code follows the example:

    typedef struct
    {
        Mailbox_MbxElem elem; /* Mailbox header        */
        MsgObj obj;           /* Application's mailbox */
    }MailboxMsgObj;


    Question: At two times in the example "padding" is mentioned with regards to the two structs mentioned above, but no further details are provided. What "padding" is needed? Can more detail be provided? Perhaps this is part of the problem.


    Question: Per the comment in the example, it says that each mailbox message requires a header, and again, there is a notice of providing padding. Again, what padding and how is this to be applied?

    It is my style to have all initialization parameters stored in a static modular variable, so these structs are wrapped into a modular type:

    typedef struct
    {
        Mailbox_Struct mbxStruct;
        //Mailbox_Handle mbxHandle;
        Error_Block mbxEb;
        Mailbox_Params mbxParams;
        MailboxMsgObj mailBoxBuffer[NUMBER_OF_MAILBOXES];
    }MailBoxInitType;   

    NUMBER_OF_MAILBOXES = 8

    It is my intention to make 8 mailboxes each 32 bytes in size. I am using software FIFOs to manage to UART transactions and my FIFOs are 8 deep.


    Both mailboxes are constructed using the parameters as follows (note there is a mailbox for CLI-to-UART, and another for UART-to-CLI communications):


    int32_t ConstructMailbox
    (
     MailBoxInitType* initParams,   ///< pointer to initialization parameters
     Mailbox_Handle* mbhRef         ///< pointer to pass the handle by reference
    )
    {
        int32_t returnVal = -1;
        volatile int32_t msgSize = 0;
        
        if (initParams && mbhRef)
        {
            Mailbox_Params_init
            (
                    &initParams->mbxParams
            );

            initParams->mbxParams.buf =
                    ((Ptr)(initParams->mailBoxBuffer));

            initParams->mbxParams.bufSize =
                    sizeof(initParams->mailBoxBuffer);

            msgSize = sizeof(MsgObj);

           Mailbox_construct
           (
                   &initParams->mbxStruct,
                   sizeof(MsgObj),
                   NUMBER_OF_MAILBOXES,
                   &initParams->mbxParams,
                   &initParams->mbxEb//NULL
                   );
           *(mbhRef) = Mailbox_handle(&initParams->mbxStruct);



           System_printf("\r\nThe msg size of this mb is: %d\r\n",Mailbox_getMsgSize(*(mbhRef)));
           System_flush();

           if (mbhRef)
           {
               returnVal = msgSize;
           }
        }
        
        return returnVal;
    }


    The mailbox handles are shared with both the CLI and the UART tasks. Both of these tasks have static modular variables with pointers to mailbox handles. These pointers are populated with the address of the constructed mailboxes, respectively.

    int32_t Assign_UART_CliOutToSerialMailbox
    (
    Mailbox_Handle** mbPtr     ///< double pointer to mailbox for assignment
    )
    {
        int32_t returnVal = -1;

        if (mbPtr)
        {
            *(mbPtr) = &serial_cliSendingOutThroughUart;

            returnVal = 1;
        }

        return returnVal;
    }

    int32_t Assign_UART_CliInFromSerialMailbox
    (
    Mailbox_Handle** mbPtr     ///< double pointer to mailbox for assignment
    )
    {
        int32_t returnVal = -1;

        if (mbPtr)
        {
            *(mbPtr) = &serial_cliReceivingThroughUart;

            returnVal = 1;
        }

        return returnVal;
    }


    By doing this, task modularity is better preserved.


    To send a message out, the CLI populates its local software FIFO. When the task function is called, if this FIFO has a non-zero size, elements are popped from the FIFO and posted to the UART task.

    ************************************
    CLI Tx Steps
    ************************************

    static int32_t ExecuteCliTxFifoActions
    (
    CliFifo* fifo
    )
    {
        int32_t returnVal = -1;
        int32_t origSize = 0;
        int32_t fifoTxSize = 0;
        int32_t NumbFreeMbMsg = 0;
        int32_t loopCount = 0;
        uint32_t i = 0;
        //uint32_t k = 0;
        CliFifoElementType fifoElement;

        if (fifo)
        {


            //if (0 < fifoTxSize)

            NumbFreeMbMsg = GetNumberOfFreeMessageSerialCli();
            fifoTxSize = GetCliFifoSize(&cliData.txFifo);

            loopCount = (NumbFreeMbMsg < fifoTxSize) ? NumbFreeMbMsg : fifoTxSize;

            for (i = 0; i < loopCount; i++)
           // while (0 < (fifoTxSize = GetCliFifoSize(&cliData.txFifo)))
            {

                if (0 == origSize)
                {
                    origSize = fifoTxSize;
                }

                PopCliFifo(&cliData.txFifo,&fifoElement);
                SendSerialOut(/*origSize,i,*/ fifoElement.size,fifoElement.data); //TODO determine if this requires multiple mail boxes
                //i++;
            }

            //Test code

            //for (k = i; (origSize) && (k < NUMBER_OF_MAILBOXES); k++)
            {
              //  SendSerialOutMailboxFlush();
            }

            returnVal = origSize;
        }

        return returnVal;
    }

    static int32_t SendSerialOut
    (
    //uint32_t totalNumberOfMessages,
    //uint32_t currentMessageIndex,
    uint32_t sizeBuff,      ///< Size to send
    uint8_t* buff       ///< Pointer to buffer
    )
    {
        int32_t returnVal = -1;
        //int32_t temp = 0;

        if (sizeBuff && buff)
        {
            if (cliData.cliCommData.serialSend)
            {
                returnVal = cliData.cliCommData.serialSend(/*totalNumberOfMessages, currentMessageIndex,*/ sizeBuff, buff);
            }

            //cliData.cli_cliSerialMbt.msg.val[0] = size;
            //memcpy(&cliData.cli_cliSerialMbt.msg.val[1],buff,size);
            
            //PostMsgToMailBox(cliData.cli_cliSerialMbt.mbhPtr,&cliData.cli_cliSerialMbt.msg);
        }

        return returnVal;
    }

    *****
        cliData.cliCommData.serialSend = SendSerialCliUart;

        cliData.cliCommData.serialReceive = ReceiveCliSerialUart;
        
    ******

    int32_t SendSerialCliUart
    (
    //uint32_t totalNumberOfMessages,
    //uint32_t currentMessageIndex,
    uint32_t size,
    uint8_t* buff
    )
    {
        int32_t returnVal = -1;
        static MsgObj msg;
        
        //msg.currentNumberOfMailboxesUsed = totalNumberOfMessages;
        //msg.idOfCurrentMailbox = currentMessageIndex;

        if (size && buff)
        {
            //cliSerialMbh->
            //cliSerialParam

            msg.currentMsgSize = size;//size = 35

            //cliData.cli_cliSerialMbt.msg.val[0] = size;
            memcpy(msg.buff,buff,size);

            //PostMsgToMailBoxCliSerial(&msg);

            System_printf("\r\nSendSerialCliUart msg size is: %d\r\n", sizeof(msg));
            System_flush();

            PostMsgToMailbox_cliOutThroughSerial(&msg);

            returnVal = 1;
        }
        
        return returnVal;
    }
    int32_t PostMsgToMailbox_cliOutThroughSerial
    (
    MsgObj* msg                 ///< pointer to message
    )
    {
        int32_t returnVal = -1;
        //int32_t stringLen = 0;
        //uint32_t i = 0;
       // char temp = 0;

        //if (mbh && msg)
        {
            //if (mbComm->mbxHandle)
            {
                returnVal = 1;

                //stringLen = strlen(msgString);

                //if (size <= MAILBOX_MESSAGES_NUMB)
                {
                    //for (i = 0; i < stringLen; i++)
                    {
                        //mbComm->postMsg.id = i;
                        //temp = *(msgString++);
                        //mbComm->postMsg.val = temp;
                        //memcpy(mbComm->postMsg)

                        Mailbox_post(serial_cliSendingOutThroughUart, msg, BIOS_NO_WAIT);
                    }
                }


            }
        }

        return returnVal;
    }

    ************************************
    UART Tx Steps
    ************************************

    After transmitting, the UART_Tx sends the message out. It had been pending for the CLI post to occur.

    Void uartTxFxn(UArg arg0, UArg arg1)
    {

        volatile int32_t test = 0;
        static MsgObj msgTx;
        //static MsgObj msgRx;
        //uint32_t size = 0;
        uint32_t i = 0;
        uint32_t k = 0;
        int32_t pendingNumMsg = 0;
        static volatile int32_t msgSize = 0;
        //char input;
        //static uint8_t uartRxBuffer[MAILBOX_MESSAGES_SIZE];
        //int32_t readReturn = 0;

        const char echoPrompt[] = "UART Tx Online!\r\n";

        test = InitUartPerph(&uartSystem.uartPerphData);

        if (0 < test)
        {
            //UART_write(uartSystem.uartPerphData.uart, echoPrompt, sizeof(echoPrompt));
        }

        //UART_write(uartSystem.uartPerphData.uart, echoPrompt, sizeof(echoPrompt));

        /* Loop forever echoing */
        while (1)
        {


            /* This handles sending messages from the CLI out of the UART */
            //memset(&msgTx,0,sizeof(MsgObj));

            //test = PendMsgFromMailbox_cliOutThroughSerial(&msgTx);
            System_printf("\r\nIn Uart Tx Task.\r\n");
            System_flush();
           // if (0 < test)
            {
                //for (i = 0; (i < msgTx.currentNumberOfMailboxesUsed) && (i < NUMBER_OF_MAILBOXES); i++)
                do
                {
                    //size = msgTx.val[0];

                    msgSize = sizeof(msgTx);

                    System_printf("\r\nuartTxFxn msg size is: %d\r\n", msgSize);
                    System_flush();

                    test = PendMsgFromMailbox_cliOutThroughSerial(&msgTx, BIOS_WAIT_FOREVER);

                    if (!pendingNumMsg)
                    {

                        pendingNumMsg = GetNumbPendingMsg_cliOutThroughSerial();
                    }

                    if ((0 < test))// && (msgTx.currentMsgSize))
                    {

                        UART_write(uartSystem.uartPerphData.uart, msgTx.buff, msgTx.currentMsgSize);//&msgTx.val[1], size);

                    //Semaphore_post(uartSystem.uartSem.sem);
                    }
                    i++;
                }while (i < pendingNumMsg);//msgTx.currentNumberOfMailboxesUsed);

     
            }




        }
    }

    When the UART tx task finshes, the UART_Rx task is allowed to start.

    ************************************
    UART Rx Steps
    ************************************

    Void uartRxFxn(UArg arg0, UArg arg1)
    {

        volatile int32_t test = 0;
        //static MsgObj msgTx;
       // static MsgObj msgRx;
        //uint32_t size = 0;
        //char input;
        //static uint8_t uartRxBuffer[MAILBOX_MESSAGES_SIZE];
        volatile int32_t readReturn = 0;
        int32_t fifoSize = 0;
        int32_t orgFifoSize = 0;
        uint32_t i = 0;
        uint32_t k = 0;
        static UartFifoElementType fifoElement;
        //uint32_t timeout = 100 * (1000/Clock_tickPeriod);


        const char echoPrompt[] = "UART Rx Online!\r\n";

        test = InitUartPerph(&uartSystem.uartPerphData);

        if (0 < test)
        {
            //UART_write(uartSystem.uartPerphData.uart, echoPrompt, sizeof(echoPrompt));
        }

        //UART_write(uartSystem.uartPerphData.uart, echoPrompt, sizeof(echoPrompt));

        /* Loop forever echoing */
        while (1)
        {
            //TODO need to employ a scheme where UART can receive messages at any time
            //And, delay/pend on messages that need to be transmitted.
            //Maybe need a uart tx and uart rx task?
            //Looks like I can set the timeout on the pend, and not have it be forever.

            //test = ReadUart(&uartSystem.uartPerphData.uart, &uartSystem.rxFifo);

            //if (0 < test)
            //{

            //}

            //test = WriteUart(&uartSystem.uartPerphData.uart, &uartSystem.txFifo);
            /* This handles receiving of messages from the UART to the CLI */

            //if (uart_readNotCalled == uartSystem.uartPerphData.readActionStatus)
            {
               // uartSystem.uartPerphData.readActionStatus = uart_readCalled;

                System_printf("\r\nIn Uart Rx Task.\r\n");
                System_flush();

                while (0 < (fifoSize = GetUartFifoSize(&uartSystem.rxMgmt.fifo)))
                {
                    if (0 == orgFifoSize)
                    {
                        orgFifoSize = fifoSize;
                    }

                    PopUartFifo(&uartSystem.rxMgmt.fifo, &fifoElement);

                    //uartSystem.rxMgmt.msg.currentNumberOfMailboxesUsed = orgFifoSize;
                    //uartSystem.rxMgmt.msg.idOfCurrentMailbox = i;
                    uartSystem.rxMgmt.msg.currentMsgSize = fifoElement.size;
                    memcpy(uartSystem.rxMgmt.msg.buff,fifoElement.data, fifoElement.size);

                    System_printf("\r\nuartRxFxn msg size is: %d\r\n", sizeof(uartSystem.rxMgmt.msg));
                    System_flush();

                    PostMsgToMailbox_cliInFromSerial(&uartSystem.rxMgmt.msg, BIOS_NO_WAIT);
                    i++;


                }
                //Test code
                memset(&uartSystem.rxMgmt.msg,0,sizeof(MsgObj));

                for (k = i; (orgFifoSize) && (k < NUMBER_OF_MAILBOXES); k++)
                {
                    PostMsgToMailbox_cliInFromSerial(&uartSystem.rxMgmt.msg, BIOS_NO_WAIT);
                }

                memset(uartSystem.rxMgmt.rxBuffer,0,MAILBOX_MESSAGES_SIZE);

                readReturn = UART_read(uartSystem.uartPerphData.uart, uartSystem.rxMgmt.rxBuffer, MAILBOX_MESSAGES_SIZE);
            }

        }
    }

    The UART_Rx task utitlizes a callback to receive the message:
    static void CallbackUartRead
    (
    UART_Handle uart,
    void* buffer,
    size_t size
    )
    {
        //static MsgObj msg;
        //uint32_t timeout = 100 * (1000/Clock_tickPeriod);
        //uint32_t i = 0;
        static UartFifoElementType fifoElement;

        //if (uart_readCalled == uartSystem.uartPerphData.readActionStatus)
        {
            if (1 < size) //size will equal 1 if there is a newline, which is will result in a double triggering
            {
                memset(&fifoElement,0,sizeof(UartFifoElementType));

                //msg.val[0] = size;

                fifoElement.size = size;
                memcpy(fifoElement.data,buffer,(size < UART_STRING_SIZE) ? size : UART_STRING_SIZE);


                PushUartFifo(&uartSystem.rxMgmt.fifo,&fifoElement);





            }

        }
    }

    When a message is recieved, the UART_Rx task posts this to the CLI Task. The CLI Task analyzes this message, and sends either a confirmation or an error message, depending on the validity of the message recieved.


    ************************************
    CLI Rx Steps
    ************************************

    ExecuteCliRxMailboxActions(cliData.cliCommData.serialReceive,&cliData.rxFifo);


    static int32_t ExecuteCliRxMailboxActions
    (
    SerialFpRx serialRxFp,
    CliFifo* rxFifo
    //uint32_t buffSize,
    //uint8_t* buff
    )
    {
        int32_t returnVal = -1;
        //int32_t origSize = 0;
        //int32_t fifoRxSize = 0;
        //int32_t bytesReceived = 0;
        //uint32_t i = 0;
        //CliFifoElementType fifoElement;

        if (serialRxFp && rxFifo)// && buffSize && buff)
        {
            {
                returnVal = serialRxFp(rxFifo);

                //if (0 < bytesReceived)
                {
                    //fifoElement.size = bytesReceived;

                   // returnVal = PushCliFifo(fifo,&fifoElement);
                }
            }

        }

        return returnVal;
    }

    int32_t ReceiveCliSerialUart
    (
    CliFifo* rxFifo
    )
    {
        int32_t returnVal = -1;
        int32_t numbPendingMsg = 0;
        //uint32_t bytesReceived = 0;
        uint32_t i = 0;
        //uint32_t k = 0;
        static MsgObj msg;
        static CliFifoElementType fifoElement;
        static volatile int32_t msgSize = 0;
        
        if (rxFifo)
        {
            //cliSerialMbh->
            //cliSerialParam

            //msg.val[0] = size;//size = 35

            //cliData.cli_cliSerialMbt.msg.val[0] = size;
            //memcpy(&msg.val[1],buff,size);

            do
            {

                msgSize = sizeof(MsgObj);

                System_printf("\r\nReceiveCliSerialUart msg size is: %d\r\n", msgSize);
                System_flush();
                memset(&msg,0,sizeof(MsgObj));
                PendMsgFromMailbox_cliInFromSerial(&msg, BIOS_WAIT_FOREVER);//TODO upon entering a "2" from Home screen, this causes abort function to be called.

                if (!numbPendingMsg)
                {
                    numbPendingMsg = GetNumbPendingMsg_cliInFromSerial();
                }

                fifoElement.size = msg.currentMsgSize;
            
                memcpy(fifoElement.data, msg.buff, (msg.currentMsgSize < CLI_STRING_SIZE) ? msg.currentMsgSize : CLI_STRING_SIZE);

                PushCliFifo(rxFifo, &fifoElement);
                i++;
            }while(i < numbPendingMsg);//msg.currentNumberOfMailboxesUsed);
            
            //for (k = i; (i) && (k < NUMBER_OF_MAILBOXES); k++)
            //{
                //PendMsgFromMailbox_cliInFromSerial(&msg, BIOS_WAIT_FOREVER);
            //}
            
            //if (size >= bytesReceived)
            {
            
                returnVal = numbPendingMsg;//msg.currentNumberOfMailboxesUsed;
            }
            
            
        }
        
        return returnVal;
    }

  • Hi Noah,

      Some quick questions.

     - If you run the example as is, what is the result?

     - Did you create your application from a new sysconfig? What if you extend the example sysconfig to include additional drivers for UART?

     - For experiment purpose, what if you mimic the example for the same message size and number of messages? I just wanted to know under what circumstances will your code not abort? Or your code will abort no matter what.