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.

TMS570LS3137: SCI reception with DMA

Part Number: TMS570LS3137

I am getting lost with DMA configuration for the SCI UART reception.

I have timing issue with SCI reception in interrupt mode. As SCI do not have any FIFO, I want to use DMA to gain performances and avoid data lost.

The UART may receive messages with various byte length and I don't have found a DMA channel settings which I could define a kind of timeout when transfer is started.

My guess was to use multiple DMA channels chained in a ring, but it does not work as I am expected.

Here is my DMA initialization and interrupt code:

#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
#define SCI_TX_ADDR ((uint32_t)(&(sciREG->TD)))
#define SCI_RX_ADDR ((uint32_t)(&(sciREG->RD)))
#else
#define SCI_TX_ADDR ((uint32_t)(&(sciREG->TD)) + 3)
#define SCI_RX_ADDR ((uint32_t)(&(sciREG->RD)) + 3)
#endif

#define SCI_SET_TX_DMA          (1<<16)
#define SCI_SET_RX_DMA          (1<<17)
#define SCI_SET_RX_DMA_ALL      (1<<18)
#define SCI_TX_DMA_CH           DMA_CH0
#define SCI_RX_DMA_COUNT        (4u)
#define SCI_RX_DMA_CH_FIRST     (SCI_TX_DMA_CH + 1)
#define SCI_RX_DMA_CH_LAST      (SCI_RX_DMA_CH_FIRST + SCI_RX_DMA_COUNT)

#define DMA_LIN_RX              (28u)
#define DMA_LIN_TX              (29u)
#define DMA_SCI_RX              (30u)
#define DMA_SCI_TX              (31u)
#define SERIAL_DMA_BUFF_SIZE    (UART_MAX_MSG_LEN)

 uint8_t serial_Rx_buf[SCI_RX_DMA_COUNT];
g_dmaCTRL g_dmaCTRLPKT_Rx[SCI_RX_DMA_COUNT];

void serial_dma_init(void)
{
    int i;
    g_dmaCTRL *dmactrl = g_dmaCTRLPKT_Rx;

    for(i = 0; i < SCI_RX_DMA_COUNT; ++i, ++dmactrl)
    {
        dmactrl->SADD      = SCI_RX_ADDR;             /* source address               */
        dmactrl->DADD      = (uint32)(serial_Rx_buf+i); /* destination  address         */
        dmactrl->CHCTRL    = (SCI_RX_DMA_CH_FIRST + ((i + 1) % SCI_RX_DMA_COUNT)) + 1;               /* next channel to be triggered */
        dmactrl->FRCNT     = 1;                       /* frame count                  */
        dmactrl->ELCNT     = 1;                       /* element count                */
        dmactrl->ELDOFFSET = 0;                       /* element destination offset   */
        dmactrl->ELSOFFSET = 0;                       /* element destination offset   */
        dmactrl->FRDOFFSET = 0;                       /* frame destination offset     */
        dmactrl->FRSOFFSET = 0;                       /* frame destination offset     */
        dmactrl->PORTASGN  = 4;                       /* port b                       */
        dmactrl->RDSIZE    = ACCESS_8_BIT;            /* read size                    */
        dmactrl->WRSIZE    = ACCESS_8_BIT;            /* write size                   */
        dmactrl->TTYPE     = FRAME_TRANSFER;          /* transfer type                */
        dmactrl->ADDMODERD = ADDR_FIXED;              /* address mode read            */
        dmactrl->ADDMODEWR = ADDR_FIXED;              /* address mode write           */
        dmactrl->AUTOINIT  = AUTOINIT_OFF;            /* autoinit                     */

        dmaSetCtrlPacket(SCI_RX_DMA_CH_FIRST+i, dmactrl);
        dmaEnableInterrupt(SCI_RX_DMA_CH_FIRST+i, BTC);
        dmaSetChEnable(SCI_RX_DMA_CH_FIRST+i, DMA_HW);
        dmaReqAssign(SCI_RX_DMA_CH_FIRST+i, DMA_SCI_RX);
    }

   sciREG->SETINT |= SCI_SET_RX_DMA  | SCI_SET_RX_DMA_ALL;

   dmaEnable();
}


void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
{
    static portBASE_TYPE xHigherPriorityTaskWoken;
    static uint8_t byte;

    xHigherPriorityTaskWoken = pdFALSE;
    switch(channel)
    {
    case SCI_TX_DMA_CH:
        xSemaphoreGiveFromISR(uart_tx_sema4, &xHigherPriorityTaskWoken);
        break;

    case SCI_RX_DMA_CH_FIRST:
    case SCI_RX_DMA_CH_FIRST+1:
    case SCI_RX_DMA_CH_FIRST+2:
    case SCI_RX_DMA_CH_FIRST+3:
        byte = serial_Rx_buf[channel-SCI_RX_DMA_CH_FIRST];
        xQueueSendFromISR(xRxedChars, &byte, &xHigherPriorityTaskWoken );
        dmaSetChEnable(channel, DMA_HW);
        break;
    }

    // If xHigherPriorityTaskWoken is now set to pdTRUE then a context
    // switch should be requested.  The macro used is port specific and
    // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
    // refer to the documentation page for the port being used.
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

 

The transmission with DMA works fine, but not the reception. I always get the first received byte.

Can someone tell me what I am doing wrong?

  • Hi,

    Could you please refer below SPI DMA example once?

    (+) [FAQ] TMS570LC4357: Examples and Demos available for Hercules Controllers (E.g. TMS570x, RM57x and RM46x etc) - Arm-based microcontrollers forum - Arm-based microcontrollers - TI E2E support forums

    And also refer below example as well:

    1362.SCI_Multibuffer_DMA_LS3137.zip

    These two are tested examples, so please refer them once and make necessary changes. If it doesn't solve your issue, then i will debug further on your issue.

    --
    Thanks & regards,
    Jagadish.

  • Hi and sorry for the late reply,

    I already have seen this example but this example is for SCI2/LIN and uses Multi-Buffer mode which is not available on SCI1.

    I found an "almost" working solution: I had to add DMA port B flag reset in dmaGroupANotification() like this:

    void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
    {
        static portBASE_TYPE xHigherPriorityTaskWoken;
        static uint8_t byte;
    
        xHigherPriorityTaskWoken = pdFALSE;
        switch(channel)
        {
        case SCI_TX_DMA_CH:
            xSemaphoreGiveFromISR(uart_tx_sema4, &xHigherPriorityTaskWoken);
            dmaREG->BTCFLAG |= (1 << channel);
            break;
    
        case SCI_RX_DMA_CH_FIRST:
        case SCI_RX_DMA_CH_FIRST+1:
        case SCI_RX_DMA_CH_FIRST+2:
        case SCI_RX_DMA_CH_FIRST+3:
            byte = serial_Rx_buf[channel-SCI_RX_DMA_CH_FIRST];
            xQueueSendFromISR(xRxedChars, &byte, &xHigherPriorityTaskWoken );
            dmaREG->BTCFLAG |= (1 << channel);
            dmaSetChEnable(channel, DMA_HW);
            break;
        }
    
        // If xHigherPriorityTaskWoken is now set to pdTRUE then a context
        // switch should be requested.  The macro used is port specific and
        // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
        // refer to the documentation page for the port being used.
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }

    This only issue I had is that the first byte is lost / not valid. 

  • Hi  

    This only issue I had is that the first byte is lost / not valid. 

    You mean in serial analyzer (E.g. Tera Term) you found first byte is lost/not valid?

    Is it possible to share your code?

  • Sorry it was an interpretation error of my side, in fact the first byte received/stored in queue twice.

    Code is hard to extract from my application, but the main part is given in this thread.

    By the way, what is the meaning of flag SCI_SET_RX_DMA_ALL?

  • By the way, what is the meaning of flag SCI_SET_RX_DMA_ALL?

    This flag is particularly useful in address-bit multiprocessor mode, where frames have an extra address bit. A frame with the address bit set to 1 is an address frame, while a frame with the address bit set to 0 is a data frame.

    the SCI_SET_RX_DMA_ALL flag (also referred to as SET_RX_DMA_ALL) is a control bit in the SCISETINT register that controls DMA request generation behavior for the SCI (Serial Communications Interface) module in multiprocessor communication modes.

    The SET_RX_DMA_ALL bit works in conjunction with the SET_RX_DMA bit to control when receive DMA requests are generated for address frames versus data frames in multiprocessor modes:

    When SET_RX_DMA_ALL = 1 and SET_RX_DMA = 1:

    • A receive DMA request is generated for both address frames AND data frames when the SCI sets the RXRDY flag

    When SET_RX_DMA_ALL = 0 and SET_RX_DMA = 1:

    • A receive DMA request is generated only for data frames (not address frames) when the SCI sets the RXRDY flag upon receipt of a data frame
    • Receive interrupt requests are generated for address frames