UART Circular buffer using DMA and IDLE line detection
MUST READ before USING
I no longer support this method. I can’t help you with any errors or any doubts.
I ported this code written here to use it with HAL and CubeMx, So all credits go to the developer of stm32f4-discovery.net,Tilen MAJERLE.
We all face the problem in UART while receiving unknown data size and If you are using HAL with CubeMx, there is no workaround for this. One might use DMA with a huge buffer size, but this will slow down the receiving process. Fortunately, the UART of STM32 have IDLE line detection interrupt which we are going to take advantage of. So today in this tutorial I will show you how to receive UART data using DMA and IDLE line detection.
What exactly is IDLE line Detection and why should we use it
Imagine that we are receiving unknown data and we don’t know the exact length of it. We can set DMA to receive particular number of bytes but than we miss the remaining data. Actually, they will be in buffer but we won’t be notified that DMA has data in memory. We have to wait until another packet with data bytes arrives to first flush old data together with new data. This can lead to timeouts in some cases.
UART have a feature called IDLE line detection and we are going to use this to sole the problem mentioned above. Idle line is detected on RX line when there is no received byte for more than 1 byte time length. We will force DMA to call transfer complete interrupt when we disable DMA stream manually, thus disabling enable bit in stream control register. In this case DMA will make an interrupt if they are enabled and we can read number of bytes we need to still receive by reading NDTR register in DMA stream. From here, we can calculate how many elements we already received.
I know it sounds complicated, So I am not going to walk you through the details here. I will show you how to implement it directly.
Setting Up the IDE
Okay it’s time to fire up your CubeMx and choose the USART2 (it’s best if you choose USART2. Code is little messed up). In the USART setting, enable the UART interrupt and setup the DMA as shown below
Okay That’s it for CubeMx. Now open the project and do the following things
- Copy DMA_CIRCULAR.c in src folder
- Copy DMA_CIRCULAR.h in inc folder
Now Right click the Application/User and select ADD existing file to the group and add DMA_CIRCULAR.c
In the main.c file do the following
Define the size of the buffers
In the main function, enable the Idle Line interrupt and DMA Tx complete interrupt. Also Disable UART Half Tx interrupt and finally start the DMA Receive
In DMA_CIRCULAR.c, change the following according to your setup
Open stm32f4xx_it.c and change the default interrupt handlers as shown in the picture below
This is it guys. Now you can start transmitting the data and see the result in the debugger window.