cancel
Showing results for 
Search instead for 
Did you mean: 

UART DMA Capture Restart.

federico.massimi
Associate III

Hi, I need a little help with this situation.

I have to receive a packet from a serial port, this packet has a variable size and is also quite long. So I use two areas of RAM as a buffer and alternatively send the data to an external flash. I tried using the UART's IDLE line interrupt, but I haven't been able to use it in combination with the DMA double buffer. This would be the best solution and if someone could help me make it work it would be great.

For now I have done it this way, I have added a timer, and if no data is received for a certain time, the package is considered finished.

Everything works, I just have a doubt, in the timer callback, when the package is finished, I have to delete the residual data in the UART and restart the capture, for now I have done this:

HAL_UART_DMAStop(&huart1);
HAL_UART_Receive_DMA(&huart1, usartRxBuffer, DATA_PACKET_SIZE);

Just wanted to ask if it's the right way to "restart" the UART?

And if anyone has suggestions for DILE line interrupt with the double DMA buffer it is always welcome�� .

Thanks in advance.

4 REPLIES 4
TDK
Guru

The most robust method to receive UART data is to have the DMA operate in circular mode and poll for new characters as needed. That way, it is never disabled and can never miss characters.

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

I am using a circular buffer but still have the problem of "restarting" the UART. Let me explain, I have to get a large data packet, about 30Mb, I made a buffer of almost all the RAM of the micro, and my idea is this:

I start acquiring data from the UART, when the HalfComplete interrupt arrives, I start writing the first half of the buffer in an external SPI flash (with another channel of DMA), then when the second half is acquired, send also the second half to the flash and everything starts again.

At the end of the packet, the last DMA si not completed and I write what's in the buffer in the flash and the transfer is complete. Now the problem is to make this mechanism work well, the next package must still be acquired at the beginning of the buffer, not where the DMA has stopped, so I have to make sure that the UART + DMA "restarts" to restart acquiring data at the beginning of the buffer.

Maybe I could do something like that?

__HAL_DMA_DISABLE(huart1.hdmarx);
huart1.hdmarx->Instance->NDTR = UART_BUFFER_SIZE;
 __HAL_DMA_ENABLE(huart1.hdmarx);

It works? Can there be problems?

PS: I can tolerate a some lost packages, not a problem.

Which STM32?

> It works? Can there be problems?

Generally, the scheme is similar - disable DMA, rewrite NDTR, reenable DMA. Whether there will be problems, depends on what exactly do those Cube/HAL incatations do.

In the double-port DMA ('F2/'F4/'F7 - I guess this is what you have), after writing 0 into CR.EN, you have to wait until it gets cleared "from inside"; it also throws a Transfer Complete interrupt at that moment, so you have to bear that in mind.

In the single-port DMA (other 'L, 'F and 'G) - it's enough to clear CCR.EN, and it does not throw the interrupt.

Re-enabling is plain, in both.

JW

federico.massimi
Associate III

I tried with:

__HAL_DMA_DISABLE(huart1.hdmarx);
huart1.hdmarx->Instance->NDTR = UART_BUFFER_SIZE;
 __HAL_DMA_ENABLE(huart1.hdmarx);

But when I re-enable DMA it seems that an UART_Rx_Complete interrupt is generated. And it is very annoying because I have to add a flag or something similar to check if the interrupt is generated by new data or if is generated by this re-enabling of the DMA.

I went back to the solution:

HAL_UART_DMAStop(&huart1);
HAL_UART_Receive_DMA(&huart1, usartRxBuffer, DATA_PACKET_SIZE);

which for now seems to work, do you think that I can have problems with this code?