Skip to main content
MLin.4
Associate
October 14, 2021
Solved

DMA Complete interrupt and USART Idel interrupt on STM32F103 device

  • October 14, 2021
  • 2 replies
  • 3082 views

Hi All,

I want to use DMA to receive unknown length data. So I config USART_IT_IDLE and DMA_IT_TC and set DMA_BufferSize = 30 bytes. When the length of received data is less than 30 bytes, It works correctly and enters the USART1_IRQHandler(void) function. But the length of data is equal to 30 bytes, it enters the DMA1_Channel5_IRQHandler(void) function first then enters the USART1_IRQHandler(void) function again. Why does the length of data be equal to BufferSize cause Idle interruption?

void RCC_Configuration(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1 ,ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
}
 
void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
 
	GPIO_DeInit(GPIOA);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;								// TX
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;								// RX
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}
 
void USART_Configuration(void)
{
	USART_InitTypeDef USART_InitStructure;
	
	USART_DeInit(USART1);
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART1, &USART_InitStructure);
	USART_Cmd(USART1,ENABLE);
	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
}
 
void DMA_Configuration(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	
	DMA_DeInit(DMA1_Channel4);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = 256;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel4, &DMA_InitStructure);
	DMA_Cmd(DMA1_Channel4, ENABLE);
	DMA_ITConfig(DMA1_Channel4,DMA_IT_TC | DMA_IT_TE,ENABLE);
	
	DMA_DeInit(DMA1_Channel5);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize = 30;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel5, &DMA_InitStructure);
	DMA_Cmd(DMA1_Channel5, ENABLE);
	DMA_ITConfig(DMA1_Channel5,DMA_IT_TC | DMA_IT_TE,ENABLE);
}
 
void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
 
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}
void USART1_IRQHandler(void)
{
	uint8_t clear;
	if(USART_GetITStatus(USART1,USART_IT_IDLE)!= RESET)			// for USART_IT_IDLE
	{
		clear = USART1->SR;									 // clear IT_IDLE
		clear = USART1->DR;
		data_len = 30 - DMA_GetCurrDataCounter(DMA1_Channel5);
		DMA_Cmd(DMA1_Channel5,DISABLE);							
		DMA_SetCurrDataCounter(DMA1_Channel5,30);
		DMA_Cmd(DMA1_Channel5,ENABLE);
	}
}
 
void DMA1_Channel4_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA1_FLAG_TC4) != RESET)					// for DMA_IT_TC
	{
		DMA_ClearITPendingBit(DMA1_IT_TC4);
	}
}
 
void DMA1_Channel5_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA1_IT_TC5) != RESET)					// for DMA_IT_TC
	{
		DMA_ClearITPendingBit(DMA1_IT_TC5);
		DMA_Cmd(DMA1_Channel5,DISABLE);							
		DMA_SetCurrDataCounter(DMA1_Channel5,30);
		DMA_Cmd(DMA1_Channel5,ENABLE);
	}
}

This topic has been closed for replies.
Best answer by TDK

You can disable the idle interrupt flag at transmission complete if you don't want it to generate an interrupt later on.

USARTx->CR1 &= ~USART_CR1_IDLEIE;

2 replies

Tilen MAJERLE
ST Employee
October 14, 2021
TDK
Super User
October 14, 2021

> But the length of data is equal to 30 bytes, it enters the DMA1_Channel5_IRQHandler(void) function first then enters the USART1_IRQHandler(void) function again. Why does the length of data be equal to BufferSize cause Idle interruption?

The 30 bytes complete and the DMA TC interrupt fires, then at some later point the line becomes idle and the IDLE interrupt fires. What's unexpected about this?

"If you feel a post has answered your question, please click ""Accept as Solution""."
MLin.4
MLin.4Author
Associate
October 15, 2021

I realize it becomes an idle and idle interrupt generator after the transmission is complete. How could I avoid idle interruptions to clear some register flag at TC point?

TDK
TDKBest answer
Super User
October 15, 2021

You can disable the idle interrupt flag at transmission complete if you don't want it to generate an interrupt later on.

USARTx->CR1 &= ~USART_CR1_IDLEIE;

"If you feel a post has answered your question, please click ""Accept as Solution""."