akospasztor / stm32-dma-uart

Efficient DMA timeout mechanism for peripheral DMA configured in circular mode demonstrated on a STM32 microcontroller.
MIT License
125 stars 46 forks source link

DMA Rx Complete event split data output #8

Open FPSUsername opened 4 years ago

FPSUsername commented 4 years ago

I adapted your code for my workspace and found an issue regarding the data length when the callback reaches a DMA Rx complete event.

The DMA_BUF_SIZE is 64 bytes and the incoming data is 5 bytes long. Once the DMA buffer is filled, I see that the start position is 60 (so it received 12 messages already).

The problem now occures at: length = DMA_BUF_SIZE - start;

This means that the length is set to 4 bytes. The next time it fires the callback it checks the remaining byte(s).

FPSUsername commented 4 years ago

I solved the issue by expanding the struct with a data length memory and another flag (I called it the dma_flag).

If the DMA Rx Complete event happens, it sets the dma flag. Then it writes the first couple of bytes to the uart buffer. Finally it saves the current data length. The next run it triggers, it sets the "i" variable with the saved data length. Now it will write the remaining byte(s) at the end of the uart buffer.

At the end of the callback function you can add a something like if (dma_uart_rx.dma_flag == 0) in order to trigger an action with the uart buffer (when it's completed)

akospasztor commented 4 years ago

Hi,

first let me clarify your issue a bit ore in detail, because it's not entirely clear for me where lies the actual problem. So based on your first comment, the following happens:

If yes, then the following happens: we have 4 empty bytes in the dma buffer, and 5 bytes are coming. Right after receiving the 4th byte, the DMA complete interrupt fires and calls the callback. In the meantime, we receive the remaining, 5th byte which is written by the dma peripheral into the very first byte of the array (overflow happened). The callback processes the incoming 4 bytes, then returns. After receiving the 5th byte, the transmission stops and after a timeout (described in README), the same callback is called again to process the remaining bytes that are overflown (in this case, only one byte).

This should work like this. Can you please elaborate more where lies your issue?

PS: when messages are arriving in a periodic way and data processing within a time bound becomes crucial, the buffer should consists of two parts and half-transfer interrupt should be utilized. Thus, the application can process safely the first part of the buffer while the dma writes new incoming data into the second half.

Best, Akos

FPSUsername commented 4 years ago

The problem I had is with the copying of the DMA buffer to the UART buffer. In this case, only the first 4 bytes of the 13th message were copied to the UART buffer (because of the DMA complete interrupt). Upon the next interrupt (timeout), the 5th byte is written in the UART buffer, at the wrong location (written at position 0 instead of 4). This is why I added a variable that keeps track of the data length so that I could use it as the starting point for the 5th byte.

In order not to trigger any further action (in my case, send the data over the CAN bus) with an incomplete UART buffer, I simply used the extra flag.

akospasztor commented 4 years ago

Ohh okay, now i get it. Yeah, you're right but this "issue" is rather how the data is being processed after the dma reception (and not the reception itself). Obviously, applications need appropriate and further data processing methods to correctly handle the data, depending on the needs. This is only a demo about the dma reception itself - it just flushes the received bytes (regardless of message re-construction or any byte handling) through the USB VCP :)