cancel
Showing results for 
Search instead for 
Did you mean: 

Re-synchronise HAL_UART_Receive_DMA best way?

######
Senior

Hello,

Using HAL_UART_Receive_DMA() function and expecting an N length message, so have set the buffer length and transfer size to N.

The communicating equipment sometimes adds an extra character / or drops a character which is taking my DMA out of synchronisation.

Once out of synchronisation it is then staying like this until a reset occurs. 

I can capture that it is out of sync and log a data error. When this occurs I would like to restart the DMA so that the data is resynchronised.

Example of the problem below:

Normal Operation Receive Bytes: 1, 2, 3, 4, ... N

When out of Sync every receive now looks like: 2, 3, 4, ... N, 1

What functions are in the HAL that allow me to resynchronise the DMA in the best way?

Thanks in advance.

PS - Have moved away from using DMA to IDLE as the connecting equipment sometimes drips feeds bytes in a disorderly fashion.

3 REPLIES 3
Karl Yamashita
Lead III

You didn't mention if you're using normal or circular mode for the DMA. You haven't shown any code so we don't know what you're doing in the callback, which is probably the issue if you're getting out of sync.

You should try HAL_UARTEx_ReceiveToIdle_DMA and HAL_UARTEx_RxEventCallback and save the packet of data to a queue buffer. If you do truly receive a bad packet, at least on the next good packet it'll be in sync again.

If smoke escapes your device, put the smoke back in. It'll still work as a conversation piece. If you find my answers useful, click the Accept as Solution button so that way others can see the solution.

Hi Karl,

As I said in my original post, I have used HAL_UARTEx_RecevieToIdle_DMA which isn't satisfactory as the communicating equipment inserts idle conditions periodically inbetween bytes - makes the problem worse.

I am currently using HAL_UART_Receive_DMA() in Normal mode. The DMA is pointed to an RXBuffer, then copied in the callback to a ProcessBuffer.

My callback has this form:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (huart->Instance == UARTX)
  {
    if (huart->RxEventType == HAL_UART_RXEVENT_TC)
    {
       /* memcpy to a ProcessBuffer */

       /* set a flag to Process in the main loop */

     HAL_UART_Receive_DMA(...)
}

All of this currently works in normal conditions. I've confirmed the problem occurs when the communicating equipment aborts a transmission on purpose, e.g. sends 5 characters instead of 6. The DMA still sits and waits for a 6th character.

To clarify, my question is really what HAL functions do I use to efficiently restart the UART/DMA? e.g. from the functions below and or others:

Pause the DMA Transfer using HAL_UART_DMAPause()
Resume the DMA Transfer using HAL_UART_DMAResume()
Stop the DMA Transfer using HAL_UART_DMAStop().

Failing this I shall have to move back and process each incoming byte on interrupt without DMA.

TIA.

In your callback you essentially restarted the DMA by calling HAL_UART_Receive_DMA. So the problem looks to be in your processing function.

Instead of DMA in normal mode, use circular mode. That way you get half and complete callback. You then copy either half to a larger buffer. To be sure you stay in sync when parsing from the larger buffer you should have a checksum, preferably a 16 bit checksum. You already know the fix length of data. So with the fix length and the checksum you can parse your good packet from the larger buffer.

If smoke escapes your device, put the smoke back in. It'll still work as a conversation piece. If you find my answers useful, click the Accept as Solution button so that way others can see the solution.