1

I have some (mostly CubeMX-generated) code:

volatile uint8_t buf[4];

int main(void)
{
    ...
    HAL_UART_Receive_IT(&huart3, buf, sizeof(buf));
    while (1)
    {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART3) {
        HAL_UART_Transmit(&huart3, buf, sizeof(buf), 0xFFFF);
        HAL_UART_Receive_IT(&huart3, buf, sizeof(buf));
    }
}

This successfully echos everything which is received on USART3. (This code is just a throw-away example to learn about the serial port.)

I am concerned about the time between HAL_UART_RxCpltCallback() being called and HAL_UART_Receive_IT() setting up the next receive.

Is there any feature of the STM32F103 which guarantees that data won't be lost in this interval? I haven't found any evidence of more than a two byte receive buffer on the USART.

I am particularly concerned that some higher-priority USB-device activity might delay the calling of HAL_UART_RxCpltCallback(), and so one or more characters might be lost.

fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • 1
    If more data is received on the UART before the current contents of the UART register have been read, then the overrun error (ORE) bit will be set. I am not familiar with the HAL interface for the UART, but the LL (Low-Level) interface offers methods for reading this bit. – David Collins Jan 13 '20 at 16:57
  • 1
    Generally speaking ... Using the `LL_USART_xxx` routines offer more flexibility than their `HAL_UART_xxx` counterparts. IIRC when using the HAL routines for interrupt-based UART reception, the number of incoming characters needs to be known in advance (which makes it non-viable to use the HAL UART driver in many cases.) – David Collins Jan 13 '20 at 17:04
  • Thanks both, I'll have a look at the `LL_USART` functions. – fadedbee Jan 13 '20 at 17:07

1 Answers1

2

Quick answer:

HAL_UART_Transmit is a blocking function, so, until it completes HAL_UART_Receive_IT is not called and the uart will surely go overflow. If you are worried of any other interrupt can preemt your execution, use dma or disable the troublesome interrupts while you issue the command. You could also rise UART interrupt priority but....

Hints:

....you should not call HAL_UART_Transmit and HAL_UART_Receive_IT within HAL_UART_RxCpltCallback as here you are in ISR mode. This cause some side issues on certain versions of the HAL framework. Better to set a flag and check for it from the main code.

Also you should really avoid the use of volatile, better if you use a compiler barrier like gcc __asm volatile("" ::: "memory")

Damiano
  • 698
  • 7
  • 19
  • I was intending `volatile` to be an indication to the compiler that the values in `buf` might change independently from the currently suspended code, when an interrupt is being handled. Do I need to use barriers around all accesses to `buf` instead? – fadedbee Jan 13 '20 at 14:38
  • 1
    You can just put one before doing your parsing of buf in the main loop. – Damiano Jan 13 '20 at 15:57
  • I've just noticed your also doing trasmission and receive on the same buffer, is this intended? What do you want to achieve with this HAL_UART_Transmit ? – Damiano Jan 13 '20 at 16:02
  • Yes, that was deliberate - it is an echo program, to test the serial port. – fadedbee Jan 13 '20 at 17:06
  • 1
    Then short/bad way is do a receive/transmit of a character at a time. If you want a better implementation, you should use the receive callback to feed a circular buffer and the main loop to keep checking for new data in it and program a new transmit when data is available. Using volatile/barrier before accessing head/tail pointer should keep any unwanted optimization away. – Damiano Jan 13 '20 at 20:02