cancel
Showing results for 
Search instead for 
Did you mean: 

simultaneous transmit and receive for UART not possible?

gfxfloro
Senior

Hi,

I am trying to set up UART communication on two STMF4 Boards, which has to handle simultaneous reception while also sending. The transmission looks something like this:

for (uint16_t i = 0; i < size; i++)
	{
		HAL_UART_Transmit(&huart3, (uint8_t*)packet + i, 1, HAL_MAX_DELAY);
		if (RX_NOT_READY)
		{
			HAL_UART_Receive_IT(&huart_xcp, rx.w_ptr, 1);
		}

with this in receive:

if (HAL_UART_Receive_IT(&huart3, write_ptr, 1) != HAL_OK) 
{
	rxbuf.state = RX_NOT_READY;
}

Seems to me like I can't block for any less time while transmitting. Nonetheless I am losing one or two of maybe 7 bytes, when I am transmitting at the same time.

My baudrate is 115200, changing it up or down doesn't have much effect.

9 REPLIES 9
Ozone
Lead II

Cube code tends to give me eye spasms.

Anyway, simultaneous transmit/receive is possible. The Rx and Tx register are separate entities.

A write to Tx triggers the transfer to the actual send hardware, as soon a no send transmission is ongoing. A TxE event will notify you when Tx is ready to receive the next character to transmit.

And you will be notified by the RxNE flag once a character was received.

Transmission is favourably done with DMA, while receive DMA can be tricky.

gfxfloro
Senior

I'm not doing any more than what you described through the HAL functions, still it seems like transmission is not quick enough. Do you think I need to write my own UART functions to get it to work?

Concerning DMA: byte count on transmit and receive are both variable. I've seen approaches using line idle to get dma working despite this, but I am not sure how feasible this is.

> Concerning DMA: byte count on transmit and receive are both variable. I've seen approaches using line idle to get dma working despite this, but I am not sure how feasible this is.

Normally, you would setup the DMA with the number of characters to send, and just trigger the transfer in a fire-and-forget fashion. This might require hardware flow control if the receiving side could be overrun. But especially with longer strings and lower baudrates, the DMA setup time is negligible compared to transmission time, and often faster then interrupt-based code.

Alternatively, you could copy the first character manually to Tx, and then enable the TxE interrupt. The handler needs to disable the interrupt again on the last character.

Reception is usually tricky, because most UART based protocols consist of asynchronous (although regular) bursts of unknown length.

This is not really compatible with a fixed-length DMA, and error detection/handling is even worse in this case.

Transmit function blocks, both rx an tx should be done with interrupts, feeding from a ring buffer.​

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

Rx is done with a ring buffer. The irq only serves to write to ring buffer and increment read and write buffers. How is doing Tx with a ring buffer better, when the Transmit function still blocks?

Piranha
Chief II

> I'm not doing any more than what you described through the HAL functions, still it seems like transmission is not quick enough.

No, you are using HAL_UART_Transmit(), which is not only a blocking call from code execution perspective, but also uses HAL's ingeniously stupid "lock" mechanism, which makes also Rx calls to fail and return HAL_BUSY.

> Do you think I need to write my own UART functions to get it to work?

Yes.

>>Do you think I need to write my own UART functions to get it to work?

The HAL U(S)ART implementation is a mess, and gets in its own way. I'm working with a much cleaner/simpler approach.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
S.Ma
Principal

For USART, HAL provides all functions per the reference manual, not based on -most common- application needs.

Actually for SPI it's ok to use HAL + DMA so that the unefficiency is less visible.

In case of USART, used LL to free my mind, and use ring buffers with callbacks.

Rather than try to share my source code, how about someone else who previously did?

https://github.com/MaJerle?tab=repositories

Pavel A.
Evangelist III