Working with STM32F7 and UART part 5: Full Duplex using DMA with IDLE

In the previous guide (here), we took a look how to configure the UART to transmit and receive data to/from PC using DMA. The limitation that we shall wait until the buffer is filled before we print the the received characters. In this guide, we shall use IDLE Line interrupt to receive unknown length of characters.

In this guide, we shall cover the following:

  • What is IDLE line.
  • Configure UART for IDLE interrupt.
  • Support functions.
  • Code.
  • Demo.

1. What is IDLE Line:

The use of IDLE is mostly related to synchronous communications (although you could use this concepts in asynchronous mode as well).

Because there is a continuous bitstream flowing on the line in synchronous mode, there is no way to send nothing – To be able to do that, the IDLE pattern (normally all ones) is often used. It simply means there is no data on the line.

2. Configure UART for IDLE interrupt:

In order to enable IDLE line interrupt for UART, we need to set the IDLEIE bit in CR1:

USART3->CR1|=USART_CR1_IDLEIE;

Then enable USART interrupt in NVIC:

NVIC_EnableIRQ(USART3_IRQn);

For the interrupt handler:

  • Check if the source is IDLE line.
  • If it is, set idle_detected to 1.
  • Clear the pending flag.
void USART3_IRQHandler(void)
	{
		if(USART3->ISR &USART_ISR_IDLE)
			{
				idle_detected_var=1;
				USART3->ICR=USART_ICR_IDLECF;
			}

	}

Also, within uart header, we shall declare the following enums:

typedef enum
	{
		noIDLE=0,
		IDLE=1
	}idle_enum;

3. Support functions:

The following functions are introduced:

  • idle_detected
  • flush_buffer

For idle_detected:

Check the idle_detected, if no idle is detected, return noIDLE which is 0. Else, set the variable to 0 and return IDLE which is 1.

uint8_t idle_detected()
	{
		if(idle_detected_var==noIDLE){return noIDLE;}
		else {idle_detected_var=noIDLE; return IDLE;}
	}

For flush_buffer:

  • Disable the DMA Stream.
  • Clear the buffer.
  • Relaunch the DMA.
void flush_buffer(uint8_t *buffer, uint16_t length)
	{
		/*Disable the DMA*/
		DMA1_Stream1->CR &=~(DMA_SxCR_EN);
		while((DMA1_Stream1->CR &(DMA_SxCR_EN)));
		/*Clear the buffer*/
		memset(buffer,'\0',length);
		/*Relaunch DMA*/
		launch_rx_dma(buffer,length);
	}

4. Code:

In main.c:

#include "uart.h"
char uart_data_tx[40], uart_data_rx[200];

uint8_t length;

int main(void)
	{
		uart_tx_rx_dma_init();
		launch_rx_dma(&uart_data_rx, 200);
		while(1)
			{
				if(idle_detected()==IDLE){
				length=sprintf(uart_data_tx,"Received characters are: %s\r\n",uart_data_rx);
				usart_dma_write(uart_data_tx,length);
				flush_buffer(uart_data_rx, 200);
				}
			}
	}

You may download the source code from here:

5. Demo:

Open serial terminal and set the baudrate to 115200 and type any characters you need with any length and you should get something similar to this:

Happy coding 🙂

Add Comment

Your email address will not be published. Required fields are marked *