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?
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.
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()
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).
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.
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.
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.
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.
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.
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
Log in with Google account
No account? Register here.