cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407VG UART DMA Not Working Properly

Mustafa BAKIRCIOGLU
Associate II

Hello Guys;

I am trying to do Push Button Interrput UART+DMA application, but I have a problem about the UART DMA. When I configure the dma in normal mode it just make transmit once. I need to use dma every time I push the button. This is my code ;

#include "stm32f4xx.h"                  // Device header
#include "stm32f4xx_hal_conf.h"         // Keil::Device:STM32Cube Framework:Classic
#include "stm32f4xx_hal.h"              // Keil::Device:STM32Cube HAL:Common
#include "stdbool.h"
 
uint8_t btnWarn[] = "Button Push Interrupt\r\n";
UART_HandleTypeDef sUart4;
DMA_HandleTypeDef dmaHandler;
 
 
 
uint8_t counter=0;
int ret=0;
int ret2=0;
 
void SysTick_Handler(){
	HAL_IncTick();
	HAL_SYSTICK_IRQHandler();
	if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0))
		counter++;
	else
		counter=0;
}
 
void UART4_IRQHandler(void)
{
  HAL_UART_IRQHandler(&sUart4);
}
 
void DMA1_Stream4_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&dmaHandler);
}
 
void EXTI0_IRQHandler(){
	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
	if(counter >=100){
		HAL_UART_Transmit_DMA(&sUart4,btnWarn,sizeof(btnWarn));
		counter =0;
	}
	
}
 
 
int main(){
	
	HAL_Init();
	__PWR_CLK_ENABLE();
	
	__GPIOC_CLK_ENABLE();
	//PC10 PC11 UART4 TX and RX
	GPIO_InitTypeDef strIO;
	strIO.Alternate = GPIO_AF8_UART4;
	strIO.Mode = GPIO_MODE_AF_PP;
	strIO.Pin = GPIO_PIN_10 | GPIO_PIN_11;
	strIO.Pull = GPIO_NOPULL;
	strIO.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOC,&strIO);
	
	__GPIOA_CLK_ENABLE();
	GPIO_InitTypeDef buttonIT;
	buttonIT.Mode = GPIO_MODE_IT_FALLING;
	buttonIT.Pin = GPIO_PIN_0;
	buttonIT.Pull = GPIO_PULLDOWN;
	buttonIT.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA,&buttonIT);
	HAL_NVIC_EnableIRQ(EXTI0_IRQn);
	
	
	
	__HAL_RCC_DMA1_CLK_ENABLE();
	
  DMA_HandleTypeDef dmaHandler;
	dmaHandler.Instance = DMA1_Stream4;
	dmaHandler.Init.Channel = DMA_CHANNEL_4;
	dmaHandler.Init.Direction = DMA_MEMORY_TO_PERIPH;
	dmaHandler.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
	dmaHandler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
	dmaHandler.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
	dmaHandler.Init.Mode = DMA_NORMAL;
	dmaHandler.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
	dmaHandler.Init.Priority = DMA_PRIORITY_VERY_HIGH;
	dmaHandler.Init.MemInc = DMA_MINC_ENABLE;
	dmaHandler.Init.MemBurst = DMA_MBURST_SINGLE;
	dmaHandler.Init.PeriphBurst = DMA_PBURST_SINGLE;
	dmaHandler.Init.PeriphInc = DMA_PINC_DISABLE;
	__HAL_LINKDMA(&sUart4,hdmatx,dmaHandler);
	HAL_DMA_Init(&dmaHandler);
	HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
	
	__UART4_CLK_ENABLE();
	sUart4.Instance = UART4;
	sUart4.Init.BaudRate = 115200;
	sUart4.Init.Mode = UART_MODE_TX_RX;
	sUart4.Init.Parity = UART_PARITY_NONE;
	sUart4.Init.OverSampling = UART_OVERSAMPLING_16;
	sUart4.Init.WordLength = UART_WORDLENGTH_8B;
	sUart4.Init.StopBits = UART_STOPBITS_1;
	sUart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
	sUart4.hdmatx = &dmaHandler;
	HAL_UART_Init(&sUart4);
	HAL_NVIC_EnableIRQ(UART4_IRQn);
	
	while(1){
		HAL_UART_Transmit_DMA(&sUart4,btnWarn,sizeof(btnWarn));
	}
	
}

I made research on Internet and I could not find the solutions. Maybe I am missing something small, I would be very appreciated I you help me about what am I doing wrong.

Best Regards

7 REPLIES 7
Tilen MAJERLE
ST Employee

After you call DMA transmit, you have to wait for transmission to complete, before you can start a new one.

Tilen,

that's presumably the role of counter variable.

Mustfa,

What exactly are the symptoms? Isn't there any DMA error (I don't know how this demonstrates itself under Cube/HAL, normally I'd look at the relevant bits in DMAx_LISR/HISR).

Btw. you are not supposed to have both DMA and interrupts active for the UART.

JW

T J
Lead

is this where you send the Tx after you hit the button ?

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
	if(counter >=100){
		HAL_UART_Transmit_DMA(&sUart4,btnWarn,sizeof(btnWarn));
		counter =0;
	}
	

then you shouldn't be doing this:

	
	while(1){
		HAL_UART_Transmit_DMA(&sUart4,btnWarn,sizeof(btnWarn));
	}
	

Mustafa BAKIRCIOGLU
Associate II

Guys I found the problem,

To see whats going on at the DMA_HandleTypeDef struct, I add same handler in to the main function too. You can see at line 8 and line 75.

When I delete the line 75 DMA_HandleTypeDef, the issue is solved. I dont know why it act like that but I guess both are conflicting.

If you know why it is acting like that could you say the true answer for me to learn 🙂

Thank you all for your responses.

Local variable shadowing global, and pointer to it passed to functions which expect it to exist permanently... Yes C allows all this and finding it may be this tricky. Although some compiler at least issue a warning.

JW

The local variable has limited and often transient scope, not really good for things that need to be globally visible and persistent. The variable in main() has limited scope, and replaces the global.

Jamming the DMA in the while loop probably is also ill-advised, you'd do much better with some kind of semaphore or flag indicating you have DMA busy doing something, which you clear when the IRQ handler sees the DMA transfer completed.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
LMI2
Lead

What ever the correct working answer is, would you write it here on forum too, please. But isn't there UART DMA code both from CubeMX and in ...\STM32Cube\Repository\STM32Cube_FW_F4_V1.21.0\Projects\STM32F4-Discovery\Examples\UART\UART_TwoBoards_ComDMA examples.