EmbDev.net

Forum: ARM programming with GCC/GNU tools STR9: Timer0 interacts with UART Interrupt


von Dan M. (gorlash)


Rate this post
useful
not useful
We have a project which uses STR912, and we are building with Yagarto 
package.  We've been running now with UART0 and UART1 in use, and timer 
running on RTC, which is lower priority than the UART interrupts.  This 
has all been running fine.

Now, we want to convert to using Timer0, so we can get rid of the 
separate RTC crystal.  However, we are finding that, if the timer0 is 
running, we begin getting invalid UART interrupts; we read
UartInt = UART1->MIS;
to see what event occurred, but UartInt is 0 !!  I've been calling these 
"unsignalled interrupts"; they occurred once every few seconds when 
Timer0 was 100 usec.  We rolled it back to 1msec and now these 
unsignalled ints occur about once per minute.

My Timer0 IRQ is:
/********************************************************/
void TIM0_IRQHandler(void)
{  //  all variables here are u32 (unsigned long)
   jiffies++ ; //  for now, just use 32-bit counter
   if (++tm_cycling_msec == 100) {
      tm_cycling_msec = 0 ;
      req_timer_100msec_service++ ;
   }
   //Clear the TIM_TO flag for the next interrupt
   TIM_ClearFlag(TIM0, TIM_FLAG_TO);
}
/********************************************************/
So I don't think I'm spending too much time in the handler.
When I comment out the timer0 interrupt, the unsignalled UART interrupts 
completely disappear, so clearly timer0 is causing this, but I have no 
idea why??

My timer0 startup code is:
//********************************************************************** 
***
static void setup_timer0(void)
{
   // return ;
   TIM_InitTypeDef TIM_InitStructure;
   TIM_StructInit(&TIM_InitStructure);
   TIM_InitStructure.TIM_Mode = TIM_PWM;
   TIM_InitStructure.TIM_Clock_Source = TIM_CLK_APB;
   TIM_InitStructure.TIM_Prescaler = 16;
   TIM_InitStructure.TIM_Pulse_Level_1 = TIM_HIGH;
   TIM_InitStructure.TIM_Period_Level = TIM_LOW;
   TIM_InitStructure.TIM_Pulse_Length_1 = 0xFF;
   TIM_InitStructure.TIM_Full_Period = 1411; //  1000usec period
   TIM_DeInit(TIM0);
   TIM_Init (TIM0, &TIM_InitStructure);
   TIM_ITConfig(TIM0, TIM_IT_TO, ENABLE); // Enable the Timer Overflow 
interrupt
   TIM_CounterCmd(TIM0, TIM_START); // Start the Timer0 counter

   // VIC configuration
   VIC_Config(TIM0_ITLine, VIC_IRQ, 4);
   VIC_ITCmd(TIM0_ITLine, ENABLE);
}

Can anyone give me any insights into this issue?

von (prx) A. K. (prx)


Rate this post
useful
not useful
The timer code itself won't likely affect the UART, though the timing 
could. However having only the timer code shown makes it hard to guess 
what's going on with the UART.

A UART with its FIFO and timeout conditions could have the possibility 
to generate spurious interrupts. Interrupts that go away without 
handling. This is well known and documented in case of the PC-alike UART 
used in the LPC2000 series. A receive timout interrupt might appear, 
then disappear again when the next character is received. If the 
interrupt service is delayed somewhat, it could happen that the service 
routine ends up seeing no reason for an interrupt.

Depending on the exact timing conditions, those interrupts might also 
end up as nonvectored when the VIC does no longer have an interrupt 
signal to derive a vector from. See AN2593 from ST for this behaviour.

von Dan M. (gorlash)


Rate this post
useful
not useful
Okay, I included the UART handler below (one of the two UART handlers in 
our app, the other is identical except for index).

One thing I note is that, if timer0 is not running, we don't get any RX 
timeout errors, nor any others either.  So if we are getting errors 
once the timer0 is enabled, it still seems as if the timer itself is 
involved in the UART errors??  However, I understand your comments to 
the effect that the small delays from the timer might be uncovering 
marginal timing issues in the UART handler which were not previously 
visible.  I'll look into these possibilities further.


/*********************************************************************** 
*
* Function Name  : UART1_IRQHandler
* Description    : This function handles the UART1 interrupt request
************************************************************************ 
*/
void UART1_IRQHandler(void)
{
  u32  UartInt, LineStatus;
  bool bOverRunErrorOccured = FALSE;
  u8 u8Var = 0;  // space for a character fetched from RX side of UART
  u32 IntrState = disable_IRQ();  //  removing this did nothing
  UartInt = UART1->MIS;

  if (UartInt == 0)
    uart_errors[PORT_1].unsignalled_ints++ ;

  if (UartInt & (UART_IT_ReceiveTimeOut | UART_IT_Receive | 
UART_IT_OverrunError)) {
    if (UartInt & (UART_IT_OverrunError)) {
       uart_errors[PORT_1].overrun_errors++ ;
    }

    if (UartInt & (UART_IT_ReceiveTimeOut)) {
       uart_errors[PORT_1].rxtimeout_errors++ ;
    }

    // An attempt to speed up the serial port rx driver code...
    rx_event_timer[PORT_1] = 0;

    // Somehow, the rx serial port buffer has been corrupted...
    if (rx_free[PORT_1] == BUF_LEN && rx_head[PORT_1] != 
rx_tail[PORT_1]) {
       uart_errors[PORT_1].rx_resets++ ;
       resetRxBuf(PORT_1);
    }

    // Read the line state of the UART
    LineStatus = UART1->RSECR;
    if (LineStatus & 0x1000) {
      // Overrun Error
      bOverRunErrorOccured = TRUE;
      errno = 0;
    }

    u8Var = UART1->DR;  // Fetch received character here
    UART_ClearITPendingBit(UART1,UART_IT_ReceiveTimeOut | 
UART_IT_Receive | UART_IT_OverrunError);

    if (rx_free[PORT_1])
    {
       rx_ring[PORT_1][rx_head[PORT_1]++] = u8Var;
       rx_head[PORT_1] &= BUF_LEN - 1;
       rx_free[PORT_1]--;
       SET_BITS_LOW( WRREG0_VALUE, LED1 & 0xF0);
       outp(WRREG0,  WRREG0_VALUE);
    }
    else                           // receive buffer for port is full
    {
       rx_buf_overflow[PORT_1] = TRUE;
       uart_errors[PORT_1].overflow_errors++ ;
    }
  } else
  if (UartInt & (UART_IT_FrameError)) {
     UART_ClearITPendingBit(UART1, UART_IT_FrameError);
     uart_errors[PORT_1].framing_errors++ ;
  }

  if (UartInt & UART_IT_Transmit) {
     UART_ClearITPendingBit(UART1, UART_IT_Transmit);
     tx_a_byte(PORT_1);
  }

  restore_IRQ(IntrState);
} //lint !e550  // End of UART1_IRQHandler()

von (prx) A. K. (prx)


Rate this post
useful
not useful
It could be interesting to also count the occurrences of the other 
spurious interrupts I mentioned, the ones ending in the nonvectored 
interrupt handler(s) of the VICs.

Note that I do not consider this behaviour an error. It is the expected 
behaviour of a FIFO based UART. Simply ignore interrupts without 
apparent reason, as well as the nonvectored spurious interrupts (which 
however should have a handler acknowledging them, as described in the 
AN).

von (prx) A. K. (prx)


Rate this post
useful
not useful
If disappearing receive timeout interrupts are the (sole) reason for the 
observed behaviour, the receive FIFO cannot be empty when such an 
interrupt is observed. However there should be no transmitter traffic 
while testing, to make sure the transmitter does not add up its own 
spurious interrupts.

von Dan M. (gorlash)


Rate this post
useful
not useful
BTW, one thing I left out is our UART init code!  That's relevant, 
because we aren't using the FIFOs:

void InitializeUART(byte portNum, unsigned int uiBaudRate)
{
  UART_InitStructure.UART_WordLength           = UART_WordLength_8D;
  UART_InitStructure.UART_StopBits             = UART_StopBits_1;
  UART_InitStructure.UART_Parity               = UART_Parity_No;
  UART_InitStructure.UART_BaudRate             = uiBaudRate;
  UART_InitStructure.UART_HardwareFlowControl  = 
UART_HardwareFlowControl_None;
  UART_InitStructure.UART_Mode                 = UART_Mode_Tx_Rx;
  UART_InitStructure.UART_FIFO                 = UART_FIFO_Disable;

  UART_DeInit((portNum==PORT_0) ? UART0 : UART1);
  UART_Init(  (portNum==PORT_0) ? UART0 : UART1, &UART_InitStructure);
  UART_Cmd(   (portNum==PORT_0) ? UART0 : UART1, ENABLE);

  // VIC configuration
  VIC_Config( (portNum==PORT_0) ? UART0_ITLine : UART1_ITLine, VIC_IRQ, 
(portNum==PORT_0) ? 0 : 1);
  VIC_ITCmd(  (portNum==PORT_0) ? UART0_ITLine : UART1_ITLine, ENABLE);
  ENABLE_UART_IT(portNum);
} // End of InitializeUART()

Is there anything in this that might be related to the unsignalled 
interrupts?

As additional info, I found in an overnight run of the software:
Port1: FRAME=0, OVERRUN=1, RXTMOUT=18, UNSIGNALLED=2762, OVFL=0, RST=0

So we do get other events besides just the unsignalled ints, though 
not nearly as many.  I'll put nonvectored counter as you recommended, 
and see what I see.

von (prx) A. K. (prx)


Rate this post
useful
not useful
That's beyond me, because I don't understand why a UART with a disabled 
FIFO still generates receive timeout interrupts. It does not make sense, 
unless maybe the hardware checks are still running even with the FIFO 
disabled, to be silently discarded by the programmer.

You may have to find someone having more knowledge of the inner workings 
of this particular UART. The ST forums could be a better place.

Do you get any data loss? If not, it might be easiest so simply ignore 
it.

von (prx) A. K. (prx)


Rate this post
useful
not useful
BTW: ST seems to have used the ARM primecell PL011 as UART, so any 
information available at the ARM site could also be helpful. The docs 
are public.

von (prx) A. K. (prx)


Rate this post
useful
not useful
As I said, it's probably best to ignore the case of MIS being 0. At 
least that's what Linux does in the amba-pl011 driver.

von Dan M. (gorlash)


Rate this post
useful
not useful
Okay, thanks for all the feedbacks, A.K. !!

BTW, it's probably not useful data at this point, but I've confirmed 
that I'm not getting any unvectored interrupts...

I'll do some research PL011 device.

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.