2009-11-12 10:22 PM
UART0 and TIMER1 interrupts issue
2011-05-17 12:57 AM
Hi Lakata,
Thank you very much for your help. I searched this forum before I posted my message. I found their issues are a little different from mine. Their program will be crashed when two interrupts are running at same time. My prorgam can run properly, but accidentally receive wrong data. I try your method and put dummy read in the beginning of ISR of UART. However, I still get wrong data sometimes. Any other suggestions? Thanks a lot! Lillian2011-05-17 12:57 AM
Hi,
I have questions regarding uart receive and timer OC interrupts. I am using STR912FAZ44H6 and keil uVision3. 1. IF I run the uart0 alone, the device can receive data correctly. 2. IF I run the timer alone, the device can get interrupt every 1 ms. 3. If I combine uart and timer together. Both work fine. However, the device receives wrong data every two or three minutes. For example, I should receive data ''ABCD'', but sometimes I will receive ''ABCCD'', or ''AABCD'', and so on. My configuration is as follows: 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 = 115200; UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None; UART_InitStructure.UART_Mode = UART_Mode_Tx_Rx; UART_InitStructure.UART_FIFO = UART_FIFO_Disable; UART_DeInit(UART0); UART_Init(UART0, &UART_InitStructure); /* Enable the UART0 */ UART_Cmd(UART0, ENABLE); UART_ITConfig(UART0, UART_IT_Receive, ENABLE); VIC_DeInit(); VIC_Config(UART0_ITLine, VIC_IRQ, 2); VIC_ITCmd(UART0_ITLine, ENABLE); /* timer set up */ TIM_DeInit(TIM1); /* TIM1 Deinitialization */ /* TIM1 Structure Initialization */ TIM_StructInit(&TIM_InitStructure); /* TIM1 Configuration in Output Compare Mode */ TIM_InitStructure.TIM_Mode = TIM_OCM_CHANNEL_1; TIM_InitStructure.TIM_OC1_Modes = TIM_TIMING; TIM_InitStructure.TIM_Clock_Source = TIM_CLK_APB; TIM_InitStructure.TIM_Clock_Edge = TIM_CLK_EDGE_FALLING; TIM_InitStructure.TIM_Prescaler = 0x64; TIM_InitStructure.TIM_Pulse_Length_1 = 0x3BB; TIM_Init (TIM1, &TIM_InitStructure); /*Enable TIM1 Output Compare1 Interrupt */ TIM_ITConfig(TIM1, TIM_IT_OC1, ENABLE); VIC_Config(TIM1_ITLine, VIC_IRQ, 3); VIC_ITCmd(TIM1_ITLine, ENABLE); TIM_CounterCmd(TIM1, TIM_START); The interrupt routines: void TIM1_IRQHandler(void) { TIM_ClearFlag(TIM1, TIM_FLAG_OC1); TIM_CounterCmd(TIM1, TIM_CLEAR); pid_count++; VIC0 -> VAR = 0xFF; VIC1 ->VAR = 0xFF; } void UART0_IRQHandler(void) { if(UART_GetITStatus(UART0, UART_IT_Receive)!= RESET) { if((UART_GetFlagStatus(UART0, UART_FLAG_RxFIFOEmpty) != SET)&&(RxCounter < RxBufferSize)) { UART_RxBuffer[RxCounter] = UART0->DR; if ( UART_RxBuffer[RxCounter] == 0x0D ) { UART_RxBuffer[RxCounter] = 0x00; //save NULL to string instead of CR FLAG.B.CR = 1; //If CR, set flag } if ( UART_RxBuffer[RxCounter] == 0x0A && FLAG.B.CR == 1 ) { UART_RxBuffer[RxCounter] = 0x00; //save NULL to string instead of LF FLAG.B.CR = 0; //If CR, set flag FLAG.B.RS232 = 1; //If CR,LF set RS-232 input string ready flag } RxCounter++; //increment the RX buffer pointer }//END OF UART_GETFLAG }//END OF UART_GETITSTATUS VIC0 ->VAR = 0xFF; VIC1 ->VAR = 0xFF; } Anyone can point out what I am wrong in my program. Greatly appreciate any inputs.2011-05-17 12:57 AM
Search this discussion group for ''interrupts'' and you'll see a lot of discussion on this.
Basically, the problem comes down to the fact that the master IRQ should only read from VIC0->ADDR. Then your TIM and UART ISRs should do the following: For TIM (which is VIC0), isr { // do something VIC0->ADDR = 0; } For UART (which is VIC1), isr { x = VIC1->ADDR; // dummy read // do something VIC1->ADDR = 0; } The problem is that if write to both VIC0 and VIC1, you can mistakenly lose an interrupt if they happen at the same time.2011-05-17 12:57 AM
Here is my IRQ Handler:
IRQHandler SUB lr,lr ,#4 SaveContext r0,r12 LDR r0, = VectorAddress LDR r0, [r0] ; Read the routine address from VIC0 Vector Address register BLX r0 ; Branch with link to the IRQ handler. RestoreContext r0,r12 Here is my timer: void BSP_TimerISR(void) { uint16_t cmp_value; cmp_value = TIM0->OC1R; // get the current compare value TIM0->SR &= ~TIM_IT_OC1; // clear timer interrupt flag cmp_value += timerTicksPerMillisecond; // Calculate a new ouput compare value TIM0->OC1R = cmp_value; // Set the output compare register jiffyStruct.u32++; VIC0->VAR = 0x00000000; // Signal the end of the interrupt } My UART interrupt: static void UART0_ISR(void) { volatile uint32_t dummy = VIC1->VAR; // required to update the priority logic UART0->ICR = UART_IT_Receive; #define RXFE 0x0010 // rx FIFO 1/2 empty flag bit #define TXFE 0x0080 // tx FIFO 1/2 empty flag bit // serial->rxInterrupts++; while (!(UART0->FR & RXFE) ) { // while not empty uint16_t b = UART0->DR; // read UART buffer if (b & 0xFF00) { // serial->rxErrorCounter++; } else { // serial->rxBytes++; } if (hwMasterMode == READING) { if (hwSerialRS485InBufferWritePtr hwSerialRS485InBuffer[hwSerialRS485InBufferWritePtr] = b; hwSerialRS485InBufferWritePtr++; } else { // overflow } } else { hwSerialRS485OutputEchoCount--; if (hwSerialRS485OutputEchoCount <=0) { HW_SerialPort0ReadMode(); UART0->CR &= ~UART_CR_LBE; // disable loop-back, so we can read again hwSerialRS485OutBufferWritePtr = hwSerialRS485OutBufferReadPtr = 0; hwMasterMode = READING; } } } if (UART0->RIS & UART_IT_Transmit ) { // Transmit interrupt // the tx buffer is guaranteed to be at least half empty, ie 8 bytes can be written, // so let's write them. #if HW_UART_BUFFER_LENGTH > 1 uint32_t i = 0; while (hwSerialRS485OutBufferReadPtr < hwSerialRS485OutBufferWritePtr && i < (HW_UART_BUFFER_LENGTH/2) ) { // transfer 1 byte to the tx buffer UART0->DR = hwSerialRS485OutBuffer[hwSerialRS485OutBufferReadPtr++]; i++; } if (UART0->FR & TXFE) { // Transmit fifo totally empty if ( hwSerialRS485OutBufferReadPtr != hwSerialRS485OutBufferWritePtr) { // uhoh i=i; } // we got to the end of the tx buffer, so now turn the RS488 bus to read mode HW_SerialPort0ReadMode(); // reset the buffer points hwSerialRS485OutBufferWritePtr = hwSerialRS485OutBufferReadPtr = 0; } #else if (hwSerialRS485OutBufferReadPtr < hwSerialRS485OutBufferWritePtr ) { // transfer 1 byte to the tx buffer UART0->DR = hwSerialRS485OutBuffer[hwSerialRS485OutBufferReadPtr++]; } #endif UART0->ICR = UART_IT_Transmit ; // clear transmit interrupt } VIC1->VAR = 0x00000000; // required to update the priority logic } Also be sure to install a default ISR static uint32_t bspVIC_ISR_Count = 0; static void BSP_VIC_ISR(void) { bspVIC_ISR_Count++; } ... VIC0->DVAR = (u32)BSP_VIC_ISR; VIC1->DVAR = (u32)BSP_VIC_ISR;2011-05-17 12:57 AM
Hi lakata,
Sorry for my late response since I am just back from vocation. Thank you very much for your source code. I compare yours with mines. The only differences are that you put clear pending bit ''UART0>ICR = UART_IT_RECEIVE'' inside of UART ISR and startup code --- IRQ handler. My IRQ handler is as follows: ; Vectored Interrupt Controller (VIC) definitions VectorAddr EQU 0xFFFFF030 ; VIC Vector Address Register VectorAddrDaisy EQU 0xFC000030 ; Daisy VIC Vector Address Register AREA IRQ, CODE, READONLY ARM PRESERVE8 ALIGN EXPORT IRQHandler IRQHandler SUB LR, LR, #4 ; Update Link Register STMFD SP!, {R0-R12, LR} ; Save Workspace & LR to Stack MRS R0, SPSR ; Copy SPSR to R0 STMFD SP!, {R0, R1} ; Save SPSR to Stack (8-byte) LDR R0, =VectorAddr LDR R0, [R0] ; Read the Routine Address LDR R1, =VectorAddrDaisy LDR R1, [R1] ; Padding between the acknowledge and re-enable of interrupts ; For more details, please refer to the following URL ; NOP NOP MSR CPSR_c, #0x1F ; Switch to SYS Mode and enable IRQ STMFD SP!, {R0, LR} ; Save Link Register (8-byte Stack) LDR LR, =IRQReturnAddress ; Read the Return Address BX R0 ; Branch to the IRQ Handler IRQReturnAddress LDMFD SP!, {R0, LR} ; Restore Link Register (8-byte Stack) MSR CPSR_c, #0xD2 ; Switch to IRQ Mode LDR R0, =VectorAddr ; Write to the VectorAddress to clear STR R0, [R0] ; the respective Interrupt LDR R1, =VectorAddrDaisy ; Write to the VectorAddressDaisy to STR R1, [R1] ; clear the respective Interrupt LDMFD SP!, {R0, R1} ; Restore SPSR to R0 MSR SPSR_cxsf, R0 ; Restore SPSR LDMFD SP!, {R0-R12, PC}^ ; Return to program END ;************************************************************************* In PC side, I program LABVIEW and send commands to my development device with STR912 continueously (Stress test). I find some puzzle things. 1. If there is no statement ''UART0>ICR = UART_IT_RECEIVE'' inside ISR of UART , my development device will receive wrong data around every one or two minutes. 2. If I put the statement ''UART0>ICR = UART_IT_RECEIVE'' in the end of UART ISR, my development device will stop receiving data after a few minutes. UART0 doesn't generate UART Receive Interrupt anymore since then. I set the UART FIFOs disabled. Anybody can help me clarify whether I need to put ''UART0>ICR = UART_IT_RECEIVE'' inside of UART ISR. Anyway I still have issues about receiving wrong data sometimes. Thank you very much for your all other suggestions. Lillian2011-05-17 12:57 AM
Hi,
Please, I'm new to this, where do I have to put the code for the irqhandler?Quote:
IRQHandler
SUB lr,lr ,#4 SaveContext r0,r12 LDR r0, = VectorAddress LDR r0, [r0] ; Read the routine address from VIC0 Vector Address register BLX r0 ; Branch with link to the IRQ handler. RestoreContext r0,r12 I have tried to put it in the startup but I think I didn't know how to do it, I found no documentation for that, please if you could help me. I have an interrupt that stops at the level of the handler, I think I need to change my startup to make it resume from the main program. thank you very much2011-05-17 12:57 AM
Hi,
I got into a similar problem with the UART interface on 912 FW 44 controller. I am trying to use the UART0 at the baud rate of 115200. When the Transmit and Recieve FIFOs are disabled, intemittently, interrupts get missed (and I wont be able to read the byte). When I lowered the baud rate to 57600, the interrupts were perfect and I was able to read all the bytes. Unfortunately, my requirement states, I need to run it at 115200:-( Also, with the FIFOs enabled it works well for both 115200 and 57600 bauds.Following are my questions. 1. Is there is a known limitation for the UARTs on this controller, when used with out the FIFOs at 115200 baud rate? 2. If there is no limitations, can you provide me any hints about anything I might be doing wrong? The only other interrupt that is enabled is the Timer0 interrupt. After reading the message from LILLIAN, I guess I will disable the TIMER and see if I can read all the data from the UART. If anyone had the similar issue and had a solution please post it to me Thank You, Anil2011-05-17 12:57 AM
Quote:
On 06-01-2009 at 15:43, Anonymous wrote: Hi lakata, .... In PC side, I program LABVIEW and send commands to my development device with STR912 continueously (Stress test). I find some puzzle things. 1. If there is no statement ''UART0>ICR = UART_IT_RECEIVE'' inside ISR of UART , my development device will receive wrong data around every one or two minutes. 2. If I put the statement ''UART0>ICR = UART_IT_RECEIVE'' in the end of UART ISR, my development device will stop receiving data after a few minutes. UART0 doesn't generate UART Receive Interrupt anymore since then. I set the UART FIFOs disabled. Anybody can help me clarify whether I need to put ''UART0>ICR = UART_IT_RECEIVE'' inside of UART ISR. Anyway I still have issues about receiving wrong data sometimes. Thank you very much for your all other suggestions. Lillian Greetings. We are having similar problems with uart: missing characters and uart interrupt stops triggering after some time. Using STR912FAW44. At other tests with minor modifications, it seems to work properly more often like 70%, but the remaining 30% still have the same problems. We have just inherited this project, and the source code is a mess, and we are new to ARM and still learning with difficulty. We are using an RTOS, but we believe it is not the cause of our problems. We are now investigating STR912 interrupt management issues that may be the cause, based on STMicro errata on the cpu revision that we are using. I have noticed your code as similar to ours, except that currently it has been modified for some reason in this line: original: MSR cpsr_c,#0x1F current: MSR cpsr_c,#0x1F | I_Bit Why I_Bit is set we have not yet received information from the original team. This will disable the interrupts. Other info: We are having problems with Uart1. Uart0 is also used but does not seem to have any problems. We have also utilized Uart2 for temporary debug output. Originally Uart1 enabled the FIFO. But someone from old team modified the settings to not use FIFO, without updating the Uart1 handler. We are fixing this now. But this would probably not cause the other problem of interrupts getting blocked. THank you for any info.2011-05-17 12:57 AM
i updated information on related topic ''Daisy chained interrupt errata fix''