cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_UARTEx_ReceiveToIdle_DMA() only receives 16 bytes.

federico.massimi
Associate III

Hi, I have a problem with the HAL_UARTEx_ReceiveToIdle_DMA() function. I'm using this simple code

main.c:

#define TM_BUS_DATA_RX_BUFFER_SIZE		256
uint8_t TM_BUS_DATA_RX_BUFFER[TM_BUS_DATA_RX_BUFFER_SIZE] = {0x00};
HAL_UARTEx_ReceiveToIdle_DMA(&huart3, TM_BUS_DATA_RX_BUFFER, TM_BUS_DATA_RX_BUFFER_SIZE);
__HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
	if( huart->Instance == TM_UART_NAME ) {
		DEBUG_MSG("TM UART RX: %s [%d]\r\n", TM_BUS_DATA_RX_BUFFER, Size);
 
		HAL_UARTEx_ReceiveToIdle_DMA(&huart3, TM_BUS_DATA_RX_BUFFER, TM_BUS_DATA_RX_BUFFER_SIZE);
		__HAL_DMA_DISABLE_IT(&hdma_usart3_rx, DMA_IT_HT);
	}
}

everything works, for example I tried to send first 5 characters, then 8 characters and everything is fine, but if I try to send a package longer than 16 characters, only the first 16 characters are read and then everything freezes and no more data is received from the UART.

0693W00000LysonQAB.jpgI don't understand why everything crashes with packets longer than 16 characters since my buffer is 256 bytes. Where did this 16 byte limit come from?

Can anyone help me?

5 REPLIES 5
KnarfB
Principal III

DMA_IT_HT seems dangerous. Even if you don't use that IRQ, HAL might depend on it. Moreover, HAL_UARTEx_ReceiveToIdle_DMA is non-blocking, so the __HAL_DMA_DISABLE_IT may kick in while the DMA is active.

If you think, HT is too much overhead, you should go LL instead of HAL.

hth

KnarfB

TDK
Guru

Probably HAL_UARTEx_RxEventCallback is being called on the first 16, then DEBUG_MSG takes longer than it should which causes a UART overrun, then the rest of the characters are lost.

Debug the code, hit pause when it's "crashed" and examine where the code is and the state of the UART flags, especially OVR.

I also think disabling HT is a bad idea and will cause problems, but is not the root cause of this particular issue.

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

I apologize for the delay in replying, but today is a national holiday in Italy.

@KnarfB​ @TDK​ I can disable HT interrupt, but how can I ignore HT interrupts in callback?

@TDK​ The Overrun is not a problem as my application should never receive packets larger than my buffer size. (And even if a packet larger than the buffer arrives I could ignore it).

Probably HAL_UARTEx_RxEventCallback is being called on the first 16

OK, it is clear that the HAL_UARTEx_RxEventCallback function is called after 16 bytes, but why immediately after 16 bytes? This number is nowhere in my code. How do I know what happens after 16 bytes? What flags I can check?

Tomorrow I can try to change the USB-UART converter or see what happens on the serial line with a logic analyzer, can these be useful tests?

Anyway thanks in advance.

> The Overrun is not a problem as my application should never receive packets larger than my buffer size.

It's not the size of the packets, it's the delay between HAL_UARTEx_RxEventCallback being called and the next HAL_UARTEx_ReceiveToIdle_DMA being started here.

> How do I know what happens after 16 bytes? What flags I can check?

As I said before:

Debug the code, hit pause when it's "crashed" and examine where the code is and the state of the UART flags, especially OVR.

> Tomorrow I can try to change the USB-UART converter or see what happens on the serial line with a logic analyzer, can these be useful tests?

Of course. If RealTerm has a delay after byte 16, however small, that's likely your answer.

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

I did some testing and it seems the problem is the nucleo board VCP converter. Trying with another USB-UART converter the problem does not arise. (for now :))

At this point, however, I only have to understand why the system stops when that event occurs. In debug I saw the UART ISR register just before the  HAL_UARTEx_ReceiveToIdle_DMA function in the HAL_UARTEx_RxEventCallback, when I have the problem I see these 3 flags set: ORE, IDLE, TXFNE.

Could it be one of these that causes the uart block? I try to clear these flags before calling the  HAL_UARTEx_ReceiveToIdle_DMA function again,

__HAL_UART_CLEAR_OREFLAG(&huart3);
__HAL_UART_CLEAR_IDLEFLAG(&huart3);
HAL_UARTEx_ReceiveToIdle_DMA(&huart3, TM_BUS_DATA_RX_BUFFER, TM_BUS_DATA_RX_BUFFER_SIZE);

and it seems that the situation has improved, could this be a stable and reliable solution?