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.

BIOSPSP 3.001.01.00 UART Rx Error Causes Null Pointer Reference and Interrupt Delays

Hi,

    I am having trouble recovering from Rx errors in the UART driver provided in the BIOSPSP. It is operating in interrupt mode with FIFO enabled on a c6748. When the Rx error occurs, the error bits OE and FE are set. There is also the IOM_TIMEOUT status value in my app callback function. This is all expected, but I have several problems. The first problem is that the uartHandleRxError function seems to be causing HWI delays (I have a HWI that can at a period of .05 ms ). The second problem is that this will cause a null pointer exception inside the uartIsr. The third problem is how to recover from this error when it occurs. I have tried calling Uart_IOCTL_RESET_RX_FIFO, and Uart_IOCTL_CANCEL_CURRENT_IO as seen from a different post, but the UART does not recover. 

   Looking at the Uart source files, I think I have narrowed down the causes of the first two problems.

   In uartIsr, UartFifoRead is called which calls the uartHandleRxError. Inside uartHandleRxError is this:

do
{
/* Read and throw error byte */
/* Till Line status int is pending */
tempByte = (Uint8)((instHandle->deviceInfo.baseAddress)->RBR);
/* To remove compiler "unused" warnings */
tempByte = tempByte;

iteration--;
while( (instHandle->deviceInfo.baseAddress->LSR
& CSL_UART_LSR_DR_MASK) == 0)
{
if (delay == 0)
{
break;
}
delay--;
}

status = (instHandle->deviceInfo.baseAddress)->LSR;
status &= (CSL_UART_LSR_BI_MASK |
CSL_UART_LSR_FE_MASK |
CSL_UART_LSR_PE_MASK |
CSL_UART_LSR_OE_MASK |
CSL_UART_LSR_RXFIFOE_MASK);
} while( ( status != 0 ) && (iteration != 0) );

if(NULL != chanHandle->activeIOP)
{
Uart_localCompleteCurrentIO(chanHandle);
}

    iteration = 16 and delay = 0xFFFF.

    Could this be a potential cause to the interrupt delay? and why the delay? I see that the UartIsr is registered as 'unmasked'. what does that mean?

    Also, localcompletecurrentIO is called in here, but when it returns up to the uartIsr, localcompletecurrentIO is going to be called again. But this time, the activeIOP is set to NULL and causes exceptions in the callback of GIO- which is my second problem. So is this the expected behavior when Rx error happens?

    Lastly, if this error does happen, then is it ok to call the reset routine for the UART handle inside the app callback or should it wait till the uartIsr finishes?

Thank You

  • Hi Joe Chong,

    Thanks for your post.

    Usually, all other interrupts would be masked when you use ECM dispatcher in the .tcf file but in your case, it is not required since you mapped the UART interrupt directly to one of HWI. I hope, you wouldn't use ECM dispatcher in the .tcf file, if i am not wrong.

    Please refer the code snippet below from the PSP release for the UART handler. It is highly recommended to follow this as much as possible in your version of the implementation.

    Also, Please make sure that IPEND bit is polled for before exiting the ISR. (Highlighted in while loop in bold)

    void uartIsr(Arg arg)

    {

        volatile Uint32   status      = 0x01u;

        Uint32            intrCnt     = 0;

        Uart_Object      *instHandle  = NULL;

        Uart_ChanObj     *chanHandle  = NULL;

        Uint32            xfer        = 0;

    #ifdef BIOS_PWRM_ENABLE

        Uns               count       = 0x00;

    #else

        IOM_Packet       *ioPacket    = NULL;

    #endif

     

        assert(NULL != arg);

     

        instHandle = (Uart_Object*)arg;

        status = (Uint32)uartGetIntrStatus(instHandle);

       

        while ((CSL_UART_IIR_IPEND_PEND == (status & CSL_UART_IIR_IPEND_NO_PEND))

              && ((intrCnt) < (Uart_MAX_ISR_LOOP)))

        {

            intrCnt++;

     

            /*  check for any line error while transfer                           */

            if (CSL_UART_IIR_INTID_RLS ==

                    (CSL_UART_IIR_INTID_RLS & (status >> CSL_UART_IIR_INTID_SHIFT)))

            {

                /* call this function when ther is any line error                 */

                uartHandleRxError(&(instHandle->rcvChanObj));

            }

            else if(Uart_OpMode_INTERRUPT == instHandle->opMode)

            {

                /* check whether any character timeout happened                   */

                if( CSL_UART_IIR_INTID_RDA ==

                    (CSL_UART_IIR_INTID_RDA & (status >> CSL_UART_IIR_INTID_SHIFT)))

                {

                    if(CSL_UART_IIR_INTID_CTI ==

                        (CSL_UART_IIR_INTID_CTI & (status >> CSL_UART_IIR_INTID_SHIFT)))

                    {

                        chanHandle = &(instHandle->rcvChanObj);

                        /* if timeout error then update stats                     */

                        instHandle->stats.rxTimeout++; 

                        /* Increment the error count                              */

                        chanHandle->errors++; 

                        /* Update the IOP with proper status                      */

                        chanHandle->activeIOP->status = IOM_ETIMEOUT; 

                        /* Transfer the remanant bytes if any are remaining in the*

                         * FIFO                                                   */

                        xfer = uartFifoRead(chanHandle,

                                chanHandle->activeBuf,

                                chanHandle->bytesRemaining); 

                        chanHandle->bytesRemaining    -= xfer;

                        chanHandle->activeBuf         += xfer;

                        instHandle->stats.rxBytes     += xfer; 

                        /* Disable the RX interrupts before completing. If only   *

                         * there is a packet for processing it shall be re-enabled*/

                        uartIntrDisable(instHandle,

                            (Uint32)(Uart_Intr_RLS | Uart_Intr_RHR)); 

                        /* Perform the operation to complete the IO               */

                        Uart_localCompleteCurrentIO(chanHandle);

    #ifdef BIOS_PWRM_ENABLE

                        if ((TRUE == instHandle->devParams.pscPwrmEnable) &&

                             (TRUE == instHandle->pwrmInfo.ioSuspend))

                        {

                            /* set the current active IOP as NULL                 */

                            chanHandle->activeIOP = NULL;

                            instHandle->devState = Uart_DriverState_PWRM_SUSPEND; 

                            if ((NULL == instHandle->rcvChanObj.activeIOP) &&

                                (NULL == instHandle->xmtChanObj.activeIOP))

                            {

                                /* if both the channels are inactive then reset   *

                                 * the io suspend flag                            */

                                instHandle->pwrmInfo.ioSuspend = FALSE; 

                                if ((PWRM_GOINGTOSLEEP == instHandle->pwrmInfo.pwrmEvent) ||

                                    (PWRM_GOINGTODEEPSLEEP == instHandle->pwrmInfo.pwrmEvent))

                                {

                                    /* reduce the dependency count                    */

                                    status = PWRM_getDependencyCount(

                                                (PWRM_Resource)instHandle->deviceInfo.pwrmLpscId,

                                                 &count);                           

                                    instHandle->pwrmInfo.dependencyCount = count;                           

                                    if (PWRM_SOK == status)

                                    {

                                        while (count > 0)

                                        {

                                            status =  PWRM_releaseDependency(

                                                      (PWRM_Resource)

                                                      instHandle->deviceInfo.pwrmLpscId);                           

                                            if (PWRM_SOK != status)

                                            {

                                                break;

                                            }

                                            count--;

                                        }

                                    }

                                }                           

                                /* call the delayed completion function           */

                                (instHandle->pwrmInfo.delayedCompletionFxn  \

                                    [instHandle->pwrmInfo.pwrmEvent])();

                            }

                        }

    #else

                        /* Now that we have just completed the current IOP        *

                         * we proceed to check if there are still packets         *

                         * pending in pending queue                               */

                        if (FALSE == QUE_empty(&(chanHandle->queuePendingList)))

                        {

                            /* we have atleast one packet                                         */

                            ioPacket = (IOM_Packet *)QUE_get(&(chanHandle->queuePendingList)); 

                            /* validate and update the iop                                        */

                            if (NULL  != ioPacket)

                            {

                                chanHandle->activeIOP      = ioPacket;

                                chanHandle->activeBuf      = ioPacket->addr;

                                chanHandle->bytesRemaining = ioPacket->size;

                                chanHandle->errors = 0;

                            }

                            uartIntrEnable(instHandle,

                               (Uint32)(Uart_Intr_RLS | Uart_Intr_RHR));

                        }

                        else

                        {

                            chanHandle->activeIOP = NULL;

                        }

    #endif

                    }

                    else

                    {

                        /* Disable the receive interrupt until current interrupt  *

                         * is processed. Re-enabled again in uartIntrHandler()    */

                        uartIntrDisable(instHandle,(Uint32)(Uart_Intr_RHR)); 

                        SWI_post(instHandle->rxTskletHandle);

                    }

                }

                else

                {

                    /* check whether Tx register is empty or not                  */

                    if (CSL_UART_IIR_INTID_THRE ==

                        (CSL_UART_IIR_INTID_THRE & (status >> CSL_UART_IIR_INTID_SHIFT)))

                    {

                        /* Disable the transmit interrupt until current interrupt *

                         * is processed. Re-enabled again in uartIntrHandler()    */

                        uartIntrDisable(instHandle,(Uint32)(Uart_Intr_THR));

                        SWI_post(instHandle->txTskletHandle);

                    }

                    else

                    {

                        /* check modem status                                     */

                        if (CSL_UART_IIR_INTID_MODSTAT ==

                            (CSL_UART_IIR_INTID_MODSTAT & (status >> CSL_UART_IIR_INTID_SHIFT)))

                        {

                            /* Read the MSR to clear Modem Status Int cause       */

                            (instHandle->deviceInfo.baseAddress)->SCR =

                                (instHandle->deviceInfo.baseAddress)->MSR;

                        }

                    }

                }

            }

            else

            {

                /* Do nothing                                                     */

            }

            status = uartGetIntrStatus(instHandle);

        }

    }

    Hope it helps!

    Thanks & regards,

    Sivaraj K

    ---------------------------------------------------------------------------------
    Please click the
    Verify Answer button on this post if it answers your question.
    ---------------------------------------------------------------------------------
  • Hi Sivaraj Kuppuraj,

    Thank you for the reply.

    I am using the UART driver provided with BIOSPSP, so that highlighted code is there. I do not have the HWI assigned to my UART reassigned to anything else if that is what you are referring to.

    Here are my Uart Config params for reference:

    Uart_FlowControl fchw_auto_rts_cts;
    fchw_auto_rts_cts.fcParam = Uart_FcParam_AUTO_RTS_CTS;
    fchw_auto_rts_cts.fcType = Uart_FcType_HW;

    Uart0Params = Uart_PARAMS;

    Uart0Params.hwiNumber = 8;
    Uart0Params.opMode = Uart_OpMode_INTERRUPT;//Uart_OpMode_DMAINTERRUPT;
    //Uart0Params.loopbackEnabled = false;
    Uart0Params.rxThreshold = Uart_RxTrigLvl_14;
    Uart0Params.softTxFifoThreshold = 1;
    Uart0Params.baudRate = Uart_BaudRate_893_8K;
    Uart0Params.parity = Uart_Parity_NONE;
    Uart0Params.charLen = Uart_CharLen_8;
    Uart0Params.fc = fchw_auto_rts_cts;

    Uart0Params.enableCache = true;
    Uart0Params.fifoEnable = true;
    Uart0Params.stopBits = Uart_NumStopBits_1;
    //Uart0Params.edmaRxTC;
    Uart0Params.polledModeTimeout = 0x00FFFFFF;
    //Uart0Params.pscPwrmEnable = true;
    //Uart0Params.pllDomain;
    #ifndef PROFILER
    /* enable the EDMA in the PSC module */
    Power_setDependency(Power_RSRC_UART_0);
    Power_setDependency(Power_RSRC_EDMA3_CC_0);
    Power_setDependency(Power_RSRC_EDMA3_TC_0);
    Power_setDependency(Power_RSRC_EDMA3_TC_1);
    Power_setDependency(Power_RSRC_EDMA3_TC_2);
    #endif

    Could you possibly answer my other questions regarding the delay in the driver code or the null pointer ref?