Lost UART interrupt on MK60DN512xxx10

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

Lost UART interrupt on MK60DN512xxx10

4,262 Views
om
Contributor III

Hi

We have a running target that connected to PC with UART.

Sometimes, the interrupt from the UART stops and the connection breaks.

When I read the data register, the interrupt start again and the connection return to be connected.

What can be the reason ?

(I read the DATA register also in order to clear overrun errors and clear other flags in the status register)

16 Replies

3,187 Views
mjbcswitzerland
Specialist V

Hi

Whenever there is a receive character waiting to be read and the interrupts are enabled there should be a pending interrupt.

Therefore this behaviour suggests that maybe an interrupt mask has been disabled for it to stop working - but this woudl mean that the interrupt is re-enabled when the character is read (or reading the character recovers from a different problem).

As reference, I have used all 6 UARTs in the K60 and the UARTs in many other K and KL devices intensively (in interrupt and DMA modes) without experiencing difficulties.

It may help if you show your interrupt handling - is it based on Freescale examples?

Regards

Mark

http://www.utasker.com/kinetis.html

0 Kudos
Reply

3,186 Views
om
Contributor III

Hi Mark

The issue is that the communication can work for few hours and then stuck.

I think that it the ISR is based on the examples of IAR

void UART_Isr(UART_COM_ENUM comPort)

{

    UART_MemMapPtr offset;

    //first calculate the offset of registers (depand the COM)

    offset = UART_MemOffsetGet(comPort);   

    register UINT16 StatReg = UART_S1_REG(offset); /* Read status register (s2 too ?)*/

    if (StatReg & (UART_S1_NF_MASK | UART_S1_OR_MASK | UART_S1_FE_MASK | UART_S1_PF_MASK))

    { /* Is any error flag set? */

        (void)UART_D_REG(offset); /* Dummy read 8-bit character from receiver */

        StatReg &= (UINT16)(~(UINT16)UART_S1_RDRF_MASK); /* Clear the receive data flag to discard the errorneous data */

    if (StatReg & UART_S1_RDRF_MASK)    /* Is the receiver's interrupt flag set? */

    {

        gUartPmon[comPort].RxInter++;

        UART_RxIsr(comPort);        

    }

    if (UartSerFlag[comPort] & ENABLED_TX_INT)  /* Is the transmitter interrupt enabled? */

    {

        gUartPmon[comPort].TxIntr++;

        if (StatReg & UART_S1_TDRE_MASK)

        { /* Is the transmitter empty? */

            UART_TxIsr(comPort);

        }

    }

}

0 Kudos
Reply

3,187 Views
mjbcswitzerland
Specialist V

HI

It looks essentially OK.

How many UARTs do you have operating together? Is it possible that the handling can be affected when 2 UART interrupts occur at the same time and share the routine (one UART may have higher priority and interrupt another).

As reference, this is the one frmm the uTasker project (DMA code removed for clarity), which uses a handler for each UART interrupt source since small code is involved and it saves having to look up the UART register pointer.

It uses a while, but there shoudn't be any difference in exiting when there is still a (second) pending uinterrupt since it will immediately return to the ISR.

Regards

Mark

static __interrupt void _SCI0_Interrupt(void)

{

    unsigned char ucState;

    while ((ucState = ((UART0_C2 & UART0_S1) & (UART_S1_RDRF | UART_S1_TDRE))) != 0) { // while interrupts present

        if (ucState & UART_S1_RDRF) {

            fnSciRxByte((unsigned char)(UART0_D & ucUART_mask[0]), 0);   // receive data interrupt - read the byte (masked with character width)

        }

        if (ucState & UART_S1_TDRE) {

            fnSciTxByte(0);                                              // transmit data empty interrupt - write next byte

        }

    }

}

0 Kudos
Reply

3,187 Views
om
Contributor III

One thing I see is that you read C2 register, and I don't.

Why is that ?

Second, we have two uarts that are working simultaneously.

The one that is stuck is talking to a PC.

The second one talks to another chip.

There may be two interrupts that occur in the same time, but:

1. I disable interrupts during the ISR handling.

2. The priority of all uarts is the same.

How do I make sure that there aren't nested interrupts in my system ?

0 Kudos
Reply

3,187 Views
mjbcswitzerland
Specialist V

Hi

C2 is just used to mask the possible interrupt flags with the ones that are actually enabled. SIcne you don't use a while you won't need this.

If the UARTs have the same interrupt priority they won't interrupt each other - if you disable global interrupts during handling there will generally be no nested interrupts.

Regards

Mark

0 Kudos
Reply

3,187 Views
om
Contributor III

Thanks a lot for the answer.

Why, if use while I need to read C2 and if I don't use while I don't ?

So what can be the reason for the disconnect ?

0 Kudos
Reply

3,187 Views
mjbcswitzerland
Specialist V

Hi

In your case there is probably no difference if using if or while and whether masking with enabled interrupts or not. The reason for it in my code is that the RX and TX are individually enabled /disabled during operation (depending on application and mode) and this allows interrupt bits to be set (eg. rx interrupt flag set bit rx interrupt not pending) but not handled, and the while not to hang in a forever loop due to this.

I would consider this a detail of a specific implementation and not a clue as to a problem in a certain case.

Regards

Mark

0 Kudos
Reply

3,187 Views
om
Contributor III

It seems that the problem solved.

The ORIE bit (Overrun Error Interrupt Enable) was not configure to be enable on power up.

Still, I don't get it

Why the reading of the status register (and then the data) during the UART ISR was not enough.

3,187 Views
mjbcswitzerland
Specialist V

Hi

Maybe the handling of a receive overrun is the problem (?):

        (void)UART_D_REG(offset); /* Dummy read 8-bit character from receiver */

        StatReg &= (UINT16)(~(UINT16)UART_S1_RDRF_MASK); /* Clear the receive data flag to discard the errorneous data */

In the case of a receiver overrun the character that overran is not put to the buffer - it is discarded by the receiver. The dummy read will be of a valid character (depending on the buffer depth/FIFO there may be more than one valid character waiting). Even without the overrun interrupt enabled the interrupt routine would still see that it has happened when servicing normal receive characters (that are waiting).

What speed is the UART operating at? Why do you have overruns? These would only occur if you have a very high BAUD rate and/or other interrupts are blocking the UART receiver interrupt for "long" periods of time. With very high rates DMA operation should be considered.

Regards

Mark

0 Kudos
Reply

3,187 Views
om
Contributor III

The baud is 115200

You are right that the UART ISR was blocked for "long" periods of time.

It was solved already, by shorten some critical sections.

Still I wanted to find the root cause of the problem why the ISR doesn't happen anymore, and why a read from the data register release the communication "stuck".

Set the ORIE solved the problem, but as you said, the ISR wasn't suppose to be stuck.

(in the interrupt table, UART error is the same as UART ISR)

The dummy read is for clearing the OR bit in the status register.

The manual instruct to do so.

0 Kudos
Reply

3,187 Views
mjbcswitzerland
Specialist V

Hi

I noticed this post: K60 UART interrupt is stuck

Maybe some similarity?

I will do some testing of overruns (I don't think that I ever experienced one to look into before) to see whether there is a recommended sequence to guarantee correct recovery apart from the one that is suggested in the user's manual.

regards

Mark

0 Kudos
Reply

3,187 Views
mjbcswitzerland
Specialist V

Hi

I have experimented with the behaviour of the UART Rx overrun flag when its interrupt is not used and belive that I can now explain your initial problem.

If the overrun flag is set, it is necessary to clear it before the receiver will continue to operate normally (there is a note about this in the user's manual). In order to clear the flag it is necessary to read the status register with the flag set and then read the data register.

In your original code this is not guaranteed, which can be explained as follows:

    register UINT16 StatReg = UART_S1_REG(offset); /* Read status register (s2 too ?)*/                 <--- flag is not set here  (A)

    if (StatReg & (UART_S1_NF_MASK | UART_S1_OR_MASK | UART_S1_FE_MASK | UART_S1_PF_MASK))          <-- so is not handled here

    { /* Is any error flag set? */

        (void)UART_D_REG(offset); /* Dummy read 8-bit character from receiver */

        StatReg &= (UINT16)(~(UINT16)UART_S1_RDRF_MASK); /* Clear the receive data flag to discard the errorneous data */

    if (StatReg & UART_S1_RDRF_MASK)    /* Is the receiver's interrupt flag set? */

    {

        gUartPmon[comPort].RxInter++;

        UART_RxIsr(comPort);          <-- some where in this routine the data register is read (B)

    }

If the overrun takes place between the initial read of the status register and the point where the data register is read (between (A) and (B), the read of the data register will not reset the overrun flag (since the status register hasn't been read "with it set"). The result is that the overrun flag remains set and the receiver will not receive any further data.

This means that there is a "window" in your interrupt routine that allows this to take plöace - the longer the code is before the data register is read, the larger the window and the greater the chance of it occurring.

When you use the interrupt flag to re-enter the interrupt routine, the overflow hander corrects the situation by re-entereing teh interrupt routine - but, without an interrupt on the overrun flag, the UART will block until the sequence is performed.

There is however a simple workaround when not handling the overrun interrupt, which is as follows.

    if (StatReg & UART_S1_RDRF_MASK)    /* Is the receiver's interrupt flag set? */

    {

        gUartPmon[comPort].RxInter++;

        UART_RxIsr(comPort);

if (UART_S1_REG(offset) & UART_S1_OR_MASK) {

    (void)UART_D_REG(offset); /* Dummy read 8-bit character from receiver */

}

    }

Here the status register is checked for the overrun "after" the read has taken place. This will catch the case where the data register read didn't automatically clear it and then reset it.

In fact the first check in the routine for an overrun error is in mainly redundent (unless you want to count how often an overrung takes place or similart) because of two reasons:

1. It is not reliable since the flag may be set after it has checked (as explained above)

2. There will always be a receive character in the data register for the interrupt to enter (when not using overrun interrupt) and so either the flag is reset by the standard data handling (the character before the overrun took place and nothing else is needed) or else the post-check will catch it

Regards

Mark

0 Kudos
Reply

3,187 Views
om
Contributor III

Hi Mark

The case in the other post is the same case.

As for your explanation, it make sense.

I already tried, 3 days ago, to make the double read of the status register, at the end of the ISR routine (after point B, in your example) with "dummy" read if the OR flag was set, but the system stil lost connection, so I remove this test.

Maybe I had to re-check it again.

Thanks a lot for all your efforts.

    OM

0 Kudos
Reply

3,187 Views
om
Contributor III

BTW, I have interrupts on GPIO, from other sources, with higher priority.

Maybe such interrupt happen, before I disable interrupts in the UART ISR ?

0 Kudos
Reply

3,187 Views
mjbcswitzerland
Specialist V

Hi

Basically interrupts of different sources, and nested interrupts, should be reliable.

However it depends on the system design and application whether certain ones need to be protected against others or not, or which priorities they have relative to another.

Systems that work normally for a period of time but fail randomly often have a critical piece of code that is interrupted (pre-empted) at a time that causes something to go wrong (often the interrupt modifying data that the interrupted code was in the middle of modfying). Since these two events (or more) have to take place at certain critical times it can be that they happen only very rarely and so the system has an 'error' that is difficult to reproduce and to identify.

Since your interrupt handling essentially looks correct/normal it may be that the source of such a problem is at a different location (the result is a side-effect of some other occurrence/error (??)).

Unfortunately solving such problems can require analysis, detective work and patience but almost 100% of the time they are due to a coding error (once identified, understood and corrected it always looks so obvious).

Regards

Mark

0 Kudos
Reply

2,947 Views
rydertacongmanh
Contributor II

Hi Mark & OM,

Thank you very much! 

I follow this thread and able to resolve my issue overrunint UART in LPC11U68. In my case the root cause is because of IRQ priority of USB and IRQ priority of UART.

"Basically interrupts of different sources, and nested interrupts, should be reliable." Thanks Mark, you are right ^^.

 

Best regards,

ryder

 

 

 

0 Kudos
Reply