礼亚 2024-05-21 15:39 采纳率: 0%
浏览 131
已结题

HC32L176调试了一个通过TIMER5+DMA驱动WS2812B

目前使用HC32L176调试了一个通过TIMER5+DMA驱动WS2812B的软件,现在出现一个问题是DMA更改占空比时会出现第一个占空比丢失的情况,比如DMA实际传输的占空比数据是[16,16,16,44,44,16,16,44,44],TIMER5实际输出的PWM波形会出现只有[16,16,16,44,16,44]这样的,每次占空比值变化时就会丢失第一个变化的占空比值。
哪位有用过HC32L176的TIMER5+DMA驱动WS2812B的,给个参考,谢谢。
补充下内容:

img

img

定时器和DMA初始化:
void BspLed_DmaInit()
{

stc_dma_cfg_t           stcDmaCfg;    

DDL_ZERO_STRUCT(stcDmaCfg);                     //结构体变量 初始值清零

// 使能 DMA时钟
Sysctrl_SetPeripheralGate(SysctrlPeripheralDma,TRUE);

stcDmaCfg.enMode =  DmaMskBlock;                            //选择块传输
stcDmaCfg.u16BlockSize = 0x01u;                             //块传输个数
stcDmaCfg.u16TransferCnt = 300;                           //Block模式,一次传输数据大小为 3,传输三次
stcDmaCfg.enTransferWidth = DmaMsk8Bit;                    //传输数据的宽度,此处选择字(32Bit)宽度
stcDmaCfg.enSrcAddrMode = DmaMskSrcAddrInc;                 //源地址自增
stcDmaCfg.enDstAddrMode = DmaMskDstAddrFix;                 //目的地址自增
stcDmaCfg.enDestAddrReloadCtl = DmaMskDstAddrReloadEnable; //禁止重新加载传输目的地址
stcDmaCfg.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable;   //使能重新加载传输源地址
stcDmaCfg.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable;      //使能重新加载BC/TC值
stcDmaCfg.u32SrcAddress = (uint32_t) (&tim5_ocl_pwmdmabuff[0]);//指定传输源地址
stcDmaCfg.u32DstAddress = (uint32_t)&M0P_ADTIM5->GCMBR;   //指定传输目的地址
//stcDmaCfg.u32DstAddress = (uint32_t)(&tim5_ocl_pwmdmabuff2[0]);   //指定传输目的地址
stcDmaCfg.enTransferMode = DmaMskOneTransfer;        //DMAC 在传输完成时不清除 CONFA:ENS 位。这个功能允许连续传输而不需要 CPU 干预。
stcDmaCfg.enRequestNum = DmaTIM5BTrig;                     //设置为ADC SQR触发

Dma_InitChannel(DmaCh0,&stcDmaCfg);       //初始化DMA通道0

}

void BspLed_AdvTimerInit(uint16_t u16Period,uint16_t u16CHB_PWMDuty)
{
en_adt_compare_t enAdtCompareB;

stc_adt_basecnt_cfg_t     stcAdtBaseCntCfg;
stc_adt_CHxX_port_cfg_t   stcAdtTIM5BCfg;
stc_adt_irq_trig_cfg_t    stcAdtTrigCfg;


DDL_ZERO_STRUCT(stcAdtBaseCntCfg);
DDL_ZERO_STRUCT(stcAdtTIM5BCfg);


Sysctrl_SetPeripheralGate(SysctrlPeripheralAdvTim, TRUE);    //ADT外设时钟使能

stcAdtBaseCntCfg.enCntMode = AdtSawtoothMode;                 //锯齿波模式
stcAdtBaseCntCfg.enCntDir = AdtCntUp;
stcAdtBaseCntCfg.enCntClkDiv = AdtClkPClk0;

Adt_Init(M0P_ADTIM5, &stcAdtBaseCntCfg);                      //ADT载波、计数模式、时钟配置

Adt_SetPeriod(M0P_ADTIM5, u16Period);                         //周期设置

enAdtCompareB = AdtCompareB;
Adt_SetCompareValue(M0P_ADTIM5, enAdtCompareB, u16CHB_PWMDuty);  //通用比较基准值寄存器B设置

stcAdtTIM5BCfg.enCap = AdtCHxCompareOutput;
stcAdtTIM5BCfg.bOutEn = TRUE;
stcAdtTIM5BCfg.enPerc = AdtCHxPeriodHigh;
stcAdtTIM5BCfg.enCmpc = AdtCHxCompareLow;
stcAdtTIM5BCfg.enStaStp = AdtCHxStateSelSS;
stcAdtTIM5BCfg.enStaOut = AdtCHxPortOutLow;
stcAdtTIM5BCfg.enStpOut = AdtCHxPortOutLow;
Adt_CHxXPortCfg(M0P_ADTIM5, AdtCHxB, &stcAdtTIM5BCfg);    //端口CHB配置

stcAdtTrigCfg.bAdtCntMatchBTrigDmaEn = TRUE;
Adt_IrqTrigCfg(M0P_ADTIM5,&stcAdtTrigCfg);

}

  • 写回答

24条回答 默认 最新

  • 阿里嘎多学长 2024-05-21 15:39
    关注
    获得0.15元问题酬金

    以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


    您想要解决的问题:

    您在调试HC32L176单片机时,使用TIMER5和DMA驱动WS2812B LED灯带时,遇到的问题是在DMA更改占空比时,TIMER5实际输出的PWM波形会丢失第一个变化的占空比值。

    问题出现原因:

    1. DMA传输同步问题:DMA在开始传输新的占空比数据时,可能存在同步问题,导致TIMER5没有正确地接收到第一个变化的占空比值。
    2. 缓冲区配置问题:DMA缓冲区可能没有正确配置,导致数据传输不连续或丢失。
    3. TIMER5配置问题:TIMER5的PWM配置可能存在问题,例如更新频率、触发DMA的条件等,导致无法正确反映DMA传输的数据。
    4. 中断处理问题:可能存在中断处理不当,导致在DMA传输和TIMER5更新之间出现冲突。

    问题解决方案:

    1. 检查DMA配置:确保DMA的配置正确,包括传输大小、源地址、目标地址以及传输触发条件等。
    2. 检查TIMER5配置:确保TIMER5的PWM配置正确,特别是与DMA传输同步的部分。
    3. 优化中断处理:如果使用了中断来处理DMA传输完成,确保中断服务程序能够正确处理并及时更新TIMER5的PWM输出。
    4. 使用软件触发:如果硬件触发存在问题,可以考虑使用软件触发TIMER5的PWM输出,以确保数据的连续性和准确性。

    提供代码:

    由于我无法提供具体的代码,因为需要针对您的硬件配置和软件环境进行定制,但我可以提供一个大致的代码框架,您可以根据这个框架调整您的代码。

    // 假设这是DMA传输完成的中断服务程序
    void DMA_TransferComplete_IRQHandler(void) {
        // 检查DMA传输状态
        if (DMA_GetFlagStatus(DMA1_Stream0, DMA_FLAG_TCIF0) != RESET) {
            // 清除DMA传输完成标志
            DMA_ClearFlag(DMA1_Stream0, DMA_FLAG_TCIF0);
            
            // 手动触发TIMER5的PWM更新(如果需要)
            // TIMER5_TriggerPWMUpdate();
        }
    }
    
    // 假设这是TIMER5的PWM配置函数
    void Configure_TIMER5_PWM(void) {
        // 配置TIMER5为PWM模式
        // ...
    }
    
    // 假设这是初始化DMA的函数
    void Init_DMA(void) {
        // 初始化DMA,设置源地址、目标地址、传输大小等
        // ...
    }
    
    void main(void) {
        // 初始化相关硬件
        Init_DMA();
        Configure_TIMER5_PWM();
        
        // 启动DMA传输
        // Start_DMA_Transfer();
        
        // 主循环
        while(1) {
            // 循环体
        }
    }
    

    代码运行方式:

    • 将上述代码框架根据您具体的硬件配置和软件环境进行调整。
    • 使用HC32L176的开发环境编译并下载到单片机中。
    • 运行程序,观察TIMER5的PWM输出是否正确。

    代码预期运行结果:

    如果代码正确配置,预期TIMER5将能够正确地输出PWM波形,不再丢失DMA传输的第一个变化的占空比值。

    推荐相关链接:

    1. HC32L176官方参考手册
    2. HC32L176 DMA配置指南
    3. WS2812B LED驱动原理
    4. 单片机PWM控制LED灯带教程

    请注意,这些链接是示例性的,您需要根据实际情况查找和验证相关信息。

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 5月29日
  • 修改了问题 5月21日
  • 创建了问题 5月21日