I'm trying to accumulate any bytes that come into the UART peripheral at any moment into a circular buffer. I want to match proprietary protocol packets on this window of data, but it's unclear how I can use the HAL in non-blocking mode to always accept bytes. I'm used to having a slightly more generic ISR that fires on a byte received. What I find in stm32f3xx_hal_uart.c is:

  * @brief Receive an amount of data in interrupt mode.
  * @param huart UART handle.
  * @param pData pointer to data buffer.
  * @param Size amount of data to be received.
  * @retval HAL status
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

I do not know ahead of time how many bytes I want to listen for, or what to put for the Size. Packets are variable length and can be corrupted or cut short at any moment. The best idea I have so far seems to start a reception for 1 byte then call that again on each completion interrupt. It just seems like a lot of code to run for a single byte.

In my_usart1.c module:

// Start
HAL_UART_Receive_IT(&my_uart_handle, my_buf, 1);


// Implement the Rx callback
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
  // Add the new byte to a circular buffer to be processed by the protocol

  // Register another callback the next time we receive a byte
  HAL_UART_Receive_IT(&my_uart_handle, my_buf, 1);

How can I receive a stream of bytes asynchronously?

  • 1
    \$\begingroup\$ You need to research HAL_UART_Receive_DMA. You will be able to set up a circular DMA buffer of any size, and may be able to set up UART idle timeout interrupt (so that you receive bytes as long as they're inbound, then get an interrupt when no new characters are received for a while). You can also use DMA without any interrupts, and poll the DMA channel's CNDTR register to detect if bytes have been received since the last poll. \$\endgroup\$ – Garrett Mace Mar 20 at 0:57
  • \$\begingroup\$ No real need for DMA for this unless you really want to or the application is demanding enough to require that. Since the asker is used to having a byte receive interrupt, they can do the exact same here - find the UART RX interrupt and connect it to their own circular buffer. The HAL UART interrupt stuff may serve as a model of how to get things setup and the interrupt enabled, but it's not what is wanted here. \$\endgroup\$ – Chris Stratton Mar 20 at 1:37
  • 3
    \$\begingroup\$ DMA isn't scary, it's a large part of effectively using the STM32 line and only about 20% more work than configuring the UART itself using HAL. It eliminates many problems with interrupt preemption priority configuration and delays caused by other poorly-designed HAL functions, especially at higher baud. Interrupting on every byte is 8-bit uC thinking due to not having any better alternative on a limited platform. The STM32 DMA peripherals are numerous and rich; use them. \$\endgroup\$ – Garrett Mace Mar 20 at 5:18
  • \$\begingroup\$ @GarrettMace, in this application (comms with a PC), I need continuous reception. I have variable packet lengths that aren't all guaranteed to be a multiple of some DMA buffer size or complete. Packets may terminate prematurely and have a number of other problems. While DMA would be nice to reduce the interrupt and CPU load, it doesn't make sense here. \$\endgroup\$ – tarabyte Mar 21 at 17:29
  • \$\begingroup\$ There are more ways to use DMA reception besides waiting for a DMA complete interrupt. As I mentioned, many of the STM32 UARTs have a configurable timeout interrupt, which means you'll get an interrupt if there is a delay between sent packets. I also mentioned the CNDTR polling method, which I've used many times for reliable serial communications. You have a simple check to see if new bytes have arrived (and how many) and can pull bytes one at a time if desired. DMA is a way to get more reliable communication, not less. \$\endgroup\$ – Garrett Mace Mar 22 at 3:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.