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.

uDMA help needed

Other Parts Discussed in Thread: TM4C129ENCPDT

I am trying to eventually write a driver for SPI communications via uDMA between two TM4C129x processors.  I have read through many of the forum posts here and the general recommendation was to get the uDMA_demo working first (over UART) and then change it to work with SPI as the configuration is similar.

I have the demo code working between two TM4C129x's but I am new to low level TIVA development and have a few questions.

1.  With the demo code, uDMA is enabled in both the TX and RX directions.  An interrupt is generated after each successful uDMA transfer. In the RX direction, the interrupt simply switches the ping pong buffer.  In the TX direction, the interrupt signals that the transfer was done and a new one set up and the channel re-enabled so that there will be new data ready to go when the UART makes another request.  Is this correct?

2.  Assuming the above is true, how do we safely modify the TX buffer to send data out?  IE, how do we ensure that the uDMA controller doesn't take a buffer that is partially full of data?

3.  My application requires two processors to exchange data periodically (10x / second).  I wanted to adapt the demo code for this purpose but am having trouble with the above question.  I have read about initiating DMA request via SW but i'm not entirely sure on how to configure a peripheral (UART or SPI) for the SW DMA transfer.  Do I keep the uDMA enabled in the TX direction when initiating the request via SW?  Any help here would be greatly appreciated.

Thank you

Steve

  • Hello Steve,

    Please find answers in the same order

    1. Yes that is correct. In RX direction the Buffer will switch and an interrupt generated when switch occurs.

    2. When the TX DONE interrupt is given, the CPU writes the buffer first and then enables the TX DMA Channel

    3. The configuration happens the same way for the uDMA. The only difference being that when the 100ms timer elapses the CPU goes and enabled the uDMA SW transfer. The uDMA on this will transfer the data from SRAM to UART if the Source and Destination are configured in the uDMA and UART enabled and configured

    Regards

    Amit

  • Thanks for the reply Amit.

    Regarding 2:

    So the idea here would be to have the CPU write the buffer inside the TX done interrupt and then enable the TX DMA Channel?  Is there a way to separate this outside of the ISR?

    I tried the following (this is the demo code with comments stripped out and my changes marked):

    void
    UART1IntHandler(void)
    {
        uint32_t ui32Status;
        uint32_t ui32Mode;
    
        ui32Status = ROM_UARTIntStatus(UART1_BASE, 1);
    
        ROM_UARTIntClear(UART1_BASE, ui32Status);
    
        ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_UART1RX | UDMA_PRI_SELECT);
    
        if(ui32Mode == UDMA_MODE_STOP)
        {
            g_ui32RxBufACount++;
    
            // Set a flag here to indicate that buffer A is ready for processing
            aBufferReady = true;
    
            ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1RX | UDMA_PRI_SELECT,
                                       UDMA_MODE_PINGPONG,
                                       (void *)(UART1_BASE + UART_O_DR),
                                       g_ui8RxBufA, sizeof(g_ui8RxBufA));
        }
    
        ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_UART1RX | UDMA_ALT_SELECT);
    
        if(ui32Mode == UDMA_MODE_STOP)
        {
            g_ui32RxBufBCount++;
    
            // Set a flag here to indicate that buffer B is ready for processing
            bBufferReady = true;
    
            ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1RX | UDMA_ALT_SELECT,
                                       UDMA_MODE_PINGPONG,
                                       (void *)(UART1_BASE + UART_O_DR),
                                       g_ui8RxBufB, sizeof(g_ui8RxBufB));
        }
    
        // Move this into a SendData() function that can be called inside the main loop
        //if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_UART1TX))
        //{
        //    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT,
        //                               UDMA_MODE_BASIC, g_ui8TxBuf,
        //                               (void *)(UART1_BASE + UART_O_DR),
        //                               sizeof(g_ui8TxBuf));
        //
        //    ROM_uDMAChannelEnable(UDMA_CHANNEL_UART1TX);
        //}
    }

    The idea here would be to have the ISR set a data ready flag whenever one of the buffers is ready for processing.  The main loop would check these flags and when new data comes in, it would process it, setup the TX buffer (copy data into it) and then call a SendData() function which would contain the code that is commented out above.

    I tried to implement this but the program seemed to get stuck looping in the ISR.  The ISR would execute and return but would loop back and execute again before anything else (main loop) could be executed.  It seems like an interrupt is not getting cleared, or something of that nature.

    After having little success with this, I started to think the SW request might be the way to go.

    Regarding 3:

    Just to clarify, the UART would still be setup to use DMA for both RX and TX (same as in the demo configuration)? 

    Thanks,

    Steve

  • Hello Steve,

    #2: The code that you have setup seems to be fine. Please note that the Interrupt is coming in the TX side as the UARTDMACTL bit for TX is still enabled. Since the FIFO is empty it will request for more data, even though the channel is disabled. Please make sure that the TXEN bit is cleared and is only set when the SendData function is called

    #3: Yes, UART would still be setup to use both DMA RX and TX.

    Regards

    Amit

  • Hi Amit,

    Ah, I knew there had to be some interrupt that I wasn't clearing.  I have modified the ISR as follows:

    EXPORT_C void UART6IntHandler(void) {
        uint32_t ui32Status;
        uint32_t ui32Mode;
    
        ui32Status = ROM_UARTIntStatus(UART6_BASE, 1);
    
        ROM_UARTIntClear(UART6_BASE, ui32Status);
    
        ui32Mode = ROM_uDMAChannelModeGet(10 | UDMA_PRI_SELECT);
    
        if(ui32Mode == UDMA_MODE_STOP)
        {
            rxBufferACount++;
            aBufferReady = true;
    
            ROM_uDMAChannelTransferSet(10 | UDMA_PRI_SELECT,
                                       UDMA_MODE_PINGPONG,
                                       (void *)(UART6_BASE + UART_O_DR),
                                       rxBufferA, sizeof(rxBufferA));
        }
    
        ui32Mode = ROM_uDMAChannelModeGet(10 | UDMA_ALT_SELECT);
    
        if(ui32Mode == UDMA_MODE_STOP)
        {
            rxBufferBCount++;
            bBufferReady = true;
    
            ROM_uDMAChannelTransferSet(10 | UDMA_ALT_SELECT,
                                       UDMA_MODE_PINGPONG,
                                       (void *)(UART6_BASE + UART_O_DR),
                                       rxBufferB, sizeof(rxBufferB));
        }
    
        // After the TX data has been sent, disable UART_TX DMA
        if(!ROM_uDMAChannelIsEnabled(11))
        {
            ////
            //// Start another DMA transfer to UART6 TX.
            ////
            //ROM_uDMAChannelTransferSet(11 | UDMA_PRI_SELECT,
            //                           UDMA_MODE_BASIC, txBuffer,
            //                           (void *)(UART6_BASE + UART_O_DR),
            //                           sizeof(txBuffer));
            //
            ////
            //// The uDMA TX channel must be re-enabled.
            ////
            //ROM_uDMAChannelEnable(11);
    
            // Disable the TX DMA
            ROM_UARTDMADisable(UART6_BASE, UART_DMA_TX);
        }

    I started with a working implementation of the DEMO and simply replaced the TX section of the ISR as detailed above.  I have not added any send functionality to the main loop yet as I just wanted to ensure that this was working.  

    With the above code, I thought that the first packet would go out (as it's configured to do so in the INITUART0Transfer() of the demo code), the ISR would fire indicating that the packet was transferred by the DMA controller, and then the TX UART DMA would be disabled.  This appears to be happening but I am no longer receiving packets and I'm not sure why.  All communication stops after the UART_DMA_TX is disabled. Am I missing something here?  The slave is running the same DEMO code and is just continuously sending packets but I am not receiving them.

    Thanks

    Steve

  • Just a followup:

    I found the solution to my bug.  It appears there is a typo in the TivaWare udma_demo (2.0.1.11577). Line 584 of udma_demo.c:

        //
        // Enable the UART DMA TX/RX interrupts.
        //
        ROM_UARTIntEnable(UART0_BASE, UART_INT_DMATX | UART_INT_DMATX);

    Both arguments are UART_INT_DMAXTX.  I believe it should read:

        //
        // Enable the UART DMA TX/RX interrupts.
        //
        ROM_UARTIntEnable(UART0_BASE, UART_INT_DMATX | UART_INT_DMARX);

    It appears to be working with this change but I have only done a few quick tests.  I will continue work on my implementation and report back.  Thanks.

    Steve

  • Hello Steve,

    I would suggest zip the CCS project and attach. I would need to look at the whole code and not a segment.

    Please do make sure that for the first transfer the UARTDMAEnable is called after the uDMA Channel is configured and enabled. Else you may end up firing a false interrupt routine causing the DMA to be disabled.

    Regards

    Amit

  • Hey Amit,

    I spent some time working on this yesterday and for the most part I think it's working but i'm running into a few issues.

    As I said before, I need to transfer 1K bytes of data between processors ~10x a second.  This communication is to be full duplex as each processor is needs to share its data with the other for a safety application. I started by adapting the demo code as stated in earlier posts.

    One issue I have is syncing the communication between the two processors. Specifically,  In the demo code, when one of the RX buffers fills up, an interrupt occurs and the DMA starts filling the other buffer.  I thought this would work as my packet size is constant but if the communication does not start at the same time, I am getting packets spread out over the two RX buffers.  IE, if one processor starts sending before the other is started (as an example).

    Do you have any suggestions on how to solve this problem?  We have a couple of handshake IO lines between both processors that could be used to sync the communication.  Another possibility would be to use the UART (eventuall SPI) timeout interrupt to indicate that the buffer should be switched.  This would allow for different sized packets (in the future) but care would need to be taken to ensure that two back to back packets are never sent as one would need to ensure that the timeout interrupt would fire (32 bit spacing for UART).  Any advice here would be appreciated.  

    Thanks,

    Steve

  • Hello Steve,

    What is the UART Baud Rate? The reason why I am asking this is because for 1K bytes it would 1000*10 bits which would be 10K bits to be sent. To find the maximum transfer rate supported it would be Baud Rate/10K. If the value is > 10 times a second then we have some head room.

    Secondly, try using the Burst Feature of the uDMA so that UDMA is more efficient in transferring the data.

    IO Synchronization would be a good idea as well. A simple code on both sides would look like below.

    GPIOOUT = 1

    while(GPIOIN == 0)

    This will ensure that both reach the same point almost together

    Regards

    Amit

  • Hi Amit,

    Thank you for the help thus far, I really appreciate it.  The good news is that I have a working implementation that seems to work well for all Baud rates up to the max of 15M.  I am having one issue that I can't seem to get my head around though.  I'll try to describe it as best I can.

    The following main() program simply exchanges data between processors 10x / second.

    int main(void) {
      uint32_t g_ui32SysClock;
    
      //
      // Run from the PLL at 120 MHz.
      //
      g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                           SYSCTL_OSC_MAIN |
                                           SYSCTL_USE_PLL |
                                           SYSCTL_CFG_VCO_480), 120000000);
    
      // Enable SysTick
      ROM_SysTickPeriodSet(g_ui32SysClock / 10000);
      ROM_SysTickEnable();
      ROM_SysTickIntEnable();
    
      // Handshake IO
      // PD0 Output Sync
      static const PinDef OUTPUT_SYNC_PIN('D', 0);
      OutputPin outputSync(OUTPUT_SYNC_PIN);
      // PF4 Input Sync
      static const PinDef INPUT_SYNC_PIN('F', 4);
      InputPin inputSync(INPUT_SYNC_PIN);
    
      // Sync Processors
      outputSync.Set(true);
      while(inputSync.Get() == 0) {}
      outputSync.Set(false);
    
      // Create the uDmaUart object. This will initialize the UART and UDMA
      // peripherals accordingly.
      static uDmaUart dmaUart(6, g_ui32SysClock);
    
      uint8_t txData = 0;
      uint8_t rxData = 0;
      uint32_t startTime = GetSysTick();
      while(true) {
        // Every 100ms
        if ((GetSysTick() - startTime) > 1000) {
          // Sync Processors
          outputSync.Set(true);
          while(inputSync.Get() == 0) {}
          outputSync.Set(false);
    
          // Send out our cross compare packet (we should verify that we sent the
          // packet out)
          if (TxUartBuffer buffer = dmaUart.TryAcquireTxBuffer()) {
            srand(txData);
            for (int i=0; i < uDmaUart::UART_TXBUF_SIZE; ++i)
              buffer[i] = (rand() % 256);
            dmaUart.SendData();
            txData++;
          }
    
          // Wait for the packet to come in (real implementation won't block)
          while (!dmaUart.DataReady()){}
    
          if (RxUartBuffer buffer = dmaUart.TryAcquireRxBuffer()) {
            srand(rxData);
            for (int i=0; i < uDmaUart::UART_RXBUF_SIZE; ++i){
              if(buffer[i] != (rand() % 256)){
                errorCount++;
                break;
              }
            }
            rxData++;
            dmaUart.ClearDataReady();
          }
    
          // Reset the timer
          startTime = GetSysTick();
        }
      }
    }

    Everything works perfect with this code and I am able to transfer data between processors indefinitely without errors.  The odd part is the need for the initial processor sync before the UART and DMA peripherals are initialized via the uDmaUart constructor. If I remove this synchronization I get problems.

    Specifically, it appears that the received data on whichever processor I enabled first is shifted by one byte. For example, if I do the following:

    • Set buffer sizes to 256
    • Configure both processors to send static data (0, 1, 2, 3, 4......255)
    • Enable processor 1 in JTAG and then
    • Enable processor 2 in JTAG

    Processor 2 will receive the correct data but processor 1 will receive (255, 0, 1, 2, ..... 254). If I enable processor 2 first, processor 1 will receive the correct data but processor 2 will receive the shifted data.  This is not an issue if I sync the processors before initializing the UART / UDMA peripherals.

    I am stumped on this one.  I have tried a few different things but nothing has worked.  Perhaps I am configuring something wrong in the UART / uDMA peripherals?  I pretty much followed the demo code as closely as possible. For reference, here is the code for the uDmaUart constructor:

    uDmaUart::uDmaUart(uint8_t id, uint32_t sysClk) : sysClk_(sysClk) {
      // Setup global variables and device pins
      switch(id) {
        case 0:
          UART_BASE = UART0_BASE;
          UDMA_TX_CHANNEL = 9;
          UDMA_RX_CHANNEL = 8;
          UART_PERIPHERAL = SYSCTL_PERIPH_UART0;
          UDMA_TX_CHANNEL_ASN = UDMA_CH9_UART0TX;
          UDMA_RX_CHANNEL_ASN = UDMA_CH8_UART0RX;
          UART_INT = INT_UART0;
          ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
          ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
          ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
          ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
          break;
        case 1:
          UART_BASE = UART1_BASE;
          UDMA_TX_CHANNEL = 9;
          UDMA_RX_CHANNEL = 8;
          UART_PERIPHERAL = SYSCTL_PERIPH_UART1;
          UDMA_TX_CHANNEL_ASN = UDMA_CH9_UART1TX;
          UDMA_RX_CHANNEL_ASN = UDMA_CH8_UART1RX;
          UART_INT = INT_UART1;
          ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
          ROM_GPIOPinConfigure(GPIO_PB0_U1RX);
          ROM_GPIOPinConfigure(GPIO_PB1_U1TX);
          ROM_GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
          break;
        case 2:
          UART_BASE = UART2_BASE;
          UDMA_TX_CHANNEL = 1;
          UDMA_RX_CHANNEL = 0;
          UART_PERIPHERAL = SYSCTL_PERIPH_UART2;
          UDMA_TX_CHANNEL_ASN = UDMA_CH1_UART2TX;
          UDMA_RX_CHANNEL_ASN = UDMA_CH0_UART2RX;
          UART_INT = INT_UART2;
          ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
          ROM_GPIOPinConfigure(GPIO_PA6_U2RX);
          ROM_GPIOPinConfigure(GPIO_PA7_U2TX);
          ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_6 | GPIO_PIN_7);
          break;
        case 3:
          UART_BASE = UART3_BASE;
          UDMA_TX_CHANNEL = 17;
          UDMA_RX_CHANNEL = 16;
          UART_PERIPHERAL = SYSCTL_PERIPH_UART3;
          UDMA_TX_CHANNEL_ASN = UDMA_CH17_UART3TX;
          UDMA_RX_CHANNEL_ASN = UDMA_CH16_UART3RX;
          UART_INT = INT_UART3;
          ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
          ROM_GPIOPinConfigure(GPIO_PA4_U3RX);
          ROM_GPIOPinConfigure(GPIO_PA5_U3TX);
          ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_4 | GPIO_PIN_5);
          break;
        case 4:
          UART_BASE = UART4_BASE;
          UDMA_TX_CHANNEL = 19;
          UDMA_RX_CHANNEL = 18;
          UART_PERIPHERAL = SYSCTL_PERIPH_UART4;
          UDMA_TX_CHANNEL_ASN = UDMA_CH19_UART4TX;
          UDMA_RX_CHANNEL_ASN = UDMA_CH18_UART4RX;
          UART_INT = INT_UART4;
          ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
          ROM_GPIOPinConfigure(GPIO_PA2_U4RX);
          ROM_GPIOPinConfigure(GPIO_PA3_U4TX);
          ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_2 | GPIO_PIN_3);
          break;
        case 5:
          UART_BASE = UART5_BASE;
          UDMA_TX_CHANNEL = 7;
          UDMA_RX_CHANNEL = 6;
          UART_PERIPHERAL = SYSCTL_PERIPH_UART5;
          UDMA_TX_CHANNEL_ASN = UDMA_CH7_UART5TX;
          UDMA_RX_CHANNEL_ASN = UDMA_CH6_UART5RX;
          UART_INT = INT_UART5;
          ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
          ROM_GPIOPinConfigure(GPIO_PC6_U5RX);
          ROM_GPIOPinConfigure(GPIO_PC7_U5TX);
          ROM_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_6 | GPIO_PIN_7);
          break;
        case 6:
          UART_BASE = UART6_BASE;
          UDMA_TX_CHANNEL = 11;
          UDMA_RX_CHANNEL = 10;
          UART_PERIPHERAL = SYSCTL_PERIPH_UART6;
          UDMA_TX_CHANNEL_ASN = UDMA_CH11_UART6TX;
          UDMA_RX_CHANNEL_ASN = UDMA_CH10_UART6RX;
          UART_INT = INT_UART6;
          ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
          ROM_GPIOPinConfigure(GPIO_PP0_U6RX);
          ROM_GPIOPinConfigure(GPIO_PP1_U6TX);
          ROM_GPIOPinTypeUART(GPIO_PORTP_BASE, GPIO_PIN_0 | GPIO_PIN_1);
          break;
        case 7:
          UART_BASE = UART7_BASE;
          UDMA_TX_CHANNEL = 21;
          UDMA_RX_CHANNEL = 20;
          UART_PERIPHERAL = SYSCTL_PERIPH_UART7;
          UDMA_TX_CHANNEL_ASN = UDMA_CH21_UART7TX;
          UDMA_RX_CHANNEL_ASN = UDMA_CH20_UART7RX;
          UART_INT = INT_UART7;
          ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
          ROM_GPIOPinConfigure(GPIO_PC4_U7RX);
          ROM_GPIOPinConfigure(GPIO_PC5_U7TX);
          ROM_GPIOPinTypeUART(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5);
          break;
      }
    
      // Initialize the UART and UDMA controllers
      Init();
    }
    
    void uDmaUart::Init() {
      // Enable the uDMA controller at the system level.
      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(dmaControlTable);
    
      // Enable the UART peripheral
      ROM_SysCtlPeripheralEnable(UART_PERIPHERAL);
    
      // Configure the UART communication parameters.
      ROM_UARTConfigSetExpClk(UART_BASE, sysClk_, UART_BAUD_RATE,
                              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_UARTFIFOLevelSet(UART_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
    
      // Enable the UART for operation, and enable the uDMA interface for the
      // RX channel. The TX channel will be enabled as needed since we are
      // sending data on request.
      ROM_UARTEnable(UART_BASE);
      ROM_UARTDMAEnable(UART_BASE, UART_DMA_RX);
    
      // Assign DMA Channel mux (this is dependant on the UART_NUMBER). See Pg.
      // 682 in the manual for details (TM4C129X)
      ROM_uDMAChannelAssign(UDMA_TX_CHANNEL_ASN);
      ROM_uDMAChannelAssign(UDMA_RX_CHANNEL_ASN);
    
      // Put the attributes in a known state for the uDMA UARTRX channel.  These
      // should already be disabled by default.
      ROM_uDMAChannelAttributeDisable(UDMA_RX_CHANNEL,
                                      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_RX_CHANNEL | UDMA_PRI_SELECT,
                                UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
                                UDMA_ARB_4);
    
      // Configure the control parameters for the alternate control structure for
      // the UART RX channel.  The alternate contol structure is used for the "B"
      // part of the ping-pong receive.  The configuration is identical to the
      // primary/A control structure.
      ROM_uDMAChannelControlSet(UDMA_RX_CHANNEL | UDMA_ALT_SELECT,
                                UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
                                UDMA_ARB_4);
    
      // Set up the transfer parameters for the UART RX primary control
      // structure.  The mode is set to ping-pong, the transfer source is the
      // UART data register, and the destination is the receive "A" buffer.  The
      // transfer size is set to match the size of the buffer.
      ROM_uDMAChannelTransferSet(UDMA_RX_CHANNEL | UDMA_PRI_SELECT,
                                 UDMA_MODE_PINGPONG,
                                 (void *)(UART_BASE + UART_O_DR),
                                 rxBufferA, sizeof(rxBufferA));
    
      // Set up the transfer parameters for the UART RX alternate control
      // structure.  The mode is set to ping-pong, the transfer source is the
      // UART data register, and the destination is the receive "B" buffer.  The
      // transfer size is set to match the size of the buffer.
      ROM_uDMAChannelTransferSet(UDMA_RX_CHANNEL | UDMA_ALT_SELECT,
                                 UDMA_MODE_PINGPONG,
                                 (void *)(UART_BASE + UART_O_DR),
                                 rxBufferB, sizeof(rxBufferB));
    
      // Put the attributes in a known state for the uDMA UARTTX channel.  These
      // should already be disabled by default.
      ROM_uDMAChannelAttributeDisable(UDMA_TX_CHANNEL, 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_TX_CHANNEL, 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_TX_CHANNEL | 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.
      // We will not enable the TX channel here as it is the responsibility
      // of SendData(). Remember - TX data is sent on request.
      ROM_uDMAChannelEnable(UDMA_RX_CHANNEL);
    
      // Enable the UART DMA TX/RX interrupts.
      ROM_UARTIntEnable(UART_BASE, UART_INT_DMATX | UART_INT_DMARX);
    
      // Enable the UART peripheral interrupts.
      ROM_IntEnable(UART_INT);
    }

    Any ideas on this one?  I'm stumped!

    Steve

  • Hello Steve,

    One of the things we do is to enable the clock to module at the start of the program. However in CCS on every run which does not involve a System Reset, it would mean that the next time a peripheral is re-configured by the code, there could already be something in it's control path that may cause spurious interrupts, dma requests and so on.

    I would suggest to use SysCtlPeripheralReset for all the peripherals being used at the start of the code. This will flush the peripheral of a data from the previous run. Do not exempt any peripheral.

    Regards

    Amit

  • Hi Amit,

    I tried your suggestion and reset all the peripherals but I still have the same problem.  I also tried using an LED to flag the issue so that I could bypass the JTAG and have both processors power up at the same time upon cycling power but to my surprise, the issue remains.  IE, if I don't have the processor sync before configuring the UART / UDMA, I get the buffer data shift error.  Cycling power doesn't matter, I still get an error (as indicated by the LED).

    Any ideas?  I'm stuck!

    Steve

  • Hello Steve,

    Let me check this on my side. Will take ma a few days and would post queries.

    Regards

    Amit

  • No problem Amit.  If you need me to zip the project and send it to you just let me know.

    Steve

  • Hello Steve

    If both sides are TM4C devices then it would be useful to have the zipped CCS project.

    Regards

    Amit

  • Hi Amit,

    Both sides are TM4C129ENCPDT's.  I have sent the project to your gmail address.

    Steve

  • Hi Amit,

    Now that I have a working implementation of the uDMA UART on my hardware (with the exception of the buffer shift bug), I am looking at modifying it to accept variable length packets.  Both processors need to be able to exchange arbitrary packets over the link.

    With that in mind, I was thinking about using the basic mode instead of the ping pong mode for the RX channel but I have a couple of implementation questions if you don't mind.

    I am planning on doing the following:

    • Keep the TX side as is (transfers are on request and this seems to be working well)
    • Switch the RX side to basic mode where the data is written into a single large buffer (large enough to accommodate multiple packets so that we have time to process the data before the buffer is overrun).
    • Have the UART timeout interrupt set to indicate that a packet has been received.  This interrupt will be tied to a pointer that indicates which data in the RX buffer is available for processing.  IE - when an interrupt occurs, we simply calculate how many bytes were received by the DMA (ROM_uDMAChannelSizeGet() will be helpful here) and keep track of this along with the pointer to the data.
    • When the RX buffer is full an interrupt will be thrown and the DMA buffer pointer is reset.

    So long as we process the data fast enough so that the DMA does not overwrite good data, it seems like this should work well. Am I on the right track here with the implementation?  Is there a better / more efficient way to do this? 

    As always, thank you kindly for all the help.  It has been invaluable.

    Steve

  • Update to my last post:

    I tried to implement it as described in my last post but it looks like the receive timeout interrupt won't work here as it is cleared whenever the UART FIFO becomes empty.  Since the DMA is constantly removing the data, it never gets asserted.  Come to think of it, i'm not sure I even need the interrupt.  I could simply calculate the number of bytes available to read on request.

    One question that I forgot to ask -- is it OK to read a part of the buffer while the DMA is writing to another part of it? 

    Thanks

    Steve

  • Hello Steve,

    I am first trying to get the other UART issue of the first byte being wrong sorted out.

    But on a general note: if the buffer is in SRAM then it is OK. If the buffer is the UART FIFo\O, then do make sure that the uDMA number of words to transfer will be met by the size of data incoming.

    Regards

    Amit

  • Hello Steve

    Apologies for the delay on the first issue: Without Sync the data is shifted by one byte.

    The reason is that there is a Framing/Break Error when Synchronization is not there. Thus the byte gets pushed but with the error flag set. The uDMA is not smart enough to understand that the error has occurred and hence the issue happens.

    How we debugged it: First cleared all the register status flags, did a CPU only reset in CCS and subsequently the program worked.

    Suggested solution:Use the Synchronization mechanism of the GPIO, or use the CPU to see if the Error Flag is set on Interrupt. If it is then flush the Error Byte and then enable the DMA to read the rest of the data.

    Regards

    Amit

  • Hey Amit,

    Thanks for the info.  I have been using the GPIO sync but i've been noticing the issue is still happening on some of the hardware.  I decided to try the second solution. Here are my interrupt handlers:

    //******************************************************************************
    // The interrupt handler for uDMA errors.  This interrupt will occur if the
    // uDMA encounters a bus error while trying to perform a transfer.  This
    // handler just increments a counter if an error occurs.
    //******************************************************************************
    void UartDmaErrorHandler(void) {
      uint32_t ui32Status;
    
      // Check for uDMA error bit
      ui32Status = uDMAErrorStatusGet();
    
      // If there is a uDMA error, then clear the error and increment
      // the error counter.
      if(ui32Status) {
        uDMAErrorStatusClear();
        dmaErrorCount++;
      }
    }
    
    //*****************************************************************************
    // The interrupt handler for UartDma.  This interrupt will occur when a DMA
    // transfer is complete using the uDMA channel. It will also be triggered if
    // the peripheral signals an error. This interrupt handler will fill a circular
    // buffer with incoming data. It will also disable uDMA for UART_TX
    // transmission as soon as a packet is sent (it is re-enabled on request by
    // UartDmaSendData()
    //*****************************************************************************
    void UartDmaIntHandler(void) {
      // Read the interrupt status of the UART.
      uint32_t ui32Status = UARTIntStatus(UART_BASE, 1);
    
      // Clear any pending status, even though there should be none since no UART
      // interrupts were enabled.  If UART error interrupts were enabled, then
      // those interrupts could occur here and should be handled.  Since uDMA is
      // used for both the RX and TX, then neither of those interrupts should be
      // enabled.
      UARTIntClear(UART_BASE, ui32Status);
    
      // If the DMA RX channel is diabled, that means the current receive buffer
      // is full.
      if(!uDMAChannelIsEnabled(UDMA_RX_CHANNEL)) {
        // Keep track of how many buffers we have filled
        rxBufferCount++;
    
        // Increment the buffer pointer
        if(++dmaBufferNum == RX_BUFFER_DEPTH)
          dmaBufferNum = 0;
        uDMAChannelTransferSet(UDMA_RX_CHANNEL | UDMA_PRI_SELECT,
                                   UDMA_MODE_BASIC,
                                   (void *)(UART_BASE + UART_O_DR),
                                   &rxBuffer[dmaBufferNum][0],
                                   sizeof(rxBuffer[dmaBufferNum]));
    
        // The uDMA RX channel must be re-enabled.
        uDMAChannelEnable(UDMA_RX_CHANNEL);
      }
    
      // If the  DMA TX channel is disabled, that means the TX DMA transfer
      // is done. We disable UART_DMA_TX here to prevent the UART from
      // continuously interrupting to request new data from the DMA. This will
      // be re-enabled in the UartDmaSendData() (when there is valid data to send)
      if (!uDMAChannelIsEnabled(UDMA_TX_CHANNEL)) {
        UARTDMADisable(UART_BASE, UART_DMA_TX);
      }
    }

    Here are my observations:

    • UdmaErrorHandler() is never fired (verified with breakpoint).
    • If I call the UdmaErrorHandler() function within UartDmaIntHandler() as the very first thing before anything else executes, the problem goes away (no shifting of data). However, the dmaErrorCount remains 0.
    • If I simply call uDMAErrorStatusGet() as the first thing inside UartDmaIntHandler(), the problem goes away. This is really strange as all that function does is read the error register.
    • If I simply read the register via HWREG(UDMA_ERRCLR) instead of uDMAErrorStatusGet(), the problem remains. Again... really strange behavior as this should be the same thing as calling uDMAErrorStatusGet(). Perhaps the act of putting the function on the stack impacts the timing or something.
    • Going with this thought, if I simply delay 1 microsecond (tried with 100 micro seconds as well), the problem remains.

    I'm really at a loss as to what's happening here.  For now I will simply leave the uDmaErrorStatusGet() in place inside my UartDmaIntHandler() as it appears to be working.... but I have no idea why.  Any thoughts?

    Steve

  • Hello Steve,

    The uDMA Error Handler is meant for the uDMA Error Interrupt. So as long as the Error is not seen by the uDMA due to a Bus Fault on a wrong address, the Interrupt will never be fired.

    Can you send the updated code "which does not work"?

    Regards

    Amit

  • Amit,

    I'm trying to use UART3 to communicate with an external peripheral using the DK-TM4C129x development kit. I've set up the uDMA controller to use channel 16 for for Rx (UDMA_CH16_UART3RX) and 17 for Tx (UDMA_CH17_UART3TX). I've used 1024-byte buffers for both transmit and receive (as we can only transfer 1024 "items" at a time) I've set up the FIFO levels for the UART to be 4/8 for transmit and receive and I've set the arbitration on the uDMA to 4 as well.

    When I run my application, I see no data transmitted from the dev kit, and data sent into the dev kit is not received at the uDMA.I can use UARTCharPutNonBlocking to transmit a character and I see that arrive at my external peripheral. I've got the external peripheral transmitting "Active" every two seconds but nothing appears to reach the uDMA.

    If I add uDMAChanelRequest for UDMA_CH16_UART3RX I do receive data, but the number of bytes received reflects the arbitration level I've used. For example, a level of four gives 1024 - 4 when I read uDMAChannelSizeGet and I can see "Acti" in my receive buffer, but an arbitration level to 512, gives 1024 - 512 and a receive buffer with "Active" followed by rubbish. If I add uDMAChanelRequest for UDMA_CH17_UART3TX as well I get nothing at all on transmit and receive.

    I've used exactly the same functional framework on UART0 for a two-way diagnostics port and I get no problems sending data between the dev kit and a PC. The only differences are the UART numbers, DMA channel numbers.

    I could go back to using individual character transmit and receive interrupts but I really need to use the uDMA as my application will be doing real-time waveform analysis so I would like the processor to manage the UARTs as much as possible.

    I would appreciate any help or insight you could provide.

    Thanks in advance,

    Dave

  • Hello Dave,

    That is a good description, but it would be great if you can share the code, including UART configuration, IO configuration and DMA configuration.

    Regards
    Amit
  • Amit,

    Really sorry for not posting a response - I've been out of the office for a couple of days,

    Bit of good news though, as my hardware designer noticed that the external peripheral I was talking to expected flow control to be active. I only had Tx and Rx connected from the DK-TM4C129x as we don;'t need the flow control to be active - schoolboy error!

    Now I've changed the receiver UART on the external peripheral to remove flow control, everything appears to be working properly.

    I would be more than happy to post my code if you think it would be helpful to others with similar problems.

    Thanks for your help,

    Dave

  • PS. There *was* an issue as I noticed that although UART3 Rx and Tx were selected for uDMA channels 16 & 17, I hadn't used uDMAChannelAssign to activate the channels. This must have been the major contributory factory to the DMA not working when a direct UART output would transmit.
  • Hello David

    Any code post on the forum that shows how to use the peripheral with external devices is an added resource. As a further note : There is an application note in the pipeline to cover a lot of aspects of using uDMA that the data sheet does not cover.

    Regards
    Amit
  • Amit,

    I've removed some of the non-relevant functions.

    I'm looking forward to the application note.

    Regards,

    Dave

    /* =============================================================================
     * Declare local data and constants (if required)
     * =============================================================================
     */
    
    // Pointer to the externally-managed application transmit message buffer
    uint8_T* ModemTransmitBuffer = NULL ;
    // Pointer to the externally-managed application transmit message length
    uint16_T* ModemTransmitLength = NULL ;
    // Pointer to the externally-managed application transmit complete flag
    boolean_T* ModemTransmitComplete = NULL ;
    
    // Pointer to the externally-managed application receive buffer
    uint8_T* ModemReceiveBuffer = NULL ;
    // Pointer to the externally-managed application receive byte count
    uint16_T* ModemReceiveLength = NULL ;
    // Pointer to the externally-managed application receive byte limit
    uint16_T* ModemReceiveLimit = NULL ;
    // Pointer to the externally-managed application receive complete flag
    boolean_T* ModemReceiveComplete = NULL ;
    
    // Index into the transmission buffer to indicate the next byte for transmission
    uint16_T ModemTransmitBufferPosition = 0 ;
    // Latched transmit length, in case the application changes the length
    uint16_T ModemLatchedTransmitLength = 0 ;
    
    // Count of the number of transmit messages for debug purposes
    uint32_T ModemTransmitMessageCount = 0 ;
    // Count of the number of recieve messages for debug purposes
    uint32_T ModemReceiveMessageCount = 0 ;
    
    // Tick timer used to determine whether the transmission of a message has stalled
    M03_strTickTimerData ModemTransmitTimer ;
    
    /*
     * =============================================================================
     *
     * Function Initialise Modem Channel
     * ---------------------------------
     *
     * This function sets up the processor configuration data for UART3. This
     * includes the baud rate, flow control and any TX/RX pin conditioning.
     *
     * =============================================================================
     * Inputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Outputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Returns
     * -----------------------------------------------------------------------------
     *
     * UART Identity
     *   
     * =============================================================================
     */
    
    void MLE_InitialiseModemChannel (void)
    {
      // Enable the UART and the peripheral interfaces that we'll need
    
      SysCtlPeripheralEnable (UART3_BASE) ;
    
      SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOJ) ;
      SysCtlPeripheralEnable (SYSCTL_PERIPH_UART3) ;
    
      // Set the GPIO pins to map onto the UART transmit and receive lines
    
      GPIOPinConfigure (GPIO_PJ0_U3RX) ;
      GPIOPinConfigure (GPIO_PJ1_U3TX) ;
    
      GPIOPinTypeUART (GPIO_PORTJ_BASE, GPIO_PIN_0 | GPIO_PIN_1) ;
    
      // Configure the UART communication parameters
    
      UARTConfigSetExpClk (UART3_BASE,
        M00_SysCtlClockFreq,
        115200,
        UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE) ;
    
      // Set both the TX and RX trigger thresholds to 4 - we need to make sure the
      // DMAs arbitrate at the same level
    
      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
    
      UARTEnable (UART3_BASE) ;
    
      UARTDMAEnable (UART3_BASE, UART_DMA_RX | UART_DMA_TX) ;
    
      // Set the DMA channel assignments for the UART. If we don't do this the DMA
      // won't operate
    
      uDMAChannelAssign (UDMA_CH16_UART3RX) ;
      uDMAChannelAssign (UDMA_CH17_UART3TX) ;
    
      // Put the attributes in a known state
    
      uDMAChannelAttributeDisable (UDMA_CH16_UART3RX,
        UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK) ;
      uDMAChannelAttributeDisable (UDMA_CH17_UART3TX,
        UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK) ;
    
      // Configure the control parameters to have a data size of a byte (8 bite) and an arbitration
      // size of 4 to match the FIFO trigger thresholds
    
      uDMAChannelControlSet (UDMA_CH16_UART3RX | UDMA_PRI_SELECT,
        UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4) ;
      uDMAChannelControlSet (UDMA_CH17_UART3TX | UDMA_PRI_SELECT,
        UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4) ;
    
      // Set up the receiver transfer here so we're actively listening for traffic. We won't
      // set the transmitter up as this will be done when we are asked to transmit by the rest
      // of the application
    
      uDMAChannelTransferSet (
        UDMA_CH16_UART3RX | UDMA_PRI_SELECT,
        UDMA_MODE_BASIC,
        (void*) (UART3_BASE + UART_O_DR),
        ModemReceiveBuffer,
        MAX_DMA_ITEMS) ;
    
      // Use a burst when transferring data from the TX buffer to the UART - DO NOT enable this for
      // the RX buffer as it appears to stop the UART receive FIFO being emptied
    
      uDMAChannelAttributeEnable (UDMA_CH17_UART3TX, UDMA_ATTR_USEBURST) ;
    
      // Start the receiver listening
    
      uDMAChannelEnable (UDMA_CH16_UART3RX) ;
    }
    
    /*
     * =============================================================================
     *
     * Function Initiate Modem Transmission
     * ------------------------------------
     *
     * This function initiates the transmission of a request message to the Modem.
     * It does this after ensuring that any previous message transmission has
     * completed.
     *
     * =============================================================================
     * Inputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Outputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Returns
     * -----------------------------------------------------------------------------
     *
     * Transmission has timed out
     *   
     * =============================================================================
     */
    
    boolean_T InitiateModemTransmission (void)
    {
      boolean_T TransmissionHasTimedOut = false ;
    
      // Wait for the last transmission to complete
    
      M03_strTickTimerData WaitForTransmissionTimer ;
    
      if (ModemTransmitComplete == NULL)
      {
        while (ModemTransmitLength == NULL) ;
      }
    
      M09_StartTickTimer (&WaitForTransmissionTimer, 1.0) ;
    
      while (!(*ModemTransmitComplete) && !M09_HasTickTimerExpired (&WaitForTransmissionTimer)) ;
    
      // If we didn't finish the transmission jump out. Any remedial action will
      // be taken by the calling function CBIT processing
    
      if (WaitForTransmissionTimer.RemainingTicks <= 0)
      {
        // Indicate that a timeout has occurred
    
        TransmissionHasTimedOut = true ;
    
        M99_LogEvent8 (M99_evUartRetransmission, 1) ;
      }
      else
      {
        // Display length and address on the instrumentation
    
        if ((ModemTransmitLength != NULL) && (ModemTransmitComplete != NULL))
        {
          static char_T MyStr [64] ;
    
          uint8_T MyLen = sprintf (MyStr, "Modem Transmit %d bytes from address 0x%08X", *ModemTransmitLength, (uint32_T) ModemTransmitBuffer) ;
    
          M99_LogString (MyStr, MyLen) ;
    
          /* Wait for the transmitter to become available */
    
          M09_StartTickTimer (&WaitForTransmissionTimer, 1.0) ;
    
          while (UARTBusy (UART3_BASE) && !M09_HasTickTimerExpired (&WaitForTransmissionTimer)) ;
    
          // If the UART transmitter wasn't ready jump out. Any remedial action will
          // be taken by the calling function CBIT processing
    
          if (WaitForTransmissionTimer.RemainingTicks <= 0)
          {
            // Indicate that a timeout has occurred
    
            TransmissionHasTimedOut = true ;
    
            M99_LogEvent8 (M99_evUartTransmitterNotReady, 1) ;
          }
          else
          {
            // Limit the length of the data logged to 128 bytes
    
            uint8_T AdjustedLength = (*ModemTransmitLength < 128) ? *ModemTransmitLength : 128 ;
    
            // Clear the transmit complete flags and start transmission from the beginning of the buffer
    
            *ModemTransmitComplete = false ;
            ModemTransmitBufferPosition = 0 ;
    
            // Start the transmit timer. We can use this to see whether the
            // transmission has completed in a timely manner
    
            M09_StartTickTimer (&ModemTransmitTimer, 10.0) ;
    
            // Latch the transmit length in case it's changed elsewhere
    
            ModemLatchedTransmitLength = *ModemTransmitLength ;
    
            // Send the message content out over the instrumentation link
    
            M99_LogSingleBinary (1) ;
            M99_LogMultiBinary ((uint8_T*) ModemTransmitBuffer, AdjustedLength) ;
    
            // Ready the DMA channel attached to the UART receiver
    
            uDMAChannelTransferSet (
              UDMA_CH16_UART3RX | UDMA_PRI_SELECT,
              UDMA_MODE_BASIC,
              (void *) (UART3_BASE + UART_O_DR),
              ModemReceiveBuffer,
              MAX_DMA_ITEMS) ;
    
            // Post the message to the DMA channel attached to the UART transmitter
    
            uDMAChannelTransferSet (
              UDMA_CH17_UART3TX | UDMA_PRI_SELECT,
              UDMA_MODE_BASIC,
              ModemTransmitBuffer,
              (void *) (UART3_BASE + UART_O_DR),
              *ModemTransmitLength) ;
    
            // Enable the DMA channels
    
            uDMAChannelEnable (UDMA_CH16_UART3RX) ;
            uDMAChannelEnable (UDMA_CH17_UART3TX) ;
          }
        }
      }
    
      return TransmissionHasTimedOut ;
    }
    
    /*
     * =============================================================================
     *
     * Function Initiate Modem Multi-Byte Transmission
     * -----------------------------------------------
     *
     * This function initiates the transmission of a multi-byte request message to
     * the Modem.
     *
     * =============================================================================
     * Inputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Outputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Returns
     * -----------------------------------------------------------------------------
     *
     * Transmission has timed out
     *   
     * =============================================================================
     */
    
    boolean_T MLE_InitiateModemMultiByteTransmission (void)
    {
      // Transmit the message as it is provided
    
      return InitiateModemTransmission() ;
    }
    
    /*
     * =============================================================================
     *
     * Function Initiate Modem Single Byte Transmission
     * ------------------------------------------------
     *
     * This function initiates the transmission of a single character to the Modem.
     *
     * =============================================================================
     * Inputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Outputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Returns
     * -----------------------------------------------------------------------------
     *
     * Transmission has timed out
     *   
     * =============================================================================
     */
    
    boolean_T MLE_InitiateModemSingleCharTransmission (uint8_T CharToTransmit)
    {
      // Load the single byte into the buffer
    
      ModemTransmitBuffer [0] = CharToTransmit ;
      *ModemTransmitLength = 1 ;
    
      // Transmit the single-byte message
    
      return InitiateModemTransmission() ;
    }
    
    /*
     * =============================================================================
     *
     * Function Monitor Modem UART
     * ---------------------------
     *
     * This function checks the progress of the Modem transmission and reception
     * activities. In the case of transmission, it ensures that the message hasn't
     * stalled.
     *
     * If the timer expires before transmission is complete, the transmission
     * complete flag is set to true and the transmit buffer is cleared. It is the
     * responsibility of the calling function to take remedial action.
     *
     * =============================================================================
     * Inputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Outputs
     * -----------------------------------------------------------------------------
     *
     * None
     *   
     * =============================================================================
     * Returns
     * -----------------------------------------------------------------------------
     *
     * Transmission has timed out
     *   
     * =============================================================================
     */
    
    void MLE_MonitorModemUart (void)
    {
      // Don't check anything until we've got some variables associated
    
      if (ModemTransmitComplete != NULL)
      {
        static uint16_T LastRxLength = MIN_uint16_T ;
    
        // The length of the response message is determined from the occupancy of the
        // DMA receive buffer. A stable length indicates that reception is finished
    
        *ModemReceiveLength = MAX_DMA_ITEMS - uDMAChannelSizeGet (UDMA_CH16_UART3RX) ;
    
        if (*ModemReceiveLength == LastRxLength)
        {
          if (*ModemReceiveLength > 0)
          {
            // If we haven't declared Rx Complete yet, we need to display the data
    
            if (!*ModemReceiveComplete)
            {
              uint16_T AdjustedLength = *ModemReceiveLength > 128 ? 128 : *ModemReceiveLength ;
    
              M99_LogSingleBinary (3) ;
              M99_LogMultiBinary ((uint8_T*) ModemReceiveBuffer, AdjustedLength) ;
            }
    
            // Increment the message receive count and flag reception complete
    
            ModemReceiveMessageCount++ ;
            *ModemReceiveComplete = true ;
          }
        }
    
        LastRxLength = *ModemReceiveLength ;
    
        // The "active" status of the transmit DMA channel tells us whether the
        // transmission has completed
    
        if (!*ModemTransmitComplete)
        {
          if (!uDMAChannelIsEnabled (UDMA_CH17_UART3TX))
          {
            // Increment the message Transmit count and flag transmission complete
    
            ModemTransmitMessageCount++ ;
            *ModemTransmitComplete = true ;
          }
        }
    
        // If we're waiting for transmit to complete check the timer
    
        if (!*ModemTransmitComplete)
        {
          if (M09_HasTickTimerExpired (&ModemTransmitTimer))
          {
            // The timer has expired so set transmit complete and zero the start of
            // the message
    
            *ModemTransmitComplete = true ;
            memset ((uint8_T*) ModemTransmitBuffer, 0, 20) ;
    
            // Indicate that a timeout has occurred
    
            M99_LogEvent8 (M99_evUartTransmitFailure, 1) ;
          }
        }
      }
    }
    
    

  • Hello Dave,

    Thanks. Do note that your inputs on what to add to the application note would be equally welcome.

    Regards
    Amit