cancel
Showing results for 
Search instead for 
Did you mean: 

UART Half Duplex: How to get DMA working for both RX and TX on STM32F303CC?

AWolf.2
Associate

I am using UART1 in half duplex mode and DMA works for TX, but I cannot get it to work for RX (after calling HAL_HalfDuplex_EnableReceiver).

Here is my initialization code:

        __HAL_RCC_GPIOA_CLK_ENABLE();
	m_GPIO_InitStructTX.Pin = GPIO_PIN_9;
	m_GPIO_InitStructTX.Mode = GPIO_MODE_AF_PP;
	m_GPIO_InitStructTX.Pull = GPIO_NOPULL;
	m_GPIO_InitStructTX.Speed = GPIO_SPEED_LOW;
	m_GPIO_InitStructTX.Alternate = GPIO_AF7_USART1;
	HAL_GPIO_Init(GPIOA, &m_GPIO_InitStructTX);
	
	__HAL_RCC_USART1_FORCE_RESET();
	__HAL_RCC_USART1_RELEASE_RESET();
	__HAL_RCC_USART1_CLK_ENABLE();
	m_uartHandle = UART_HandleTypeDef();
	m_uartHandle.Instance        = USART1;
	m_uartHandle.Init.BaudRate   = 9600;
	m_uartHandle.Init.WordLength = UART_WORDLENGTH_8B;
	m_uartHandle.Init.StopBits   = UART_STOPBITS_2;   // !!! 2 Stopbits
	m_uartHandle.Init.Parity     = UART_PARITY_NONE;
	m_uartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
	m_uartHandle.Init.Mode       = UART_MODE_TX;
	huart = &m_uartHandle;
	HAL_HalfDuplex_Init(&m_uartHandle);
	HAL_HalfDuplex_EnableTransmitter(&m_uartHandle);
	HAL_NVIC_ClearPendingIRQ(USART1_IRQn);
	HAL_NVIC_DisableIRQ(USART1_IRQn);
	HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(USART1_IRQn);
 
	__HAL_RCC_DMA1_CLK_ENABLE();
	m_DMAHandleTX.Instance = DMA1_Channel4;
	m_DMAHandleTX.Init.Direction = DMA_MEMORY_TO_PERIPH;
	m_DMAHandleTX.Init.PeriphInc = DMA_PINC_DISABLE;
	m_DMAHandleTX.Init.MemInc = DMA_MINC_ENABLE;
	m_DMAHandleTX.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
	m_DMAHandleTX.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
	m_DMAHandleTX.Init.Priority = DMA_PRIORITY_MEDIUM;
	m_DMAHandleTX.Init.Mode = DMA_NORMAL;
	hdmaTX = &m_DMAHandleTX;
	__HAL_LINKDMA(&m_uartHandle, hdmatx, m_DMAHandleTX);
	__HAL_DMA_ENABLE_IT(&m_DMAHandleTX, DMA_IT_TC);
	HAL_DMA_Init(&m_DMAHandleTX);
	HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);

DMA works fine for TX, but when I switch to HAL_HalfDuplex_EnableReceiver it does not work anymore. I also tried to reconfigure the DMA and UART by calling:

m_uartHandle.Init.Mode       = UART_MODE_RX;
HAL_HalfDuplex_Init(&m_uartHandle);
HAL_DMA_DeInit(&m_DMAHandleTX);
m_DMAHandleTX.Init.Direction = DMA_PERIPH_TO_MEMORY;
__HAL_LINKDMA(&m_uartHandle, hdmarx, m_DMAHandleTX);
HAL_DMA_Init(&m_DMAHandleTX);
HAL_HalfDuplex_EnableReceiver(&m_uartHandle);
HAL_UART_Receive_DMA(&m_uartHandle, buf, length);

What am I missing?

2 REPLIES 2
S.Ma
Principal

For STM32L4R the reference manual says:

USART single-wire Half-duplex communication

Single-wire Half-duplex mode is selected by setting the HDSEL bit in the USART_CR3

register. In this mode, the following bits must be kept cleared:

• LINEN and CLKEN bits in the USART_CR2 register,

• SCEN and IREN bits in the USART_CR3 register.

The USART can be configured to follow a Single-wire Half-duplex protocol where the TX

and RX lines are internally connected. The selection between half- and Full-duplex

communication is made with a control bit HDSEL in USART_CR3.

As soon as HDSEL is written to ‘1’:

• The TX and RX lines are internally connected.

• The RX pin is no longer used.

• The TX pin is always released when no data is transmitted. Thus, it acts as a standard

I/O in idle or in reception. It means that the I/O must be configured so that TX is

configured as alternate function open-drain with an external pull-up

Usually the DMA Channel for RX and TX are different... maybe this is the missing point.

Make sure only one DMA channel is active at any time.

AWolf.2
Associate

Thanks for your quick answer.

It makes sense that a different DMA channel must be used if TX and RX are internally connected. Going to try that.

The TX pin must be configured with AlternateFunction PushPull though. OpenDrain doesn't work. But initialized with NOPULL. PULLUP does not work either (that's what I do for a full duplex UART on the TX side). Makes sense to me also since in TX mode the pin will stay UP and in RX mode it must stay open.