Analysis of STM32 serial port interrupt stuck main loop problem

In a project, using STM32 as the main control, the main loop may be stuck after the program runs for a period of time.

 

The problem analysis is as follows:

1. The program USART2 keeps receiving and processing serial data, with a baud rate of 115200;

2. The main loop is stuck;

3. The USART1 interrupt and TIM2 interrupt response functions are running normally; (USART1 and TIM2 interrupt priority is higher than USART2)

4. After the phenomenon occurs, unplug the receiving data cable of USART2, and the phenomenon cannot return to normal;

5. After the phenomenon occurs, unplug and then insert the receiving data cable of USART2, the phenomenon cannot return to normal;

6. There is no HardFault phenomenon;

 

Based on the above 4 points, the possible reasons are as follows:

1. The USART2 receive interrupt flag is not cleared;

2. The stack data overflows, causing the program to be abnormal;

        3. The USART2 interrupt re-entrance causes an exception;

4. The USART2 interrupt function is abnormally responded;

        5. USART2 interrupts ERR;

 

Analyze the possible reasons for the above one by one:

1. The problem of clear interrupt reception flag:

(1) The USART2 receive interrupt response function is as follows:

 

[cpp]  view plain copy  
 
  1. void USART2_Istr(void)  
  2. {    
  3.     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  4.     {     
  5.         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  6.         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  7.         Data = USART_ReceiveData(USART2);  
  8.         //Process Data  
  9.     }  
  10. }  

 

 

(2) After the phenomenon occurs, the following information is obtained through Usart1 interrupt:

a. USART_GetITStatus(USART2,  USART_IT_RXNE)  == RESET

b. USART_GetFlagStatus(USART2,  USART_FLAG_RXNE)  == RESET

c. It cannot return to normal after executing USART_ClearFlag(USART2, USART_FLAG_RXNE) and USART_ClearITPendingBit(USART2, USART_IT_RXNE);

 Conclusion: Nothing to do with the USART2 RXNE interrupt flag.

 

2. The stack data overflows, causing the program to be abnormal;

(1) Using twice the stack space, the problem exists and the probability will not be reduced;

(2) Using 0.5 times the stack space, the problem exists, and the probability will not increase;

(3) Using 0.25 times the stack space, the program runs into HardFault;

Conclusion: nothing to do with the stack.

 

3. The USART2 interrupt re-entrance causes an exception;

(1) Use the flag method to confirm that the interrupt response function is not reentrant when a problem occurs;

Conclusion: Interrupt response functions are not reentrant.

 

4. The USART2 interrupt function is abnormally responded;

(1) The USART2 interrupt function can be called normally, but it keeps entering the interrupt response function and the main loop is stuck;

(2) Check the program Map and find no function with the same address as the interrupt response function;

(3) Check the interrupt vector table and find no exception;

Conclusion: The interrupt function is not called abnormally;

 

5. USART2 interrupts ERR;

(1) Turn off the USART2 interrupt, and the main loop returns to normal;

(2) Start USART2 interrupt, the main loop is stuck;

(3) Get DR=0x0000;

(4)USART_GetITStatus取到:RXNE=0,PE=0,TXE=0,TC=0,IDLE=0,LBD=0,CTS=0,ERR=0,ORE=0,NE=0,FE=0;

(5) Clearing CTS, LBD, TXE, TC, RXNE, IDLE, ORE, NE, FE, PE through USART_ClearITPendingBit cannot return to normal;

(6) Via USART_GetFlagStatus:

  a. The first time: CTS=0, LBD=0, TXE=1, TC=1, RXNE=0, IDLE=1, ORE=1, NE=0, FE=0, PE=0

b. The second time: CTS=0, LBD=0, TXE=1, TC=1, RXNE=0, IDLE=0, ORE=0, NE=0, FE=0, PE=0

c. The third time: CTS=0, LBD=0, TXE=1, TC=1, RXNE=0, IDLE=0, ORE=0, NE=0, FE=0, PE=0

(7) Clearing CTS, LBD, TXE, TC, RXNE, IDLE, ORE, NE, FE, PE through USART_ClearFlag cannot return to normal;

analyze:

(1) Why are all interrupt flags obtained through USART_GetITStatus, all of which are RESET (TC, TXE interrupts are not turned on), and will be interrupted?

(2) Why are all interrupt flags cleared through USART_ClearITPendingBit, and the interrupt is still entered?

(3) Why does the USART2 still enter the stuck state after turning off the USART2 interrupt and starting it again?

(4) Why are the first and second readings different through USART_GetFlagStatus? And USART_ClearFlag clears all Flags, but it can't return to normal?

 

With the above questions, I checked the reference manual and realized it! as follows:

(1) Turn on RXNEIE. By default, both RXNE and ORE interrupts are turned on.

(2) RXNE must be cleared at the first time. If it is not cleared in time, an Overrun error will be generated when the next frame of data arrives!

(3) The error is caused by ORE

When an error occurs, RXNE=0 is read, and the error should be ticked in the above picture, as follows

 

(4) As the documentation states, to clear the ORE interrupt, you need to read the USART_SR and USART_DR registers in sequence!

That is to say, after USART_ClearFlag clears all Flags, the USART_DR register must be read again!

      After the test has a problem, read and read USART_SR and USART_DR in turn, and the program returns to normal!

 

(5) Then there is another question, why USART_GetITStatus cannot read the ORE interrupt flag?

Read the USART_GetITStatus function to know. Only when the EIE of CR3 is set to 1 and the ORE of SR is set to 1, the USART_GetITStatus(USART2, USART_IT_ORE) is the SET.

See EIE bit description of CR3.

 

The solution is to read the ORE through USART_GetFlagStatus when it is received through, and if it is not RESET, read the DR data and discard it.

Modify as follows:

 

[cpp]  view plain copy  
 
  1. void USART2_NewIstr(void)  
  2. {    
  3.     if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)  
  4.    {  
  5.        USART_ReceiveData(USART2);  
  6.      USART_ClearFlag(USART2, USART_FLAG_PE);  
  7.    }  
  8.       
  9.    if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)  
  10.    {  
  11.        USART_ReceiveData(USART2);  
  12.      USART_ClearFlag(USART2, USART_FLAG_ORE);  
  13.    }  
  14.       
  15.     if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)  
  16.    {  
  17.        USART_ReceiveData(USART2);  
  18.       USART_ClearFlag(USART2, USART_FLAG_FE);  
  19.    }  
  20.       
  21.     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
  22.     {     
  23.         USART_ClearFlag(USART2, USART_FLAG_RXNE);  
  24.         USART_ClearITPendingBit(USART2, USART_IT_RXNE);  
  25.         Data = USART_ReceiveData(USART2);  
  26.     }  
  27. }  

 

 

 

Summarize:

1. Look at the documentation! Check out the documentation! Or look at the documentation! (Important things to say 3 times)

2. When using the library function, pay attention to its implementation. It may be used wrongly if you are not careful.

3. Pay attention to the difference between USART_GetFlagStatus and USART_GetITStatus, as well as the interrupt response mechanism.

4. Error handling should be considered at any time.

 

Check it out, and someone else has encountered the same situation, you can refer to:

http://blog.csdn.net/love_maomao/article/details/8234039

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325027778&siteId=291194637