我在调试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,让其下次的波形为高电平或者是低电平即可。
在测试过程中,还发现一个奇怪的问题,以下程序仍然可以产生多一个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[] 则不行) = =!