<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[MCAL CddUart模块调用异步接收&#x2F;发送函数时间过长优化方案]]></title><description><![CDATA[<h2>问题背景</h2>
<p dir="auto">在CddUart模块中使用DMA的方式进行异步通信时，调用异步函数的API单次用时达30us，对于串口调用效率有较高的需求时，API调用时间过长。</p>
<h2>问题原因</h2>
<p dir="auto">经测试发现，CddUart 在每次调用异步收发函数时，均通过 CddDma_SetLogicChannelTransfer 对 DMA 通道进行完整配置。CddDma_SetLogicChannelTransfer 调用链路如下：</p>
<pre><code>CddDma_SetLogicChannelTransfer()
  └── Dma_Lld_SetChannelTransfer()
        └── Dma_Lld_PushConfigToReg()     // 写入全部 CTS 寄存器
              ├── DMA_CTSSetEngineStall()        // CSR
              ├── DMA_CTSSetSrcAddr()            // SADDR
              ├── DMA_CTSSetDestAddr()           // DADDR
              ├── DMA_CTSSetAttribute()          // TCR
              ├── DMA_CTSSetSrcOffset()          // SOFF
              ├── DMA_CTSSetDestOffset()         // DOFF
              ├── DMA_CTSSetSrcLastAdjust()      // STO
              ├── DMA_CTSSetDestLastAdjust / RAM reload  // DTO_RLD
              ├── DMA_SetErrorIntCmd()           // CHEIE
              ├── DMA_CTSSetMajorCompleteIntCmd() // CSR
              ├── DMA_CTSSetSrcMinorLoopOffsetCmd() // BCNT.LOEN
              ├── DMA_CTSSetDstMinorLoopOffsetCmd() // BCNT.LOEN
              ├── DMA_CTSSetTransferLoopOffset() // BCNT.LOEN
              ├── DMA_CTSSetNbytes()             // BCNT
              ├── DMA_CTSSetChannelLoopLink()    // TCNTRV/TCNT
              ├── DMA_CTSSetChannelTriggerLink() // CSR
              ├── DMA_CTSSetTriggerCount()       // TCNTRV/TCNT
              └── DMA_DisDmaReqAfterCTSDoneCmd() // CSR
</code></pre>
<p dir="auto">每次发送/接收都重写 全部 DMA 寄存器，但其中大部分参数在整个生命周期中保持不变。<br />
使用CddDma_SetLogicChannelTransfer 优点在于与CddDma模块保持统一管理，可移植性变高，且遵循AUTOSAR的架构。但缺点是太多冗余代码，且CddDma_SetLogicChannelTransfer 函数内部有很多子函数跳转，这是消耗时间的主要原因。</p>
<h2>优化方案</h2>
<p dir="auto">每次调用异步收发函数时，不再调用CddDma_SetLogicChannelTransfer ，而是通过直接修改寄存器的方式修改需要改变的参数。<br />
将 DMA 配置拆分为两个阶段：</p>
<ul>
<li>Install（初始化阶段）：在 <code>LinFlexD_Lld_Init</code> 中调用CddDma_SetLogicChannelTransfer ，完成全部 DMA 寄存器的一次性配置。</li>
<li>Update（运行时阶段）：在每次收发时，仅通过直接寄存器写入更新变化参数。</li>
</ul>
<h2>优化前后对比</h2>
<p dir="auto">优化前：</p>
<pre><code>static CddUart_StatusType LinFlexD_Lld_StartSendUsingDma(...)
{
    TxDmaTransferConfig = *DmaChannelTransferConfigArray[...]; // 拷贝模板

    UartState-&gt;TxBuff = TxBuff;
    UartState-&gt;TxSize = TxSize;
    // ...

    if (/* 8-bit */) {
        SchM_Enter_...();
        TxDmaTransferConfig.SrcTransferSize = ...;  // 冗余
        TxDmaTransferConfig.DestTransferSize = ...; // 冗余
        TxDmaTransferConfig.SrcOffset = ...;        // 冗余
        TxDmaTransferConfig.DestOffset = ...;       // 冗余
        TxDmaTransferConfig.TransferLoopByteCount = ...; // 冗余
#if YTM32
        // Dummy 通道全量重配（冗余）
        DummyDmaTransferConfig.SrcTransferSize = ...;
        // ... 约 15 行冗余代码 ...
        CddDma_SetLogicChannelTransfer(DummyChannel, ...);
#endif
        SchM_Exit_...();
        CddDma_SetLogicChannelTransfer(TxChannel, // 写入全部寄存器
            TxBuff, &amp;Base-&gt;DATA.DATA8[0], &amp;TxDmaTransferConfig);
    }
    // else 16-bit 同理 ...

    CddDma_InstallCallback(...);     // 每次重新注册回调（冗余）
    CddDma_InstallErrorCallback(...);
    CddDma_StartChannel(...);
    // ...
}
</code></pre>
<p dir="auto">优化后：</p>
<pre><code>static CddUart_StatusType LinFlexD_Lld_StartSendUsingDma(...)
{
    volatile DMA_Type *DmaBase = DMA0;
    uint8 TxCh = (uint8)UartState-&gt;TxDMAChannel;
    uint32 TriggerCount;

    UartState-&gt;TxBuff = TxBuff;
    UartState-&gt;TxSize = TxSize;
    // ...

    if (/* 8-bit */) {
        TriggerCount = TxSize / (1U &lt;&lt; DMA_TRANSFER_SIZE_1_BYTE);
        SchM_Enter_...();
        DmaBase-&gt;CTS[TxCh].SADDR = (uint32)TxBuff;  // ← 直接写 SADDR
        LinFlexD_Lld_SetDmaTriggerCount(DmaBase, TxCh, TriggerCount); // ← 直接写 TCNTRV/TCNT
#if YTM32
        LinFlexD_Lld_SetDmaTriggerCount(DmaBase, DummyChannel, TriggerCount);
#endif
        SchM_Exit_...();
    }
    // else 16-bit 同理 ...

    CddDma_StartChannel(TxChannel);
    // 使能发送器 ...
}
</code></pre>
<h2>优化结果</h2>
<p dir="auto"><strong>优化后单次调用异步收发API从原来的30us降为10us。</strong></p>
<p dir="auto"><img src="https://yt-static-main.oss-cn-shanghai.aliyuncs.com/nodebb/242/5a91c21a-39f2-4683-93d4-20c10290f1e7.png" alt="c910fbf5-b95e-4543-9fe8-aa96d550e096-image.png" class=" img-fluid img-markdown" /></p>
<p dir="auto"><img src="https://yt-static-main.oss-cn-shanghai.aliyuncs.com/nodebb/242/ffa5c617-c14c-4e25-8d73-54797e657f20.png" alt="a94c7045-87d1-4f42-b16e-2c4840fe0d3f-image.png" class=" img-fluid img-markdown" /></p>
<h2>附上代码</h2>
<p dir="auto">若有需要可直接替换此demo的 <strong>CddUart_Lld_LinFlexD.c</strong><br />
适用版本： <strong>YTM32B1ME0/YTM32B1MD1   2_3_0</strong><br />
<a href="https://yt-static-main.oss-cn-shanghai.aliyuncs.com/nodebb/242/e2647a43-c7b9-4040-ad08-5f4ed6ff80fe.zip" rel="nofollow ugc">CddUart_WithDma_Demo.zip</a></p>
]]></description><link>https://forum.ytmicro.com/topic/1973/mcal-cdduart模块调用异步接收-发送函数时间过长优化方案</link><generator>RSS for Node</generator><lastBuildDate>Wed, 27 May 2026 19:08:22 GMT</lastBuildDate><atom:link href="https://forum.ytmicro.com/topic/1973.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 26 May 2026 07:20:41 GMT</pubDate><ttl>60</ttl></channel></rss>