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.

EK-TM4C1294XL: Repeated Bytes in Local Buffer in polling method

Part Number: EK-TM4C1294XL

Hello Team,

I'm working on EK-TM4C1294XL on DMA receive with UART using polling method. I'm sending 3 bytes of packet from TM4C eval board to another msp430 board, I want to receive those bytes on RxBufferA from Data register. When i run the code i'm getting 147,3,3,3. but i need to get 147,1,17. Am i missing something in configuration or anywhere? can someone guide me in a right way. Below is the code and output following where bytes in yellow are repeated in RxBufA instead 147,1,17.

void
uDMAIntHandler(void)
{}
/*****************************************************************/
void
UART3IntHandler(void)
{}
/*****************************************************************/  
void
InitUART3Transfer(void)
{

    //
      // Enable the GPIO Peripheral used by the UART.
      //
      ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);


      //
      // Enable processor interrupts.
      //
      ROM_IntMasterEnable();

      //
      // Configure GPIO Pins for UART mode.
      //
      ROM_GPIOPinConfigure(GPIO_PA4_U3RX);
      ROM_GPIOPinConfigure(GPIO_PA5_U3TX);
      ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_4 | GPIO_PIN_5);

    //
    // Enable the UART peripheral, and configure it to operate even if the CPU
    // is in sleep.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3);

    //
    // Configure the UART communication parameters.
    //
    ROM_UARTConfigSetExpClk(UART3_BASE, g_ui32SysClock, 1000000,
                            UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                            UART_CONFIG_PAR_NONE);

    //
    // Set both the TX and RX trigger thresholds to 4.  This will be used by
    // the uDMA controller to signal when more data should be transferred.  The
    // uDMA TX and RX channels will be configured so that it can transfer 4
    // bytes in a burst when the UART is ready to transfer more data.
    //
    ROM_UARTFIFOEnable(UART3_BASE);
    ROM_UARTFIFOLevelSet(UART3_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);

    //
    // Enable the UART for operation, and enable the uDMA interface for both TX
    // and RX channels.
    //
    ROM_UARTEnable(UART3_BASE);

    ROM_UARTDMAEnable(UART3_BASE, UART_DMA_RX | UART_DMA_TX);

    //
    // Put the attributes in a known state for the uDMA UART1RX channel.  These
    // should already be disabled by default.
    //
    ROM_uDMAChannelAttributeDisable(UDMA_CH16_UART3RX,
                                    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                    UDMA_ATTR_HIGH_PRIORITY |
                                    UDMA_ATTR_REQMASK);

    //
    // Configure the control parameters for the primary control structure for
    // the UART RX channel.  The primary contol structure is used for the "A"
    // part of the ping-pong receive.  The transfer data size is 8 bits, the
    // source address does not increment since it will be reading from a
    // register.  The destination address increment is byte 8-bit bytes.  The
    // arbitration size is set to 4 to match the RX FIFO trigger threshold.
    // The uDMA controller will use a 4 byte burst transfer if possible.  This
    // will be somewhat more effecient that single byte transfers.
    //
    ROM_uDMAChannelControlSet(UDMA_CH16_UART3RX | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
                              UDMA_ARB_4);

    //
    // Put the attributes in a known state for the uDMA UART1TX channel.  These
    // should already be disabled by default.
    //
    ROM_uDMAChannelAttributeDisable(UDMA_CH16_UART3RX,
                                    UDMA_ATTR_ALTSELECT |
                                    UDMA_ATTR_HIGH_PRIORITY |
                                    UDMA_ATTR_REQMASK);

    //
    // Set the USEBURST attribute for the uDMA UART TX channel.  This will
    // force the controller to always use a burst when transferring data from
    // the TX buffer to the UART.  This is somewhat more effecient bus usage
    // than the default which allows single or burst transfers.
    //
    ROM_uDMAChannelAttributeEnable(UDMA_CH17_UART3TX, UDMA_ATTR_USEBURST);

    //
    // Configure the control parameters for the UART TX.  The uDMA UART TX
    // channel is used to transfer a block of data from a buffer to the UART.
    // The data size is 8 bits.  The source address increment is 8-bit bytes
    // since the data is coming from a buffer.  The destination increment is
    // none since the data is to be written to the UART data register.  The
    // arbitration size is set to 4, which matches the UART TX FIFO trigger
    // threshold.
    //
    ROM_uDMAChannelControlSet(UDMA_CH17_UART3TX | UDMA_PRI_SELECT,
                              UDMA_SIZE_8 | UDMA_SRC_INC_8 |
                              UDMA_DST_INC_NONE |
                              UDMA_ARB_4);

    //
    // Now both the uDMA UART TX and RX channels are primed to start a
    // transfer.  As soon as the channels are enabled, the peripheral will
    // issue a transfer request and the data transfers will begin.
    //
    ROM_uDMAChannelEnable(UDMA_CH16_UART3RX);
    ROM_uDMAChannelRequest(UDMA_CH16_UART3RX);
    ROM_uDMAChannelEnable(UDMA_CH17_UART3TX);
    ROM_uDMAChannelRequest(UDMA_CH17_UART3TX);

    //
    // Enable the UART DMA TX/RX interrupts.
    //
    ROM_UARTIntEnable(UART3_BASE, UART_INT_DMARX);

    //
    // Enable the UART peripheral interrupts.
    //
    ROM_IntEnable(INT_UART3);
}

/*****************************************************************/  

int
main(void)
{
    uint32_t ui32Status;
    uint32_t ui32Mode;
    //
    // Set the clocking to run directly from the crystal at 120MHz.
    //
    g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                             SYSCTL_OSC_MAIN |
                                             SYSCTL_USE_PLL |
                                             SYSCTL_CFG_VCO_480), 120000000);

    //
    // Enable peripherals to operate when CPU is in sleep.
    //
    ROM_SysCtlPeripheralClockGating(true);


    //
    // Enable the uDMA controller at the system level.  Enable it to continue
    // to run while the processor is in sleep.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

    //
    // Enable the uDMA controller error interrupt.  This interrupt will occur
    // if there is a bus error during a transfer.
    //
    ROM_IntEnable(INT_UDMAERR);

    //
    // Enable the uDMA controller.
    //
    ROM_uDMAEnable();

    //
    // Point at the control table to use for channel control structures.
    //
    ROM_uDMAControlBaseSet(pui8ControlTable);

    //
    // Initialize the uDMA UART transfers.
    //
    InitUART1Transfer();

    //
    // Loop until the button is pressed.  The processor is put to sleep
    // in this loop so that CPU utilization can be measured.
    //
    while(1)
    {

        if(num)
        {
          num = 0;
          AutoIdPkt(); // My 3 bytes packet(147,1,17)
        }
       while(MAP_UARTCharsAvail(UART3_BASE))
       {

          //
         // Read the interrupt status of the UART.
         //
         ui32Status = ROM_UARTIntStatus(UART3_BASE, 1);

         ROM_UARTIntClear(UART3_BASE, ui32Status);

         //
         // 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_CH16_UART3RX | 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)
         {
        g_ui32RxBufACount++;
        ROM_uDMAChannelTransferSet(UDMA_CH16_UART3RX | UDMA_PRI_SELECT,
                                                  UDMA_MODE_BASIC,
                                                  (void *)(UART3_BASE + UART_O_DR),
                                                  g_ui8RxBufA, sizeof(g_ui8RxBufA));

                 ROM_uDMAChannelEnable(UDMA_CH16_UART3RX);
                 ROM_uDMAChannelRequest(UDMA_CH16_UART3RX);

          }
       }
    }
}

  • Do I understand correctly that the TM4C is supposed to send three characters out UART3 using uDMA, the MSP430 echoes those characters back and the TM4C then is to receive them using uDMA?

    I cannot follow your code. You call the function InitUART1Transfer() in line 182, but that function was not included. Instead you included the function InitUART3Transfer() on line 10, but never call it.

    Can you use CCS to export your project to a .zip file and attach it? That way I should get all of the source and the settings.

  • Thank you for the reply Bob,

    Yes. "TM4C is to send three characters out UART3 using uDMA, the MSP430 echoes those characters back and the TM4C then is to receive them using uDMA."

     InitUART1Transfer() only it is mistaken.

    I have attached zip file please check where i'm mistaken and guide me in a right direction. Also one thing i observed is UARTFIFODisable() function is not working where 

    UART_LCRH_FIFO = 1 every time. Why?

    UART_DMAreceive.zip

  • Before I dig deeper, have you looked at the serial port with a logic analyzer or oscillisope? It would be good to verify that the correct characters are coming into the UART3 RX pin. That way we know the problem is on the RX side, not the TX side.

  • I looked in serial port(terminal) 3 bytes are transferred correctly as expected. But at receiver side also getting only when i checked with break point at " ROM_uDMAChannelEnable(UDMA_CH16_UART3RX);
                  ROM_uDMAChannelRequest(UDMA_CH16_UART3RX);"   in while(1). Not getting in free run. Unable understand why?

  • Ok, there is a lot here. You set the UART3RX uDMA channel to do a basic transfer of "sizeof(g_ui8RXBufA" bytes. (Line565) But you only send three bytes. The uDMA channel would not go to UDMA_MODE_STOP, except that you call "ROM_uDMAChannelRequest(UDMA_CH16_UART3RX);. That function is for software uDMA requests. You basically started the RX uDMA before all three characters were received. Once enabled the UART3 uDMA channel gets its channelrequest from the UART. 

    Can you tell me what you want to do in the end application? Your current use of uDMA inside of a loop that calls UARTCharsAvail() does not make any sense.

  • Thank you Bob,

    As i was begginer to DMA i want to try in a polling fashion. Actually i want to receive bytes from peripheral data register to RxBufA using DMA  at the same i want to know whether there is a incrementing count or not in DMA to know how many bytes received without using handlers. Based on count i can process the received bytes. Since my packets are not more than 1024 bytes, therefore i'm using basic mode. When i have to start Rx uDMA ? How to know all bytes have received or not, Any count/indication for received bytes ? Please help me to resolve this issue. Any help would be very thankful.

  • Several times people have asked for ways to receive a variable number of transfers by uDMA or how to count the number of transfers already received by uDMA. The uDMA does not support this. If you don't know the number of bytes you want to receive, or you need to count the bytes as they come in, you should use CPU interrupts, not the uDMA.

  • So, For that can we use peripheral interrupt method to count number of bytes.?
    Also please solve polling method issue which i sent zip file. Where all bytes getting when i use breakpoint at
     " ROM_uDMAChannelEnable(UDMA_CH16_UART3RX);
       ROM_uDMAChannelRequest(UDMA_CH16_UART3RX);" .Otherwise same byte is repeating Bob. Can you guide me exact process to receive bytes from peripheral(UART)  in basic mode.

  • Bob, Can you please tell me-> Can we have access to read destination incrementing count(UDMA_DST_INC_8) in

    " MAP_uDMAChannelControlSet(UDMA_CH8_UART0RX |  UDMA_PRI_SELECT,                                                                                                    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4);"

    which is underlined?

  • The value UDMA_DST_INC_8 is a macro. Its value is 0 and it is used as a parameter to the function uDMAChannelControlSet(). I think what you are trying to ask is if you can read the address used by the uDMA controller for writing the value transfered. The answer to that question is no, this is a working register inside of the uDMA module with no direct CPU access. 

    Some people have tried to identify the state of the uDMA transfer by reading the RAM contents of the uDMA control block. (See the description starting on page 702 of this datasheet.) The problem with this is that the control block is only updated when the uDMA switches channels or completes.

  • Thank you for the reply Bob,
    As you said some people tried to read RAM contents of the uDMA control block. Can you please suggest any forum link with example of those people tried to read RAM content for reference or any issues you resolved regarding reading RAM content. This would help me to move to further process. Any help would be very thankful Bob.

  • As I mentioned in the previous post, read the uDMA control block does not allow you to identify the number of transfers that have occurred or the destination address of the next transfer because those values are stored in internal uDMA registers until the uDMA needs to do a channel change. As such, there is no post where it has been done successfully, and I suspect it cannot be done. There is a post discussing using uDMA to receive a Modbus RTU frame. The conclusion was it was better to use interrupts on the receive frame as the frame length could not be determined until the first several characters were received and analyzed.

    https://e2e.ti.com/support/microcontrollers/other-microcontrollers-group/other/f/other-microcontrollers-forum/481797/tm4c123g-uart-with-udma/1736099

  • The whole point of DMA is to minimize the CPU's involvement in the data transfer! That's why there are limited ways to manage and inspect the transfer status.

    What Bob is too nice to say is that you shouldn't even try to do what you think you want to do.

    You are sending tiny message packets over a slow link. There is nothing to be gained by trying to get the uDMA involved in this.