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.