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.

[参考译文] TMS570LC4357:TMS570LC4357:不带 IRQ 和可变数据包长度的 SCI DMA RX

Guru**** 2885180 points

Other Parts Discussed in Thread: TMS570LC4357

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1627259/tms570lc4357-tms570lc4357-sci-dma-rx-without-irq-and-variable-packet-lengths

器件型号: TMS570LC4357

您好:

我正在 TMS570LC4357 评估板上工作、并针对可变字节长度数据包开发无中断 SCI1 RX DMA 接口。 我阅读并知道这张票证、其中提到该器件不支持接收可变数据包长度: https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/838614/tms570lc4357-how-to-configure-sci-dma-for-receiving-varying-sized-packets

 

不过、我尝试了 WCP CTCOUNT 的一个简单测试、我可以看到、在 DMA 接收到一些字节后、它会得到更新。 我能够使用它来跟踪我是否收到了新的字节、但是除非发生新的 DMA 触发、否则它不会更新、因此在仲裁之前它始终保存过时的值。

 

我通过了这个 TT、其中提到使用 Porta/B TR Count 来了解收到了多少字节: https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1237441/sci-with-dma/4681424?tisearch=e2e-sitesearch&keymatch=%22DMA%22%20AND%20%22length%22%20AND%20%22dynamic%22%20AND%20%22Jagadish%22

 

不过、我观察到端口 A/B 值始终反映 DMA 计划执行的当前传输。 在可能的情况下、我将多个 DMA 通道与不同的外设一起使用、如何使用端口 A/B TR 计数来了解我在特定 SCI RX DMA 通道上接收到了多少个字节?  我尝试使用 FIFOSTAT 寄存器、但它们在收到字节时也不会更新。  

 

从我在论坛上阅读的其他门票,我知道使用协议是使这项工作的唯一方法,但是,我想知道 FIFO TR 或 WCP CNT 是否可以使它实际工作。

 

此致、

Surabhi

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

    感谢您的答复。

    我发现您的解决方案 “具有最少中断的混合方法“很有意思。 您能否详细说明一下如何使用超时中断实现 SCI RX?

    另外、如果超时 IRQ 能够检测数据包结束条件、我们如何知道接收的字节数(或要复制的字节数)?

    谢谢、
    Surabhi

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

    您好、Surabhi、

    使用 DMA 实现 SCI RX 超时中断

    配置 SCI RX 超时中断

    当 RX 线路在指定的时间段内空闲时、将触发超时中断。 下面介绍了如何实现它:

    硬件配置

    ```c
    //假设使用 TI TMS570 或类似的具有 SCI 超时功能的 MCU

    void SCI_ConfigureRxTimeout (scibase_t *sci、uint32_t timeout_bits)

    //启用超时功能
    //超时值通常以位时间为单位(例如 8-16 位周期)
    SC->SETINTTIMEOUT = TIMEOUT_BITS;//示例:10 位时间

    //启用超时中断
    SCI->SETINT = SCI_RX_INT_TIMEOUT;

    //清除任何挂起的超时标志
    SCI->FLG = SCI_RX_INT_TIMEOUT;
    }

    void SCI_void (Init_With_Timeout)

    //标准 SCI 初始化
    sciInit();

    //配置为 115200 波特、8N1
    sciSetBaudrate (sciREG1115200);

    //将超时设置为~10 位时间
    //这意味着如果 10 个位周期内没有数据到达、则会触发超时
    SCI_ConfigureRxTimeout (sciREG1、10);

    //启用 SCI 和 RX
    sciREG1->GCR1 |= 0x80;//启用 SCI
    sciREG1->SETINT |= 0x200;//启用 RX 超时中断
    }
    ```μ s

    超时计算

    ```c
    //对于给定的波特率、计算相应的超时值
    //超时应> 1 个字符的时间但<预期的数据包间隙

    uint32_t Calculate_Timeout_Value (uint32_t baudrate、浮点 char_times)

    //每个字符= 10 位(1 个开始位+ 8 个数据位+ 1 个停止位)
    //以位时间表示的超时= char_times * 10.

    //示例:任何波特率下均需要 1.5 个字符
    return (uint32_t)(char_times * 10.0f);
    }

    //用法:
    //用于在 1.5 个字符静音后检测数据包结束:
    uint32_t TIMEOUT = Calculate_Timeout_Value (115200、1.5);
    ```μ s

    2.确定接收的字节数

    这是关键部分! 以下是几种方法:

    方法 A:使用 DMA 计数器(最常见)

    ```c
    #define RX_BUFFER_SIZE 256

    uint8_t rx_buffer[RX_BUFFER_SIZE];
    易失性 uint32_t packet_size = 0;

    void SETUP_DMA_FOR_RX (void)

    //为 SCI RX 配置 DMA 通道
    dmaChannel_t dma_cfg;

    dma_cfg.Sadd =(uint32_t)&sciREG1->RD;//源:SCI RX 寄存器
    dma_cfg.dadd =(uint32_t) rx_buffer;// Dest:我们的缓冲区
    DMA_cfg.CHCTRL = 0;//禁用自动初始化
    dma_cfg.FRCNT = RX_BUFFER_SIZE;//帧计数(要接收的字节)
    dma_cfg.ELCNT = 1;//元素计数
    dma_cfg.ELDOFFSET = 0;
    DMA_cfg.FRDOFFSET = 0;
    DMA_cfg.PORTASGn = PORTA_READ_PORTB_WRITE;

    dmaSetChEnable (DMA_CH0、DMA_HW);
    dmaSetChannel (DMA_CH0、DMA_cfg);
    }

    void SCI_Timeout_ISR (void)

    //读取 DMA 传输计数器以查看剩余多少个字节
    uint32_t bytes_remaining = dmaGetTransferCount (DMA_CH0);

    //计算实际接收的字节
    packet_size = RX_BUFFER_SIZE - bytes_remaining;

    //清除超时标志
    sciREG1->FLG = SCI_RX_INT_TIMEOUT;

    //向应用程序发出数据包就绪的信号
    //(设置标志,后信标等)
    packet_ready_flag = 1;

    //为下一个数据包重置 DMA
    SETUP_DMA_FOR_RX ();
    }

    //应用程序代码
    void Process_Packets (void)

    IF (packet_ready_flag)

    packet_ready_flag = 0;

    //现在我们确切地知道收到了多少个字节
    Process_Data (rx_buffer、packet_size);
    }
    }
    ```μ s

    方法 B:具有指针跟踪功能的双缓冲器

    ```c
    #define BUFFER_SIZE 256

    uint8_t rx_buffer_a[buffer_size];
    uint8_t rx_buffer_B[buffer_size];
    uint8_t *active_buffer = rx_buffer_a;
    uint8_t *proce_buffer = NULL;

    易失性 uint32_t received_COUNT = 0;

    void SETUP_DMA_Circular (void)

    // DMA 写入 ACTIVE_BUFFER
    //在超时时、我们交换缓冲区

    dmaChannel_t dma_cfg;
    dma_cfg.Sadd =(uint32_t)&sciREG1->RD;
    dma_cfg.dadd =(uint32_t) active_buffer;
    dma_cfg.FRCNT = BUFFER_SIZE;

    dmaSetChannel (DMA_CH0、DMA_cfg);
    }

    void SCI_Timeout_ISR (void)

    uint32_t bytes_remaining = dmaGetTransferCount (DMA_CH0);
    received_count = buffer_size - bytes_remaining;

    //交换缓冲区
    PROCESSOR_BUFFER = ACTIVE_BUFFER;
    active_buffer =(active_buffer == rx_buffer_a)? rx_buffer_B:rx_buffer_a;

    //将 DMA 重新配置为新缓冲区
    dmaSetDestAddr (DMA_CH0、(uint32_t) ACTIVE_BUFFER);
    dmaSetTransferCount (DMA_CH0、BUFFER_SIZE);

    //清除标志和信号应用
    sciREG1->FLG = SCI_RX_INT_TIMEOUT;
    packet_ready_flag = 1;
    }
    ```μ s

    方法 C:使用硬件字节计数器(如果可用)

    ```c
    //某些 MCU 有一个硬件字节计数器寄存器

    void SCI_Timeout_ISR (void)

    //读取硬件字节计数器(特定于 MCU)
    packet_size = sciREG1->byte_count;//假设寄存器

    //或使用 DMA 传输完成计数
    PACKET_SIZE = DMA_CH0->BTCNT;//传输的字节计数

    //清除并继续
    sciREG1->FLG = SCI_RX_INT_TIMEOUT;
    packet_ready_flag = 1;
    }
    ```μ s

    完成工作示例

    下面是一个完整的实现:

    ```c
    #define RX_BUFFER_SIZE 512
    #define TIMEOUT_BIT 15 //~1.5 个字符时间

    uint8_t rx_buffer[RX_BUFFER_SIZE];
    易失性 uint32_t packet_length = 0;
    易失性 uint8_t packet_ready = 0;

    void Init_SCI_DMA_void (With_Timeout)

    // 1。 初始化 SCI
    sciInit();
    sciSetBaudrate (sciREG1115200);

    // 2. 配置超时
    sciREG1->TIMEOUT_CTRL = TIMEOUT_BITS;
    sciREG1->SETINT |= SCI_TIMEOUT_INT;

    // 3. 设置 DMA
    dmaChannel_t DMA_CONFIG ={
    .sadd =(uint32_t)&sciREG1->RD、
    .dadd =(uint32_t) rx_buffer、
    .FRCNT = RX_BUFFER_SIZE、
    .ELCNT = 1、
    .CHCTRL = 0、
    .PORTASGN = PORTA_READ_PORTB_WRITE
    };

    dmaSetChannel (DMA_CH0、DMA_CONFIG);
    dmaSetChEnable (DMA_CH0、DMA_HW);

    // 4. 启用中断
    vimEnableInterrupt (SCI_TIMEOUT_INT_CHANNEL、SYS_IRQ);

    // 5. 启动 SCI
    sciREG1->GCR1 |= 0x80;
    }

    #pragma 中断 (SCI_IRQ、Timeout_Handler)
    void SCI_void (Timeout_Handler)

    //从 DMA 获取剩余计数
    uint32_t remaining = dmaREG->BTCR[DMA_CH0];

    //计算接收的字节
    Packet_length = RX_BUFFER_SIZE - remaining;

    //仅当我们收到数据时才进行处理
    if (packet_length > 0)

    packet_ready = 1;

    //暂时停止 DMA
    dmaSetChEnable (DMA_CH0、DMA_SW);

    //将在处理后重新启动
    }

    //清除超时标志
    sciREG1->FLG = SCI_TIMEOUT_FLAG;
    }

    void Main_Task (void)

    INIT_SCI_DMA_DMA With_Timeout ();

    while (1)

    if (packet_ready)

    //处理接收到的数据包
    Process_Packet (rx_buffer、packet_length);

    //重置下一个数据包
    packet_ready = 0;
    Packet_length = 0;

    //重新启动 DMA
    dmaSetTransferCount (DMA_CH0、RX_BUFFER_SIZE);
    dmaSetChEnable (DMA_CH0、DMA_HW);
    }

    //其他任务...
    }
    }
    ```μ s

    要点

    1.**超时检测**:当 RX 线路在指定的位时间内处于空闲状态时、硬件会自动检测
    2.**字节计数**:读取 DMA 计数器寄存器以确定`bytes_received = buffer_size - bytes_remaining`
    3.**最低开销**:每个数据包只有一个中断、而不是每个字节
    4.**可靠**:硬件超时比软件轮询更准确

    这种方法通过可靠的数据包边界检测提高了 DMA 的效率!

    --
    此致、
    Jagadish。

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

    尊敬的 Jagadish:

    感谢你的详细答复和花时间分析我的意见--我感谢你的努力。

    我想阐明一个具体要点、并使其与我在 TRM 和硬件上看到的内容保持一致。

    SCI 超时/空闲中断支持

    重新查看 TMS570LC43x 技术参考手册 和 SCI 寄存器映射后、我看不 到此器件上对可编程 SCI RX 超时中断的支持。

    具体来说:

    • SCI 模块中没有用于配置 RX 不活动超时(例如,静音 N 位时间后超时)的寄存器。
    • SCI 中断源限制为 RX 就绪、TX 就绪、错误条件、唤醒/空闲检测和中断检测。
    • 唤醒/空闲检测机制看起来基于状态、适用于地址标记或低功耗唤醒用途、不适用于可编程的数据包结束超时检测、并且它与任何可配置的计数器无关。

    我无法在 SCIGCRxSCISETINTSCIFLR或相关 SCI 寄存器中找到任何与超时相关的位或计数器、它们的行为类似于真正的 RX 超时中断。

    DMA + WCP/传输计数观察

    如前所述、我的测试确认:

    • WCP.CTCOUNT 仅在对 DMA 通道进行仲裁时更新。
    • 对于多个有效 DMA 通道、即使 SCI RX 数据继续到达、该值也可能保持过时。
    • 端口 A/B 传输计数寄存器反映 配置的 传输大小、而不是已经接收的字节数。

    因此、我仍然无法可靠地确定 SCI RX DMA 通道在任何给定时间实际传输了多少个字节、 SCI 硬件本身似乎也没有提供一种机制来指示数据包结束或 不活动而不中断或协议帧。

    因此、我的问题是:
    TMS570LC4357 上是否有任何硬件支持方法来确定除了固定长度 DMA 传输、协议级分隔符或中断之外的 SCI RX DMA 进度或数据包完成情况?
    到目前为止、我还没有在 TRM 中或通过实验找到它。

    结论

    基于上述内容、我目前的理解是:

    • TMS570LC4357 支持硬件中的 SCI RX 超时中断。
    • 使用 DMA 的可变长度 SCI RX 似乎需要以下任一条件:
      • 协议级分隔符或长度字段、或
      • 使用 SCI 或 DMA 中断来检测数据包边界。

    如果我错过了支持此用例的特定寄存器、勘误表注释或记录机制、我非常希望找到指向确切 TRM 部分或寄存器说明的指针、以便我能进行查看。

    再次感谢您的时间和指导。

    此致、
    Surabhi

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

    您好、Surabhi、

    对延迟的回复表示歉意!

    [引述 userid=“690006“ url=“~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1627259/tms570lc4357-tms570lc4357-sci-dma-rx-without-irq-and-variable-packet-lengths/6319313
    • TMS570LC4357 支持硬件中的 SCI RX 超时中断。
    • 使用 DMA 的可变长度 SCI RX 似乎需要以下任一条件:
      • 协议级分隔符或长度字段、或
      • 使用 SCI 或 DMA 中断来检测数据包边界。
    [/报价]

    你的理解是完全正确的。

    您也可以参考以下主题进行相同确认:

    (+) TMS570LC4357-TMS570LC4357 EP—是否存在空闲线路 RX 中断? -基于 Arm 的微控制器论坛 — 基于 Arm 的微控制器 — TI E2E 支持论坛

    --
    此致、
    Jagadish。