cancel
Showing results for 
Search instead for 
Did you mean: 

DMA Complete interrupt and USART Idel interrupt on STM32F103 device

MLin.4
Associate II

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);
	}
}

1 ACCEPTED SOLUTION

Accepted Solutions

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".

View solution in original post

5 REPLIES 5
Tilen MAJERLE
ST Employee

Hi

see here example with LL drivers:

https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx

TDK
Guru

> 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
Associate II

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?

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".

Ok, this is a way without idle interrupt.

Thanks for your replies.