Skip to main content
yuri CH
Senior
May 9, 2018
Question

Restart HAL_UART_Receive_IT

  • May 9, 2018
  • 15 replies
  • 3379 views
Posted on May 09, 2018 at 14:37

Hi!

in my program i am using the 'HAL_UART_Receive_IT' function, it is first called when i initialize my app.

There comes a moment during the run of the program when the pointer to buffer given to the function expires and is no longer valid, this is when i want to call this function again with new parameters.

The problem is that the operation doesnt succeed and the HAL_BUSY retval is returned.

please advise on how to restart this function properly after it has already been used.

thanks alot!

    This topic has been closed for replies.

    15 replies

    Nesrine M_O
    Associate
    May 9, 2018
    Posted on May 09, 2018 at 14:50

    Hi

    yuri.cherniakov

    ,

    Please have a look to this example it may help you :

    STM32Cube_FW_L4_V1.0\Projects\STM32L476G-EVAL\Examples\I2C\I2C_TwoBoards_RestartComIT:

    This example describes how to perform a single I2C data buffer transmission/reception

    between two boards in Interrupt mode and with a restart condition.

    -Nesrine-

    yuri CH
    yuri CHAuthor
    Senior
    May 9, 2018
    Posted on May 09, 2018 at 15:18

    Hi Nesrine,

    Thanks for responding. unfortunetly this doesnt help since i'm using UART communication.

    Tesla DeLorean
    Guru
    May 9, 2018
    Posted on May 09, 2018 at 15:35

    Reflect on the library code provided, and write something better. There is no value to building a fine house on a poor foundation. I prefer a clean/elegant approach over an abstracted/obtuse one.

    With the HAL you'd likely need to transition the object's buffer state in the IRQ Handler prior to calling into the HAL layer, or lock down the interrupt/structure to reconfigure it.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    T J
    Senior III
    May 9, 2018
    Posted on May 09, 2018 at 15:53

    this seems to be the problem:

    'There comes a moment during the run of the program when the pointer to buffer given to the function expires'

    this is an architectural issue. imho

    Tesla DeLorean
    Guru
    May 9, 2018
    Posted on May 09, 2018 at 16:07

    Yeah, I don't like the use of auto/local variable for DMA or IRQ buffers.

    If the scope is finite, manage it with a timeout. As I've observed before the HAL often get's in its own way, and has a paradigm that frequently doesn't fit what people are used to, or is 95% complete.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Pavel A.
    May 10, 2018
    Posted on May 10, 2018 at 02:59

    This is likely because the HAL function checks 'busy' flag set by it's previous call.

    If the flag is set it immediately fails.

    https://github.com/pavel-a/stm32f4_libs/blob/db5c1ad80b84837d8c52efabd071e1e65811a340/STM32Cube_FW_F4/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_usart.c#L707

    .

    So you need to let the HAL function complete, or call

    https://github.com/pavel-a/stm32f4_libs/blob/db5c1ad80b84837d8c52efabd071e1e65811a340/STM32Cube_FW_F4/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_usart.c#L1193

    .

    -- pa

    Daniel Glasser
    Associate III
    May 11, 2018
    Posted on May 12, 2018 at 00:08

    You should either use a statically or dynamically allocated buffer for the UART or use an automatic (stack allocation) buffer that is declared at a scope that does not 'expire'.  Static allocation of buffers is easier to debug, though other schemes are possible.  Stack allocation is particularly hard to debug because the interrupt callback functions don't have the stack variables from the non-interrupt thread in their scope.  The buffer is still there, but there's no really good way to get the address of it using the array name for the buffer.

    In any case, I recommend not calling the 'HAL_UART_Receive_IT()' function in your initialization routine.  You can set up the interface there without calling the receive function.  Instead, make the receive call at the top of a main loop where the buffer does not go out of scope until the program exits.  You can cancel any pending IO on the way out.  Having the input pending before you are prepared to process the data then switching to a new buffer will cause any data received up to that point to be lost anyway, so it's best to wait to make the receieve call until you're ready to process the data.

    yuri CH
    yuri CHAuthor
    Senior
    May 13, 2018
    Posted on May 13, 2018 at 07:18

    Thaks everyone for your responses,

    I understand that the 'expiration' of the pointer to the buffer is an architechtural issue that has to be dealt with.

    unfortunetly, i have inhereted some code that can not be changed at this part of the project.

    I am particularly intrested in the HAL_UART_Abort function, this would help me solve the probem, i was unable to find it in the HAL functions.

    i am working on the STM32F7 , is the set of the abort commands is not yet implemented for the F7?

    Pavel A.
    May 14, 2018
    Posted on May 14, 2018 at 02:05

    i am working on the STM32F7 , is the set of the abort commands is not yet implemented for the F7?

    Have you looked? Have you downloaded the F7 libraries? 

    -- pa

    Tesla DeLorean
    Guru
    May 14, 2018
    Posted on May 14, 2018 at 02:27

    Worse case find one of the libraries where it is implemented and diff/merge the stuff you need. Or as I suggested before update the structures data pointer in the IRQ handler before you hand off to HAL

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Willem La Grange
    Associate
    May 15, 2018
    Posted on May 15, 2018 at 21:18

    OK. I have been doing this all the time and it id based on the assumption that if I do not receive a byte within 5ms of the last, then I have received the whole message. No fuss with circular buffers and get tangled with in-and-out pointers etc.

    Obviously there are some assumed code. If you want those as well, email me at willem(at)stima.co.za.

    Firstly the IRQ handler has to be modified:

    In STM32xxx_it.c:

    void USART2_IRQHandler(void)

    {

      /* USER CODE BEGIN USART2_IRQn 0 */

      uint32_t tmp1 = 0, tmp2 = 0;

      tmp1 = __HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE);

      tmp2 = __HAL_UART_GET_IT_SOURCE(&huart2, UART_IT_RXNE);

      /* UART in mode Receiver ---------------------------------------------------*/

      if((tmp1 != RESET) && (tmp2 != RESET))

      {  

               /* just my Status Engine that informs the application that reception is in progress. Struct is below */

              Usart_Message.Status.Receiving = true;

              if(Tick_IsStarted(&MessageRXTicker))

                       /* refreshing the timeout a tick driven timer. Can put your own solution here */

                      Tick_NewRepeatTime(&MessageRXTicker,5);

              else

              {

                       /* setting a tick timer for 30ms after first character received with a callback function

                                  UART_RXVD_Complete() that would be called at timeout. Can put own solution here */

                      Tick_SetParam(&MessageRXTicker, 30, 30, ONETIME, UART_RXVD_Complete);

                      Tick_Start(&MessageRXTicker);

              }

              RX_SIZE++;

       }

      /* USER CODE END USART2_IRQn 0 */

      HAL_UART_IRQHandler(&huart2);

      /* USER CODE BEGIN USART2_IRQn 1 */

      /* USER CODE END USART2_IRQn 1 */

    }

    in usart.c user section:

    void UART_RXVD_Complete(void)

    {

        if(RX_SIZE== 0)

           Usart_Message.Status.Aborting = true;

       /* This is how you stop further reception and solve you HA_BUSY problem  */

        HAL_UART_RxCpltCallback(&huart2);

    }

    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

    {

      if(huart->Instance == USART2)

      {

         Usart_Message.Status.Receiving = false;

         Usart_Message.Status.MessageWaiting = true;

         RX_Mess_Buf = (uint8_t *) &RX_TEMPBUFFER[0];

      /* copy the message into your own buffer and free up the interupt buffer to hold nect recieved message */

         strncpy((char *) &Usart_Message.RX_MESS_BUFFER[0], (char *)&RX_TEMPBUFFER[0], sizeof(Usart_Message.RX_MESS_BUFFER) -1);

      /* RXsize is a global variable declared as volatile */

         Usart_Message.RX_size = RX_SIZE;

         RX_SIZE = 0;

         HAL_UART_ReceiveAbort(&huart2);

         HAL_UART_Receive_IT(&huart2, (uint8_t *)&RX_TEMPBUFFER[0], sizeof(RX_TEMPBUFFER)-1);

      }

     

      if(huart->Instance == USART3)

      {

     // handle next Usart here

      }

     

    }

    /* for all Usarts */

    HAL_StatusTypeDef HAL_UART_ReceiveAbort(UART_HandleTypeDef *huart)

    {

        /* Process Locked */

        __HAL_LOCK(huart);

        memset((void *)&RX_TEMPBUFFER, 0, sizeof(RX_TEMPBUFFER));

        RX_SIZE = 0;

        huart->pRxBuffPtr = (uint8_t *)&RX_TEMPBUFFER[0];

     /* Care should be taken when interrupt is disabled. It must be reenabled again */

        //__HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

        huart->RxXferCount = 0;

        huart->RxXferSize = 0;

        huart->ErrorCode = HAL_UART_ERROR_NONE;

      __HAL_UNLOCK(huart);

      return HAL_OK;

    }

    In your main.c:

    typedef struct MESSAGE_OBJECT

    {

        MessageFlags Flags;

        uint8_t RX_MESS_BUFFER[256];

        uint8_t TX_MESS_BUFFER[256];

        uint8_t SMS_Text[170];

        uint16_t RX_size;

        uint16_t TX_size;

        UartState State;

        UartState LastState;

        struct COMMS_STATUS

        {

           unsigned Busy                   : 1;

           unsigned Aborting                : 1;

           unsigned MessageWaiting   : 1;

           unsigned Receiving               : 1;

           unsigned Transmitting            : 1;

           unsigned SendRequest          : 1;

           unsigned ReleaseTimeout      : 1;

           unsigned QueueWaiting          : 1;

        }Status;

    }MessageObject;

    volatile MessageObject Usart_Message;

    //mainloop:

    while (1)

    {

     ......

        if(Usart_Message.Status.MessageWaiting)

               Go_handle_Usart message();

     ......

    }