K64F infinite UART IRQ loop

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

K64F infinite UART IRQ loop

2,046 Views
jheni
Contributor I

Hey guys,

I'm using the SDK's UART RX and TX Functions in order to send or receive data

UART_TransferReceiveNonBlocking()

and

UART_TransferSendNonBlocking()

The IRQ Callback sets a finnish Eventbit (or a failure eventbit).

So far for the theory :smileyhappy:

However there are some reasons where I end up in an infinite IRQ loop. From Debugging I found out that

void UART_TransferHandleIRQ(UART_Type *base, uart_handle_t *handle)

{

//some other checks

/* Receive data register full */
    if ((((uint32_t)kUART_RxDataRegFullFlag & status) != 0U) && ((UART_C2_RIE_MASK & base->C2) != 0U))
    {
/* Get the size that can be stored into buffer for this interrupt. */
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
        count = base->RCFIFO;
#else
        count = 1;
#endif

//in the infinite loop I end up here where RX is Full but count = 0

        /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
        while ((count != 0U) && (handle->rxDataSize != 0U))
        {
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
            tempCount = (uint8_t)MIN(handle->rxDataSize, (uint32_t)count);
#else
            tempCount = 1;
#endif

            /* Using non block API to read the data from the registers. */
            UART_ReadNonBlocking(base, handle->rxData, tempCount);
            handle->rxData += tempCount;
            handle->rxDataSize -= tempCount;
            count -= tempCount;

            /* If all the data required for upper layer is ready, trigger callback. */
            if (0U == handle->rxDataSize)
            {
                handle->rxState = (uint8_t)kUART_RxIdle;

                if (handle->callback != NULL)
                {
                    handle->callback(base, handle, kStatus_UART_RxIdle, handle->userData);
                }
            }
        }

        /* If use RX ring buffer, receive data to ring buffer. */
        if (handle->rxRingBuffer != NULL)
        {
            while (0U != count--)
            {
                /* If RX ring buffer is full, trigger callback to notify over run. */
                if (UART_TransferIsRxRingBufferFull(handle))
                {
                    if (handle->callback != NULL)
                    {
                        handle->callback(base, handle, kStatus_UART_RxRingBufferOverrun, handle->userData);
                    }
                }

                /* If ring buffer is still full after callback function, the oldest data is overridden. */
                if (UART_TransferIsRxRingBufferFull(handle))
                {
                    /* Increase handle->rxRingBufferTail to make room for new data. */
                    if ((size_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
                    {
                        handle->rxRingBufferTail = 0U;
                    }
                    else
                    {
                        handle->rxRingBufferTail++;
                    }
                }

                /* Read data. */
                tmpdata                                        = base->D;
                handle->rxRingBuffer[handle->rxRingBufferHead] = tmpdata;

                /* Increase handle->rxRingBufferHead. */
                if ((size_t)handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
                {
                    handle->rxRingBufferHead = 0U;
                }
                else
                {
                    handle->rxRingBufferHead++;
                }
            }
        }

        else if (0U == handle->rxDataSize)
        {
            /* Disable RX interrupt/overrun interrupt/fram error/idle line detected interrupt */
            UART_DisableInterrupts(base, (uint32_t)kUART_RxDataRegFullInterruptEnable |
                                             (uint32_t)kUART_RxOverrunInterruptEnable |
                                             (uint32_t)kUART_FramingErrorInterruptEnable);

            /* Disable parity error interrupt when parity mode is enable*/
            if ((UART_C1_PE_MASK & base->C1) != 0U)
            {
                UART_DisableInterrupts(base, (uint32_t)kUART_ParityErrorInterruptEnable);
            }
        }
        else
        {
        }
    }

//.... some further Checks

}

Do you know How I could avoid this sittuation where kUART_RxDataRegFullFlag is full but count = 0? I looks like the SDK does not use the UART RX FIFO. To me that sounds like there is nothing in the RX register (or only garbage) but the interupt was triggerd.

How can i clear the kUART_RxDataRegFullFlag  Interrupt Pending flag?

Or, if it is not possible to clear the kUART_RxDataRegFullFlag  IRQ Pending flag, how can i shoot down the whole UARTX IRQ Vector.

I tried the following

UART_DisableInterrupts(pMyUart,kUART_AllInterruptsEnable);

UART_EnableRx(pMyUart,false);
 UART_EnableTx(pMyUart,false);

 UART_Deinit(pMyUart);

do you have a suggestion for me?

BTW: I couldn't find a code formating option. Is there any?

kind regards Julian

Tags (1)
0 Kudos
12 Replies

830 Views
jbrud
Contributor III

Hi all,

I faced exactly the same issue. Has anyone found a solution for this?

Thanks,

Johannes

0 Kudos

809 Views
jbrud
Contributor III

I catched the case when the kUART_RxDataRegFullFlag is set but the FIFO is empty and added the handling which is the same as when receiving was successful or aborted.

...
    /* Receive data register full */
    if ((((uint32_t)kUART_RxDataRegFullFlag & status) != 0U) && ((UART_C2_RIE_MASK & base->C2) != 0U))
    {
/* Get the size that can be stored into buffer for this interrupt. */
#if defined(FSL_FEATURE_UART_HAS_FIFO) && FSL_FEATURE_UART_HAS_FIFO
        count = base->RCFIFO;
#else
        count = 1;
#endif

        if( count == 0U && handle->rxDataSize > 0U ) {
           /* Disable and re-enable the global interrupt to protect the interrupt enable register during
             * read-modify-wrte. */
            irqMask = DisableGlobalIRQ();
            /* Disable RX interrupt/overrun interrupt/fram error/idle line detected interrupt */
            base->C2 &= ~((uint8_t)UART_C2_RIE_MASK | (uint8_t)UART_C2_ILIE_MASK);
            base->C3 &= ~((uint8_t)UART_C3_ORIE_MASK | (uint8_t)UART_C3_FEIE_MASK);
            /* Disable parity error interrupt when parity mode is enabled */
            if (((uint8_t)UART_C1_PE_MASK & base->C1) != 0U)
            {
                base->C3 &= ~(uint8_t)UART_C3_PEIE_MASK;
            }
            EnableGlobalIRQ(irqMask);
        }

        /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
        while ((count != 0U) && (handle->rxDataSize != 0U))
        {
...

 This workaround brings back the driver to normal operation.  Anyway it would be good know from NXP, how this can be happen that the FIFO is empty but kUART_RxDataRegFullFlag is set.

0 Kudos

1,778 Views
dfahrion
Contributor I

I'm seeing the same behavior on a KVM5 processor.  It has been a few months since the original post, has anyone made any progress?

The KVM5 processor has 2 UARTs with a 8 byte FIFO and I'm using DMA on one and interrupts on the other one.  On the one with interrupts when sending a lot of traffic in a debug build I am seeing the interrupt handler get into a state where the RDRF flag is set but the RCFIFO is reading as 0.  At this point it is stuck in the interrupt handler until the watchdog reboots it.

I believe somehow the FIFO count has gotten out of sync.  I know this happens on this processor when there is an overrun, however I am not getting an overrun interrupt.  I found when this happens if I then read the data and flush the FIFO like the overrun handler does it recovers.  I suspect whatever causes the FIFO count to get out of sync during an overrun is happening, however the strange part is I am not getting any overrun interrupt, thus the normal overrun handler in the BSP is not fixing it.  Is there some other condition that can cause the FIFO count to get out of sync that I (or the BSP) should be handling?  My only other thought is there is an overrun interrupt but something is accidentally clearing it, but looking through the BSP code and how I am calling it and I am not seeing where that might be happening.


The other part that makes this frustrating to handle is frequently even when it is working when you first get the RDRF interrupt the RCFIFO is 0, it can take several interrupt loops before it registers the correct count and the interrupt is actually handled, so just triggering on RDRF set with RCFIFO=0 doesn't work.

Thanks,

Dan

0 Kudos

1,794 Views
Sabina_Bruce
NXP Employee
NXP Employee

I will keep trying to reproduce this problem. However, if possible to create a small example with the bare minimum to reproduce it, it would help to be able to check it with detail.

So far I've not been successful in getting the same error as you both are experiencing. 

I'll let you know if I have different results in these next couple of days.

Best Regards,

Sabina

0 Kudos

1,794 Views
Sabina_Bruce
NXP Employee
NXP Employee

Hello Julian,

My name is Sabina and I'll be glad to help you find out where the root issue is. Firstly, from my understanding the above is all of your IRQ handler is this correct? If so, I'd recommend to reconsider the design of your interrupt handler. The reason being that the best practice for handlers is to have them as short as possible, generally to clear flags and maybe a small function to be done. The rest should be created in a different function or in your main while loop. This will improve the application and avoid many bugs that have to do with interruptions. 

To better understand what you would like to achieve, could you please answer the following:

1. Have you been able to successfully run a UART example from the SDK?

2. How and when are you initializing your interrupt?

3. Could you please confirm the version of the IDE and SDK that you are using. 

If possible could you attach the primary file that you are working with, so that I may try to run from my end. 

Best Regards,

Sabina

0 Kudos

1,794 Views
jheni
Contributor I

Hey Sabrina thx for your answer,

yes I'm currently using the UART example ffrom the SDK Manual

https://www.nxp.com/docs/en/reference-manual/KSDK20APIRM.pdf  Ch 53.2.2.2 UART Send/receive using an interrupt method

I initialise the UART like this:

 uart_config_t uart_config = {0};
  /* Configure UART mode                          */
  /************************************************/
  UART_GetDefaultConfig(&uart_config);
  uart_config.baudRate_Bps = pUartSettings->dwSpeed;

 UART_Init(pUartSettings->UartControl.pUartBase, &uart_config, CLOCK_GetFreq(pUartSettings->UartControl.UartClock));

 UART_TransferCreateHandle(pUartSettings->UartControl.pUartBase, &pUartSettings->UartHandle, pUartSettings->callback,
        (void*) pUartSettings);
    if (NULL != pUartSettings->rx.pbyRxCache)
    {
      UART_TransferStartRingBuffer(pUartSettings->UartControl.pUartBase, &pUartSettings->UartHandle, pUartSettings->rx.pbyRxCache,
          pUartSettings->rx.wChacheSize);
    }

Now for our write function I needed an extra functionality. I have to enable the RX to be able to read possible lincomming data before calling the read Function.

My write function looks like this

//do some checks to verify that no transmission is currently ongoing

//...

  uart_transfer_t xfer = {0};
  xfer.data = (uint8_t*) pData;
  xfer.dataSize = dwNum;

 UART_EnableRx(pUartData->UartControl.pUartBase, true);
 UART_EnableTx(pUartData->UartControl.pUartBase, true);

//send the actual data

status_t statusUart = UART_TransferSendNonBlocking(pUartData->UartControl.pUartBase, &pUartData->UartHandle, &xfer);

My read function basically does the same thing except for calling the SDKs read function

//do some checks to verify that no transmission is currently ongoing

//...

  uart_transfer_t transfer = { 0 };
  transfer.data = (uint8_t*) pData;
  transfer.dataSize = dwNum;

  UART_EnableRx(pUartData->UartControl.pUartBase, true);

 size_t nReadBytes = 0;

status_t status = UART_TransferReceiveNonBlocking(pUartData->UartControl.pUartBase, &(pUartData->UartHandle), &(transfer),
      &nReadBytes);

I'm using the SDK Callback to determine whether a communication is done

static void callback_Uart(UART_Type *base, uart_handle_t *handle, status_t status, void *userData)

{

switch (status)
  {
    case kStatus_UART_Error:

 case kStatus_UART_TxWatermarkTooLarge:
    case kStatus_UART_RxWatermarkTooLarge:
    case kStatus_UART_FlagCannotClearManually:
    case kStatus_UART_RxRingBufferOverrun:
    case kStatus_UART_RxHardwareOverrun:
    case kStatus_UART_NoiseError:
    case kStatus_UART_FramingError:
    case kStatus_UART_ParityError:

   {

     //set an RX and TX error flag to notify about the failure

     //...

      break;

   }

 default:
    {
      //default case => no error => do nothing
      break;
    }

}

 if (kStatus_UART_TxIdle == status)

  {

    //set the TX successful flag

   //....

  }

 if (kStatus_UART_RxIdle == status)

{

   //set the RX successfull flag

   //...

}

}

I' m using SDK 2.7.0 with Eclipse CDT (12-2019) in combination with Cmake and GCC 4.8 (yeah I know GCC 4.8 is pretty ancient :O)

Did this help you?

0 Kudos

1,794 Views
Sabina_Bruce
NXP Employee
NXP Employee

Thank you for clarifying your procedure. From your initial description you mention that you get stuck in an infinite loop. Just to confirm that I am understanding you correctly , you are entering the following if statement.

pastedImage_3.png

However, when count = base->RCFIFO is execute, the count at that point is zero? Is this correct?

Does this happen in the first interrupt or does it occur after several interrupts. I am attempting to reproduce this from my end I will update you as soon as possible.

Best Regards,

Sabina

0 Kudos

1,794 Views
jheni
Contributor I

Hey Sabrina,

thx for answering!

Yes I'm entering

if ((((uint32_t)kUART_RxDataRegFullFlag & status) != 0U) && ((UART_C2_RIE_MASK & base->C2) != 0U))

{

count = base->RCFIFO;

however count is 0 therefore the following while loop  is never executed.

This problem happens approx after 10 mins of UART Communication. So it's not the first Interrupt which goes crazy

My guess:

In our particular application the K64 is the Master. We send a request to the slave.

Enable the RX Periferal  by calling UART_EnableRx() before calling UART_TransferSendNonBlocking()

Try to call UART_TransferReceiveNonBlocking() 40ms after the Send has been performed.

I'm guessing that there are some occasions where RX characters are already incoming when we call UART_TransferReceiveNonBlocking()

does this help you?

Thx for your help :smileyhappy:

0 Kudos

1,794 Views
darshan_shah1
Contributor II

Hi,

I am facing the same issue right now. Are you able to find out the solution?

In your case is RTS CTS connected?

0 Kudos

1,794 Views
jheni
Contributor I

Hey,

@Sabina . Sorry it's difficult to reproduce this using an example. This problem rises in a full (already developed application). The UART communication with the particular component is only the Low Level. There is a full protocol layer above this.

@Sabina and @Darshan Nope not yet, which is pretty unfortunate.

However in our project we use 4 UARTS (1 UART+DMA and 3 "normal" UARTS).

The problem only arises in a single UART.

So at the moment I'm assuming there is some sort of hardware glitch.

Could it be that the UART RX Reg Data Full Interrupts is triggert by a rising flank (however the flank was only caused by some sort of glitch). No Start/Stop Bits where detected. Therefore there is no data in the RX FIFO.

@Sabina. If this assumption is correct what would be the proper way to handle this?

0 Kudos

1,794 Views
darshan_shah1
Contributor II

@Julian,

Thanks you for the response.

I also found the same behaviour. When data is recieving and if we call UART_TransferReceiveNonBlocking, we are getting such error. I also see many time HW Buffer OverFlow. I am also using UART RTOS example and just update the uart rtso driver with timeout (in default, code is blocking infinite).

0 Kudos

1,794 Views
Sabina_Bruce
NXP Employee
NXP Employee

Hello Julian, 

I've been trying to reproduce this but have not been successful. Is it possible for you to recreate this using to FRDMs one master and one slave so that I can reproduce it from my end and check it with detail and be able to test it myself.

I understand what you are doing, however its difficult to follow with code only. 

Please let me know if this is possible. 

Best Regards,

Sabina

0 Kudos