0

controller : STM32F411RE

I am using USART2 as serial port with interrupt based. I enable NVIC in stmcubemx, its generated code whenever data is transferred from terminal interrupt is coming but uart state is HAL_UART_STATE_READY. Because of that its going to receive function UART_Receive_IT function and came out. Please help solve this issue and also I need guidance how to make uart as a interrupt mode.

code :

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{   
  if(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE))
  {  
      HAL_UART_Transmit(huart, str, 7, 0xFF);
      memset(str, '\0', sizeof(str));
  }

}                                /********* IRQ code*******/ 
  void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{


  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE);  
  /* UART parity error interrupt occurred ------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_PEFLAG(huart);

    huart->ErrorCode |= HAL_UART_ERROR_PE;
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART frame error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_FEFLAG(huart);

    huart->ErrorCode |= HAL_UART_ERROR_FE;
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART noise error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_NEFLAG(huart);

    huart->ErrorCode |= HAL_UART_ERROR_NE;
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART Over-Run interrupt occurred ----------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_OREFLAG(huart);

    huart->ErrorCode |= HAL_UART_ERROR_ORE;
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
  if(tmp2 == 0x32)
    tmp2=0x32;
  /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {         
    UART_Receive_IT(huart);
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE);
  /* UART in mode Transmitter ------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {
    UART_Transmit_IT(huart);
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_TC);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC);
  /* UART in mode Transmitter end --------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {
    UART_EndTransmit_IT(huart);
  }

  if(huart->ErrorCode != HAL_UART_ERROR_NONE)
  {
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;

    HAL_UART_ErrorCallback(huart);
  }  
}                      
/************receive code *********/   
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
  uint16_t* tmp;
  uint32_t tmp1 = 0;

  tmp1 = huart->State; 
  if((tmp1 == HAL_UART_STATE_BUSY_RX) || (tmp1 == HAL_UART_STATE_BUSY_TX_RX))
  {
    if(huart->Init.WordLength == UART_WORDLENGTH_9B)
    {
      tmp = (uint16_t*) huart->pRxBuffPtr;
      if(huart->Init.Parity == UART_PARITY_NONE)
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
        huart->pRxBuffPtr += 2;
      }
      else
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
        huart->pRxBuffPtr += 1;
      }
    }
    else
    {
      if(huart->Init.Parity == UART_PARITY_NONE)
      {
        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
      }
      else
      {
        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
      }
    }

    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;
    }
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
} 
  • Show us some code, please. – Paulo Soares Aug 22 '16 at 09:50
  • In UART_Receive_IT function huart->State will always be HAL_UART_STATE_READY so it came out of loop. – chandan mishra Aug 22 '16 at 12:28
  • Have a look at [https://stackoverflow.com/questions/37297318/cannot-transmit-every-characters-through-uart](https://stackoverflow.com/questions/37297318/cannot-transmit-every-characters-through-uart), it looks like the same question. – Paulo Soares Aug 22 '16 at 15:40
  • HAL_UART_RxCpltCallback is executed on receive process, when interrupt is enable that time from HAL_UART_IRQHandler called UART_Receive_IT function. Inside UART_Receive_IT function it will check for state. Every time hurat (UART) state is HAL_UART_STATE_READY because of that it will come out of loop, and it will not call HAL_UART_RxCpltCallback. You can see on code also when condition got fail it will return directly HAL_BUSY. So interrupt base receive function is not working for UART interface. – chandan mishra Aug 23 '16 at 07:13

2 Answers2

1

I think there are a few issues in your code. The way the HAL works is to make things easier for you so that you don't need to check interrupt flags and so on. In your interrupt handler you actually check the UART_IT_RXNE bit, but this bit has already been automatically cleared when the HAL read the bytes from the USART RX register. So remove the line:

if(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE)

str seems to be an array of characters, I think you are not using the memset as it should, the right way is:

#define LEN 7
char str[LEN];
memset(str, '\0', LEN);

I understand that you want to send a string when you reach the RX interrupt handler, but I am not sure how you called the HAL_UART_Receive_IT function in the first place. The way I am using it is as follow:

volatile bool char_received = false;
volatile char rx_char;

int main(void)
{
    //All your hardware init here

    //Receive 1 character in interrupt mode
    HAL_UART_Receive_IT(&huart, &rx_char, 1);

    while(1)
    {
        if (rx_char == true)
        {
            rx_char = false;

            if (rx_char == 's')
            {
                HAL_UART_Transmit(&huart, "Hello", 5, 100);
            }

            HAL_UART_Receive_IT(&huart, &rx_char, 1);
         }
     }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    rx_char = true;
}

In the code above, I send the "Hello" string if I receive 's' in interrupt mode. Note that I do not do much in the interrupt handler, just set a flag. Also note that you need the call again HAL_UART_Receive_IT.

Guillaume Michel
  • 1,189
  • 8
  • 14
  • I have seen your code then what is meaning of interrupt base you are calling HAL_UART_Receive_IT function in while(1). I want to call from UART_Receive_IT function whenever data is in uart data register from vector table uart irq handle. – chandan mishra Aug 23 '16 at 09:17
  • `HAL_UART_Receive_IT(&huart, &rx_char, 1)` enables the UART RX interrupt (vector table) and gets ready to receive 1 character in interrupt mode. Then when 1 character is received, the HAL disables the UART RX interrupt, calls `HAL_UART_RxCpltCallback` and at this point `rx_char` contains the actual character. If you want to receive another character, you need to call again `HAL_UART_Receive_IT`. Note that in this example, I want to receive only one character. If you know that you should receive N characters, use `HAL_UART_Receive_IT(&huart, rx_buff, N)` where `rx_buff` is an array of N bytes – Guillaume Michel Aug 23 '16 at 12:16
  • Thanks for your explanation. Still I have some doubts 1. at time of receive how you decide bytes count, user cannot tell you the no. of byte only thing is till '\r' or '\n' is end point. 2. When I have already configure my uart register for uart receive interrupt base then line should give interrupt as per my knowledge. No need to enable interrupt every time, it should automatically come from vector table. – chandan mishra Aug 23 '16 at 13:00
  • 1. That's why I suggested to receive 1 character at a time. In the interrupt handler you add the received character to an array. When you receive 'r', you can then interpret your array. 2. This is actually a 2 stage interrupt. The USART peripheral global interrupt is connected to the vector table. The HAL enables it when `HAL_UART_Init` is called. Then the USART peripheral can have a few internal interrupts (RX, TX complete, errors...). When you call `HAL_UART_Receive_IT `, the HAL enables the RX interrupt and disable it when characters have been received. This is how the HAL works. – Guillaume Michel Aug 23 '16 at 13:17
  • I got your point clearly. I am thinking about if I have to read 1000 line then first it enable the interrupt throug HAL_UART_Receive_IT then it will jump to HAL_UART_RxCpltCallback and read 1 byte at a time this make wasting of CPU cycle and power.One more thing whenever data on line whether you call HAL_UART_Receive_IT or not interrupt will raised with that basis yesterday I have implemented my interrupt in new way that its able to read whatever data on line at a time in buffer. I have made changes on uart interrupt handler. Now I am performing some testing after that I will share my code. – chandan mishra Aug 24 '16 at 07:33
  • The initial question was to be able to receive characters from the USART in interrupt mode. I think I answered the question! If you want a more advanced management you should consider DMA, circular buffer and possibly timers. – Guillaume Michel Aug 25 '16 at 07:54
  • I never ask about interrupt if you read clearly I am able to receive interrupt but UART_Receive_IT function which is called from HAL_UART_IRQHandleris not able to receive character that is my problem because of uart state machine is not updated. And I know more advance management DMA but currently I am trying to get more throughput from uart without using DMA. – chandan mishra Aug 29 '16 at 11:10
0
  void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{


  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE);  
  /* UART parity error interrupt occurred ------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_PEFLAG(huart);

    huart->ErrorCode |= HAL_UART_ERROR_PE;
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART frame error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_FEFLAG(huart);

    huart->ErrorCode |= HAL_UART_ERROR_FE;
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART noise error interrupt occurred -------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_NEFLAG(huart);

    huart->ErrorCode |= HAL_UART_ERROR_NE;
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART Over-Run interrupt occurred ----------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  { 
    __HAL_UART_CLEAR_OREFLAG(huart);

    huart->ErrorCode |= HAL_UART_ERROR_ORE;
  }

  tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
  tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
  if(tmp2 == 0x32)
    tmp2=0x32;
  /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp1 != RESET) && (tmp2 != RESET))
  {         
     HAL_UART_Receive(huart, buff, 8, 0xFF); // FOR receive data on interrupt base :chandan
  }
  • This function HAL_UART_Receive(huart, buff, 8, 0xFF) will receive all data till '\r' or '\n' inside function I made changes for it. Its working fine. – chandan mishra Aug 25 '16 at 07:01