跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
折叠
品牌标识

YunTu Forum

YTMicro.com
  1. 主页
  2. Discussion & Question
  3. YT MCAL
  4. MCAL CddUart模块调用异步接收/发送函数时间过长优化方案

MCAL CddUart模块调用异步接收/发送函数时间过长优化方案

已定时 已固定 已锁定 已移动 YT MCAL
1 帖子 1 发布者 56 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • RuiXuR 离线
    RuiXuR 离线
    RuiXu YunTu
    编写于 最后由 编辑
    #1

    问题背景

    在CddUart模块中使用DMA的方式进行异步通信时,调用异步函数的API单次用时达30us,对于串口调用效率有较高的需求时,API调用时间过长。

    问题原因

    经测试发现,CddUart 在每次调用异步收发函数时,均通过 CddDma_SetLogicChannelTransfer 对 DMA 通道进行完整配置。CddDma_SetLogicChannelTransfer 调用链路如下:

    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
    

    每次发送/接收都重写 全部 DMA 寄存器,但其中大部分参数在整个生命周期中保持不变。
    使用CddDma_SetLogicChannelTransfer 优点在于与CddDma模块保持统一管理,可移植性变高,且遵循AUTOSAR的架构。但缺点是太多冗余代码,且CddDma_SetLogicChannelTransfer 函数内部有很多子函数跳转,这是消耗时间的主要原因。

    优化方案

    每次调用异步收发函数时,不再调用CddDma_SetLogicChannelTransfer ,而是通过直接修改寄存器的方式修改需要改变的参数。
    将 DMA 配置拆分为两个阶段:

    • Install(初始化阶段):在 LinFlexD_Lld_Init 中调用CddDma_SetLogicChannelTransfer ,完成全部 DMA 寄存器的一次性配置。
    • Update(运行时阶段):在每次收发时,仅通过直接寄存器写入更新变化参数。

    优化前后对比

    优化前:

    static CddUart_StatusType LinFlexD_Lld_StartSendUsingDma(...)
    {
        TxDmaTransferConfig = *DmaChannelTransferConfigArray[...]; // 拷贝模板
    
        UartState->TxBuff = TxBuff;
        UartState->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, &Base->DATA.DATA8[0], &TxDmaTransferConfig);
        }
        // else 16-bit 同理 ...
    
        CddDma_InstallCallback(...);     // 每次重新注册回调(冗余)
        CddDma_InstallErrorCallback(...);
        CddDma_StartChannel(...);
        // ...
    }
    

    优化后:

    static CddUart_StatusType LinFlexD_Lld_StartSendUsingDma(...)
    {
        volatile DMA_Type *DmaBase = DMA0;
        uint8 TxCh = (uint8)UartState->TxDMAChannel;
        uint32 TriggerCount;
    
        UartState->TxBuff = TxBuff;
        UartState->TxSize = TxSize;
        // ...
    
        if (/* 8-bit */) {
            TriggerCount = TxSize / (1U << DMA_TRANSFER_SIZE_1_BYTE);
            SchM_Enter_...();
            DmaBase->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);
        // 使能发送器 ...
    }
    

    优化结果

    优化后单次调用异步收发API从原来的30us降为10us。

    c910fbf5-b95e-4543-9fe8-aa96d550e096-image.png

    a94c7045-87d1-4f42-b16e-2c4840fe0d3f-image.png

    附上代码

    若有需要可直接替换此demo的 CddUart_Lld_LinFlexD.c
    适用版本: YTM32B1ME0/YTM32B1MD1 2_3_0
    CddUart_WithDma_Demo.zip

    1 条回复 最后回复
    1

  • 云途开发生态介绍

    快速上手云途开发生态

  • 云途论坛规则/Yuntu Forum Rules

    发帖前请查看

  • YT CONFIG TOOL调查问卷

    帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...

  • can
    25
    demo
    22
    lin stack
    13
    uds
    13
    md14
    6
    yt-link
    6
    fbl
    5
    adc模块
    4
    Online Users
    • 登录

    • 登录或注册以进行搜索。
    • 第一个帖子
      最后一个帖子
    0
    • 版块
    • 最新
    • 标签
    • 热门