
In the previous guide (here), we saw how to configure the UART in full duplex mode with DMA. However, the application need to know the number of transfer in advanced in order to receive data. Using IDLE line, the application doesn’t need to know number of character to be received in advanced.
In this guide, we shall cover the following:
- Configure UART for IDLE interrupt.
- Code.
- Demo.
1. Configure UART for IDLE interrupt:
To add IDLE line interrupt as simple as enabling it in CR1 (Control Register 1) and enable USART2 interrupt in NVIC

C
x
/*Enable IDLE Line Interrupt */
USART2->CR1|=USART_CR1_IDLEIE;
NVIC_EnableIRQ(USART2_IRQn);
For interrupt handler:
- Stop the DMA (optional).
- Check if the source is IDLE line.
- Set the received to 1.
- Clear the pending IDLE line interrupt flag
C
void USART2_IRQHandler()
{
if(USART2->ISR & USART_ISR_IDLE)
{
stop_dma();
received=1;
USART2->ICR|=USART_ICR_IDLECF;
}
}
In while loop:
Check if the received is set to 1 and print the received data using DMA also:
C
if(received==1)
{
length=sprintf(data_tx,"Received data\" %s \"\r\n",data_rx);
uart_transmit_dma(data_tx,length);
while(inprogress==1);
inprogress=0;
received=0;
flush_buffer();
lunch_dma();
}
2. Code:
Hence, the entire code is as following:
C
volatile uint8_t received=0, inprogress=0,full=0;
char data_tx[buffer_size];
char data_rx[buffer_size];
uint16_t length;
void stop_dma();
void lunch_dma();
void flush_buffer();
static uint16_t compute_uart_bd(uint32_t PeriphClk, uint32_t BaudRate)
{
return ((PeriphClk + (BaudRate/2U))/BaudRate);
}
void uart_transmit_dma(char *message, uint16_t len)
{
if(inprogress==0)
{
/*DMA1 Channel 7 is for USART_TX*/
DMA1_Channel7->CCR &=~DMA_CCR_EN;
while((DMA1_Channel7->CCR &DMA_CCR_EN));
DMA1_Channel7->CCR|=DMA_CCR_MINC|DMA_CCR_DIR|DMA_CCR_TCIE;
NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn);
DMA1_Channel7->CPAR=(uint32_t)(&USART2->TDR);
DMA_CSELR|=(0x04<<24);
DMA1->IFCR|=DMA_IFCR_CTCIF7;
DMA1_Channel7->CMAR=(uint32_t)message;
DMA1_Channel7->CNDTR=(uint16_t)len;
DMA1_Channel7->CCR|=DMA_CCR_EN;
inprogress=1;
}
else return;
}
int main(void)
{
systick_init(2097000);
/*Enable clock access to GPIOA*/
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
GPIOA->MODER|=GPIO_MODER_MODE2_1;
GPIOA->MODER&=~GPIO_MODER_MODE2_0;
GPIOA->MODER|=GPIO_MODER_MODE3_1;
GPIOA->MODER&=~GPIO_MODER_MODE3_0;
GPIOA->AFR[0]|=(AF04<<8);
GPIOA->AFR[0]|=(AF04<<12);
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
USART2->BRR=compute_uart_bd(APB1_CLK,UART_BAUDRATE);
/*Configure transfer direction*/
USART2->CR1 = USART_CR1_TE|USART_CR1_RE;
/*Enable IDLE Line Interrupt */
USART2->CR1|=USART_CR1_IDLEIE;
NVIC_EnableIRQ(USART2_IRQn);
/*Enable DMA TX for UART*/
USART2->CR3|=USART_CR3_DMAT|USART_CR3_DMAR;
/*Enable Clock access to DMA1*/
RCC->AHBENR|=RCC_AHBENR_DMA1EN;
/*Launch DMA*/
lunch_dma();
/*Enable uart module*/
USART2->CR1 |= USART_CR1_UE;
length=sprintf(data_tx,"Hello from UART DMA\r\n");
uart_transmit_dma(data_tx,length);
while(inprogress==1);
inprogress=0;
while(1)
{
if(received==1)
{
length=sprintf(data_tx,"Received data\" %s \"\r\n",data_rx);
uart_transmit_dma(data_tx,length);
while(inprogress==1);
inprogress=0;
received=0;
flush_buffer();
lunch_dma();
}
if(full==1)
{
length=sprintf(data_tx,"full buffer data\" %s \"\r\n",data_rx);
uart_transmit_dma(data_tx,length);
while(inprogress==1);
inprogress=0;
full=0;
}
}
}
void stop_dma()
{
DMA1_Channel6->CCR&=~DMA_CCR_EN;
}
void flush_buffer()
{
memset(data_rx,'\0',buffer_size);
}
void lunch_dma()
{
/*Configure DMA1_Channel6 for USART2_RX*/
DMA1_Channel6->CCR&=~DMA_CCR_EN;
while((DMA1_Channel6->CCR &DMA_CCR_EN));
DMA1_Channel6->CCR|=DMA_CCR_MINC|DMA_CCR_CIRC|DMA_CCR_TCIE;
NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn);
DMA1_Channel6->CPAR=(uint32_t)(&USART2->RDR);
DMA_CSELR|=(0x04<<20);
DMA1_Channel6->CMAR=(uint32_t)data_rx;
DMA1_Channel6->CNDTR=buffer_size;
DMA1_Channel6->CCR|=DMA_CCR_EN;
}
void DMA1_Channel4_7_IRQHandler(void)
{
if(DMA1->ISR & DMA_ISR_TCIF7)
{
inprogress=0;
DMA1->IFCR|=DMA_IFCR_CTCIF7;
}
if(DMA1->ISR & DMA_ISR_TCIF6)
{
full=1;
DMA1->IFCR|=DMA_IFCR_CTCIF6;
}
}
void USART2_IRQHandler()
{
if(USART2->ISR & USART_ISR_IDLE)
{
stop_dma();
received=1;
USART2->ICR|=USART_ICR_IDLECF;
}
}
3. Demo:
Happy coding
Add Comment