RSL10 UART DMA usage for CLI

In DMA mode, the UART of RSL10 offers the best possible performance while minimizing CPU load because a single interrupt occurs at the end of the DMA transfer.

This sounds great, but in practice there are restrictions if we want to use it for a Command Line Interface (CLI) in text mode…

Tx Side of UART DMA transfer

On Tx side, it works as expected: if you need to send 17 bytes of text, you provide to the UART driver a pointer + size and it will care about it. In the meantime, if you must transfer two more lines of 5 and 23 bytes, you will need to wait for the end of the current transfer, but you can enqueue the data in a waiting buffer; thus, when the end of transfer interrupt occurred, you can send all 28 bytes in a single call.

Conclusion: the UART Tx side offers the expected performance.

Rx Side of UART DMA transfer

Rx side is a bit trickier in the case of CLI because you don’t know in advance the size of the line to read. Moreover, the DMA reception doesn’t handle specific events such as:

  • interrupt the packet reception when an end-of-line is encountered
  • same thing for other special characters such as Backspace, Del, Arrows to handle line edition
  • timeout after the first (or last) character received

If such events could also trigger the DMA interrupt, a performant implementation would be possible, but unfortunately, they are ignored.

A last point could also help: reading ahead the reception buffer. Let’s take the example of a buffer reception waiting for 4 bytes but a small command of 3 bytes is entered. Of course, the interrupt is not triggered (waiting for one more byte) but if the buffer was previously cleared (filled with zeros) it is possible to read it periodically and manage a partial reception of the 3 received bytes. In practice, this doesn’t work as the DMA controller manages an internal buffer to write to memory only once 4 bytes have been received… Thus, read-ahead is not possible either.

So, the solution is to use a buffer reception of 1 byte to make sure we won’t miss the end of line. A slightly better solution is to use circular mode allowing the automatic flip-flop between two 1-byte buffers (still leading to an interrupt after each character).

Conclusion: the UART Rx side offers a performance roughly like interrupt mode.

3 Likes

Hi @rvs,

Thank you for the excellent feedback. We will take this into consideration with regards to our current and future product offerings.

Regarding a few of the comments, I also have the feedback below:

This strategy (timeout from first) could be achieved using a combination of our DMA Counter Interrupt and Transfer Interrupt. By setting the Counter interrupt to fire after the first character is received over the UART RX, you would be able to start a timer that would automatically end the transfer after a given amount of time.

I believe this is only the case if the Peripheral (UART) is set to 32bit mode. If you instead set the interface to operate in 8bit mode the DMA request line should trigger a transfer from Peripheral to the Memory buffer every time an 8bit character is received.

In this configuration it would likely be possible to check the latest character transferred into the memory buffer to see if it was the expected ‘end-of-command’ character.

1 Like

@brandon.shannon

I didn’t test your proposals but they should certainly work.
I confirm my Rx DMA configuration was set to 32 bit in memory explaining my failure of read-ahead:

    /* Prepare rx dma configuration */
    const DMA_CFG_t dmaCfgR = {
        .src_sel       = DMA_TRG_UART,
        .src_step_mode = DMA_STEP_STATIC,
        .src_word_size = DMA_WORD_SIZE_8,
        .dst_sel       = DMA_TRG_MEM,
        .dst_step_mode = DMA_STEP_INC,
        .dst_word_size = DMA_WORD_SIZE_32,
        .byte_order    = DMA_ENDIANNESS_LITTLE,
        .ch_priority   = DMA_CH_PRI_0,
        .data_mode     = DMA_REPEAT	// Use flip/flop instead of DMA_SINGLE
    };
4 Likes