Overview:
This is somewhat a continuation based on the results of a previous thread, with the focus on a specific UART use case on the TM4C.
Use Case:
Within this TI-RTOS application, there will be one main high priority task. It's sole purpose is to receive a 32-byte payload over UART @ 115200 8-N-1, every 10ms.
Within this payload, there's a 2 byte header, and 2 byte footer, which are fixed values, and do not change.
Header | Body | Footer |
Bytes[0:1] | Bytes[2:29] | bytes:[30:31] |
The TM4C will have other lower priority tasks running, but aside from the watchdog, this UART RX task will be next in line in terms of priority.
Options:
As I see it, I have 3 main options to effectively receive and process this data. I've implemented each option as a proof of concept, but based on those implementations, two of them have a common error path, which is the reason for the post. The options below are listed in order of performance, where #1 is the least performant solution.
- Create a task that triggers a Hwi for each character received over UART. Based on the character sequence, detect the header, data, footer, and parse accordingly. The major downside to this approach is the context switching that would be required. Since these interrupts would trigger in the form of an Hwi, and Hwi's have the highest priority in the RTOS, then you would be constantly interrupting other tasks as data is received.
- Create a task which leverages DMA with UART, kind of similar to the existing UART Echo example provided by TI. In this case, you would manually setup the read, and sleep (non-blocking) until the UART_INT_DMARX Hwi triggers. Once triggered, you can pull out the 32 bytes and parse as needed.
- Create a task, very similar to #2 above, but optimized by utilizing UDMA_MODE_PINGPONG. Basically as one buffer is filling up (B), you can process the previously collected buffer (A) and vice versa.
Results:
In terms of options #2 and #3, in the happy path scenario, they worked fine. However, they both suffer from the same issue; what if you don't receive the full 32 byte payload? Since we are using DMA to facilitate UART RX, the Hwi will only fire once the DMA buffer is full (every 32 bytes). If you only received 10 out of the 32 bytes, and then a new frame arrives, then you would be out of sync from a parsing perspective.
I tried playing around with interrupt masks such as UART_INT_RT, and UART_INT_BE, thinking, maybe by enabling those bits, the Hwi would trigger if the FIFO is not empty, and no data is received after (n) cycles. However, I'm thinking that because I am using DMA, the transfer from the FIFO to the destination address would happen almost instantly, meaning the FIFO would never actually be in the state where there's residual data left over (am I correct on saying this? Not too confident on that one)
Question:
So I guess this is a very long winded way of asking, when using DMA with UART, is there any way to know when the expected payload is incomplete. i.e you were expecting to read 32 bytes, but only received 8? My first thought was to simply use a timer to track the delta between bytes received, but again, since I am using DMA, I only get the Hwi when all 32 are received, and I'm trying to catch the use case where they are not.
I have a feeling that this issue has been solved before, so I figured I would ask the question before trying to reinvent the wheel.
Thanks!