AnsweredAssumed Answered

Is this UART really busy?

Question asked by Barta.Hank on Jan 12, 2015
Latest reply on Jan 15, 2015 by Montassar BEN ROMDHANE
I'm baffled by a bit of code that results in a lockup in my application (On n STM32F429I-
DISCO) related to a UART receive ISR. The code receives characters one at a time as it needs to handle variable length messages. To do that it issues a read request within the receive data ISR:
[code]HAL_StatusTypeDef st;

void HAL_UART_RxCpltCallback( UART_HandleTypeDef * huart)
{
/* Character by character interrupt callback Ugh! HAL has no concept of
  receiving variable length messages so we do that at application level.
  Here the RxXferCount==0 means the 1 character receive buffer has been exhausted
  and the receiver disablked. We need to store the character and reissue the read.
  */
     if( huart->State != HAL_UART_STATE_RESET) {
          if(!huart->RxXferCount) { // character received?
                  RxBuffer[RxBufferHead] = *RxBufferIT; 
                  RxBufferHead = (RxBufferHead + 1) % RX_BUFFER_SIZE;
                  if((st=HAL_UART_Receive_IT(&UartHandle, (uint8_t *)RxBufferIT, 1)) != HAL_OK)
                  {
                    HAL_UART_Receive_IT(huart, (uint8_t *)RxBufferIT, 1);
                    Error_Handler();
                  }
          }
     }
}[/code]
(Error_Handler(); turns on an LED and goes into an infinite loop.)

I can break on the line prior to the call to Error_Handler() and find that the return status from HAL_UART_Receive_IT(); is HAL_BUSY. If I step through a second call to HAL_UART_Receive_IT(), all works well. If I program a loop to repeat the call to HAL_UART_Receive_IT() until it no longer returns HAL_BUSY it can repeat up to 100,000 times without ever returning a good status. 

Within HAL_UART_Receive_IT() I set a breakpoint on the line where it returns HAL_BUSY and execution never stops at the breakpoint. 

Woaking back up the call stack, HAL_UART_RxCpltCallback(huart); mis called from within this bit of code (in UART_Receive_IT(UART_HandleTypeDef *huart) in stm32f4xx_hal_uart.c):

[code]    if(--huart->RxXferCount == 0)
    {
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);


      /* Check if a transmit process is ongoing or not */
      if(huart->State == HAL_UART_STATE_BUSY_TX_RX) 
      {
        huart->State = HAL_UART_STATE_BUSY_TX;
      }
      else
      {
        /* Disable the UART Parity Error Interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_PE);


        /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
        __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);


        huart->State = HAL_UART_STATE_READY;
      }
      HAL_UART_RxCpltCallback(huart);


      return HAL_OK;
    }[/code]

It seems that the state (huart->State) should either be HAL_UART_STATE_BUSY_TX or HAL_UART_STATE_READY, neither of which should cause this path to be taken in the code.

All I can think of is that some memory access is being optimized away (Optimization within IAR EWARM set to low) but I cannot see where that would be happening.

The definition for the UART handle is:

UART_HandleTypeDef UartHandle;

and if I try to add the volatile keyword to it, the compiler spits out:
[code]Error[Pe147]: declaration is incompatible with "struct <unnamed> volatile UartHandle" (declared &#1;<SRCREF line=44&#1;>at line 44&#1;</SRCREF&#1;>) C:\STM32Cube_FW_F4_V1.3.0\Projects\STM32F429I-Discovery\Applications\STemWin\WiFi with STemWin_HelloWorld\Src\main.c 44 
[/code]
whicl leads me to believe it is already declared volatile through some magic I do not understand. (The typedef for UART_HandleTypeDef does not mention volatile) And since the handle is passed though the ISR chain as a pointer, I do not see how the volatile keyword would be honored unless the library code included it with the signature for the ISR related procedures.

I'm at a loss as to what to try to fix this since I cannot figure out what is causing it in the first place. Many thanks for suggestions on where to look!

Outcomes