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:使用 DMA 进行 SCI 接收

Guru**** 2680595 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1589476/tms570ls3137-sci-reception-with-dma

器件型号: TMS570LS3137

SCI UART 接收的 DMA 配置丢失。

我在中断模式下遇到 SCI 接收的时序问题。 由于 SCI 没有任何 FIFO、我想使用 DMA 提高性能并避免数据丢失。

UART 可能会接收具有不同字节长度的消息、我没有找到可以定义传输开始时的一种超时的 DMA 通道设置。

我猜是使用多个链入一个环的 DMA 通道、但它无法按预期工作。

这是我的 DMA 初始化和中断代码:

#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 );
}

 

使用 DMA 进行传输可以正常工作、但无法正常接收。 我始终获得第一个接收字节。

有人能告诉我我出了什么问题吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、

    您能否请参考下面的 SPI DMA 示例一次?

    (+)【常见问题解答】TMS570LC4357:适用于 Hercules 控制器的示例和演示(例如 TMS570x、RM57x 和 RM46x 等)-基于 Arm 的微控制器论坛 — 基于 Arm 的微控制器 — TI E2E 支持论坛

    还请参考以下示例:

    e2e.ti.com/.../1362.SCI_5F00_Multibuffer_5F00_DMA_5F00_LS3137.zip

    这两个示例都经过测试、因此请参考一次并进行必要的更改。 如果它无法解决您的问题、我将对您的问题进行进一步调试。

    --
    此致、
    Jagadish。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、很抱歉、您稍后回复。

    我已经看到了此示例、但此示例适用于 SCI2/LIN、并使用 SCI1 上不提供的多缓冲器模式。

    我发现一个“几乎“起作用的解决方案:我必须 dmaGroupANotification() 像这样添加 DMA 端口 B 标志重置:

    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 );
    }

    我遇到的唯一问题是第一个字节丢失/无效。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好 Fabrice Mousset 

    我遇到的唯一问题是第一个字节丢失/无效。  [/报价]

    您是指在串行分析器(例如 Tera Term)中发现第一个字节丢失/无效?

    是否可以共享您的代码?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    很抱歉、这是我这边的解释错误、实际上队列中接收/存储的第一个字节是两次。

    代码很难从应用中提取、但主题中提供了主要部分。

    这是什么意思 SCI_SET_RX_DMA_ALL呢?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    顺便说一下、flag 的含义是什么 SCI_SET_RX_DMA_ALL

    该标志在中特别有用 地址位多处理器模式 、其中帧具有额外的地址位。 地址位设置为 1 的帧是地址帧、而地址位设置为 0 的帧是数据帧。

    SCI_SET_RX_DMA_ALL标志(也称为 SET_RX_DMA_ALL) 是中的一个控制位 SCISETINT 寄存器  该控制多处理器通信模式下 SCI(串行通信接口)模块的 DMA 请求生成行为。

    SET_RX_DMA_ALL位与该SET_RX_DMA位结合使用、以控制何时为生成接收 DMA 请求 帧的映射 数据帧 在多处理器模式下:

    SET_RX_DMA_ALL= 1 且SET_RX_DMA= 1 时:

    • 为生成接收 DMA 请求 地址帧和数据帧 当 SCI 设置 RXRDY 标志时

    SET_RX_DMA_ALL= 0 且SET_RX_DMA= 1 时:

    • 生成接收 DMA 请求 仅适用于数据帧 (非地址帧):SCI 在接收到数据帧时设置 RXRDY 标志
    • 为地址帧生成接收中断请求