DMA+Timer 产生 PWM 多出一个波形问题

我在调试ws2812的时候,发现灯光的数据一直和预想的不符合,简化了程序逻辑依然看不出有什么问题,最后通过逻辑分析仪发现,PWM多出了一个波形,明显的,这导致所有的数据错了一位。

事实上这不是硬件上的BUG,猜测原因:因为每一次DMA请求是Timer的溢出中断产生的,所以在DMA请求前,就已经有一个PWM产生了,那么从时序看上,就多出一个PWM波形,但这并不是DMA产生的。

问题回顾

uint16_t test_arr[48] = {
                         59,29,59,59,59,59,59,59,\
                         29,29,29,29,29,29,29,29,\
                         29,29,29,29,29,29,29,29,\
                         \
                         29,29,29,29,29,29,29,29,\
                         29,29,29,29,29,29,29,29,\
                         59,59,59,59,59,59,59,59,\
                         \
                         };

HAL_TIM_PWM_Start_DMA(&htim1,TIM_CHANNEL_1,(uint32_t *)test_arr,(48));

在上面的程序中,按道理应该产生48个波形,但是我却观察到了49个,而且第一个波形是第二个数组的值决定的。也就是说,他似乎搬运的数组为:

uint16_t test_arr[48] = {
                      29,59,29,59,59,59,59,59,59,\
                         29,29,29,29,29,29,29,29,\
                         29,29,29,29,29,29,29,29,\
                         \
                         29,29,29,29,29,29,29,29,\
                         29,29,29,29,29,29,29,29,\
                         59,59,59,59,59,59,59,59,\
                         \
                         };

一开始我用的是数据填充函数出现是数据错位问题,所以我用了以上这种原始数组的方式,排除我数据填充函数的逻辑错误,后来才发现,当DMA传输结束以后,会继续新的传输,然后产生一个中断,当DMA完成中断被调用时候,DMA已经搬运到第二个值了,所以此时,定时器的占空比就为第二个值。

解决思路

如果需要定时器不要产生一个波形,那么只需要根据情况,在DMA完成中断以后,通过把占空比设置为0或者0xFF,让其下次的波形为高电平或者是低电平即可。

记录一个,未知原因 BUG

  • 数组越界?
  • 堆栈溢出?

在测试过程中,还发现一个奇怪的问题,以下程序仍然可以产生多一个PWM波形:

volatile int cnt = 0;
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{ 
    cnt++;
    if(cnt == 2)
    {
        cnt = 0; 
    }
    
    HAL_TIM_PWM_Stop_DMA(&htim1,TIM_CHANNEL_1);
   __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,0);
}

void HAL_TIM_PWM_PulseFinishedHalfCpltCallback(TIM_HandleTypeDef *htim)
{   
    cnt++; 
}

这段程序多了一个cnt++计数,我做了一些测试,发现这个bug产生的条件比较苛刻,必须同时满足:

  • 半传输中断中有:cnt++语句
  • if 必须判断 cnt == 2,2 改成 4 BUG 消失
  • if 内必须是 cnt = 0 ,改成 1 或 2 BUG 消失

程序还包含一些其他测试语句,删除以后发现这个 BUG 消失了,或许是数组越界问题?

链接:https://pan.baidu.com/s/1tKbzexqTrQnzxDw7hWXJJg
提取码:n7u6

经过进一步的测试,源文件存在两个192 x 2 字节的大数组:

uint16_t pulse[192] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
                       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
                         \
                         59,59,59,59,59,59,59,59,\
                         29,29,29,29,29,29,29,29,\
                         29,29,29,29,29,29,29,29,\
                         \
                         29,29,29,29,29,29,29,29,\
                         59,59,59,59,59,59,59,59,\
                         29,29,29,29,29,29,29,29,\
                         \
                         29,29,29,29,29,29,29,29,\
                         29,29,29,29,29,29,29,29,\
                         59,59,59,59,59,59,59,59,\
                         \
                         59,59,59,59,59,59,59,59,\
                         59,59,59,59,59,59,59,59,\
                         29,29,29,29,29,29,29,29,

                       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\
                       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint16_t data[192];

其中,删除掉 pulse[192]数组即可(不删除pulse[]而换作删除 data[] 则不行) = =!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值