This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1290NCPDT: uDMA Demo on Tiva Micro

Part Number: TM4C1290NCPDT
Hi:
In the uDMA Demo from TI, a ping-pong approach is used for receiving data (see the code below). The receiving variable, The g_ui8RxBufA, is currently set to 256 bytes.  My question is that when UDMA_MODE_STOP is set at the interrupt handler, how do we know the actual received bytes when the remote end is sending less than 256 bytes of data?
Dennis
    //
    // Check the DMA control table to see if the ping-pong "A" transfer is
    // complete.  The "A" transfer uses receive buffer "A", and the primary
    // control structure.
    //
    ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_UART1RX | UDMA_PRI_SELECT);
    //
    // If the primary control structure indicates stop, that means the "A"
    // receive buffer is done.  The uDMA controller should still be receiving
    // data into the "B" buffer.
    //
    if(ui32Mode == UDMA_MODE_STOP)
    {
        //
        // Increment a counter to indicate data was received into buffer A.  In
        // a real application this would be used to signal the main thread that
        // data was received so the main thread can process the data.
        //
        g_ui32RxBufACount++;
        //
        // Set up the next transfer for the "A" buffer, using the primary
        // control structure.  When the ongoing receive into the "B" buffer is
        // done, the uDMA controller will switch back to this one.  This
        // example re-uses buffer A, but a more sophisticated application could
        // use a rotating set of buffers to increase the amount of time that
        // the main thread has to process the data in the buffer before it is
        // reused.
        //
        ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1RX | UDMA_PRI_SELECT,
                                   UDMA_MODE_PINGPONG,
                                   (void *)(UART1_BASE + UART_O_DR),
                                   g_ui8RxBufA, sizeof(g_ui8RxBufA));
    }
  • You will not get an interrupt with UDMA_MODE_STOP until you have received the 256 bytes requested. If the remote unit sending the bytes does not send 256 bytes, the uDMA will wait indefinitely. Because of this using uDMA to receive from a peripheral when the number of bytes to receive is not known before hand is not practical.

  • Hi:

    Do you a better approach of using uDMA operation, other than transfer data from a peripheral, to get the actual size of received data?

    Dennis

  • When receiving an unknown number of bytes from a peripheral, such as when the packet is defined by an end character or a timeout, I use interrupts, not DMA. When the length of the packet is defined by a byte sent early in the packet, you can use interrupts and then finish reading the packet by DMA once you read the length.

  • Hi:

    I think you are saying that using the interrupt and read the characters from the FIFO and determine the length of packet, and then switch to DMS for the rest of data?

    Do you have an example or an outline of code segment that does that?

  • Yes, that is what I am suggesting. I do not have an example as it is very protocol specific.

  • Can you describe the protocol, at least well enough to identify the size of the packet?

  • The protocol is this:

    One packet

    <Cmd><2 byte Count><5 reserved bytes><Payload up to 2K><2 Byte Checksum>

    Note: the client can send a series of packet in the above-mentioned format. As you can see, a fix size DMA operation is not practical to determine the received data.

    Do you have an outline of code segment of how to do the hybrid solution suggested earlier?

  • OK, let me work on it. The plan would be to setup UART1 FIFO to interrupt after receiving 4 characters. The interrupt routine will then read the command and packet length. It will setup the uDMA to read the rest of the packet. With a 16x8 FIFO there will be a 12 character receive time for the interrupt to respond and setup the DMA. 

    What baud rate is the data? Is there any hardware flow control on the UART?

  • Hi:

    The baud rate is 115200 with no hardward flow control.  However, we did use RTS and CTS for flow control.

  • Here is the basic flow.

    1) Setup the UART to use the FIFO and to interrupt after receiving 4 characters. Also setup the uDMA to do a basic transfer, but don't yet enable the uDMA channel.

    2) In the UART interrupt routine, read the first three characters from the FIFO. From the second and third characters, determine the number of remaining characters. Disable the UART RX interrupt, finish the uDMA initialization setting the transfer size and enable the uDMA channel and enable the UART RX DMA interrupt.

    3) The second time the UART interrupt routine is entered the entire packet should have been received. Now you can re-enable the UART RX interrupt to prepare for receiving the next command. You can use a static enum to keep track  of whether the interrupt is for receiving a command or for finishing the packet.

    Basically executing the UART RX interrupt routine twice for every packet received. Using RTS and CTS to control data flow should make interrupt latency not a concern. If the execution time of the interrupts must be kept to an absolute minimum, you can embed the source from the TivaWare functions instead of calling them. Often you can optimize the code for your application and you will save the call/return time.

  • Hi Bob,

    In your proposed outlines, the DMA operation would be frozen f the logic retrieve the wrong data length (for whatever reason) and never get the expected data length.

    Is there a catch or handling logic to address this type of error, which may happen in data communications between two devices?

  • Hi Dennis,

    To handle the condition where the peripheral receives less data than the uDMA expects, you would need to use a timer which would interrupt based on the amount of data expected. If the timer times out before the DMA transaction completes, then you must assume the data packet is not valid. You can abort the uDMA transmission by disabling the channel. You would then re-initialize the uDMA transmission and you must have some mechanism to tell the source to retransmit the packet.

    In the first UART interrupt routine you setup and start the uDMA, then setup and start the timer. If the second UART interrupt happens first, (the correct amount of data was received) you disable the timer. If the timer interrupt happens first (not enough data was received) you disable the uDMA channel and then tell the source to restart the packet transmission.

    How accurate you can make the timeout period depends on the predictability of the transmission source. You really have the same issue if you are polling a UART or using only UART interrupts. It is just that with the DMA you timeout on the packet time, not the individual bytes.