STM32 HAL+PWM+DMA方式驱动WS2812灯珠波形分析

通过示波器观察PWM+DMA的方式驱动WS2812灯珠的波形及分析对应的现象

文章目录

    • 1. 在DMA传送完PWM波形后不关闭PWM的DMA输出
    • 2. 在DMA传送完PWM波形后,在PWM传输完成后回调函数中关闭PWM的DMA输出
    • 3. 在DMA传送完PWM波形后,在DMA中断函数中关闭PWM的DMA输出
    • 分析

1. 在DMA传送完PWM波形后不关闭PWM的DMA输出

灯珠显示效果:
灯珠会错乱显示(没有按正常设定的颜色显示)
示波器显示如下:
在这里插入图片描述

2. 在DMA传送完PWM波形后,在PWM传输完成后回调函数中关闭PWM的DMA输出

灯珠显示效果:
会按照设定的颜色正常显示,但灯带的起始位置会有绿色的余光(基于自己测试时使用的灯带)
示波器显示如下
在这里插入图片描述

3. 在DMA传送完PWM波形后,在DMA中断函数中关闭PWM的DMA输出

灯珠显示效果:
按照设定的颜色模式正常显示
示波器显示效果如下:
在这里插入图片描述

分析

方式1在pwm通过DMA的方式传输完成后会保持高电平,且会产生杂波,可能是导致灯珠显示错乱的主要原因.
方式2在DMA传输完成的回调函数关闭PWM输出,还会产生杂波,而将关闭PWM输出的函数放到DMA中断中便不会产生杂波,这个现象感觉很怪异,DMA中断函数HAL_DMA_IRQ()会调用传输完成的回调函数HAL_TIM_PWM_PulseFinishedCallback()但不知到为什么就不可以.

  • 会产生杂波的方式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 中断回调函数,在设定的pwm通过DMA发送完成后会调用 */
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef* htim)
{<!-- -->
  /*
  TODO:无论在这里是否关闭DMA输出,在PWM传输完成后都会产生一段杂波(用示波器看到的)。但是在这里关闭DMA输出后
       灯珠的颜色可以正常显示,杂波不会影响当前及后续灯珠的显示。但是在这里不关闭DMA输出,便会影响灯珠的显示。
      (不清楚原因)
  TODO:在DMA中断函数中关闭DMA输出便不会产生杂波
  */
  /* 注意这里的通道号要用 HAL_TIM_ACTIVE_CHANNEL_x而不能用TIM_CHANNEL_x,看定时器句柄定义的Channel类型便可知晓*/
  if(htim->Instance == TIM3) {<!-- -->
    if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {<!-- -->
      HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_1);
    } else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {<!-- -->
      HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_2);
    }  
  }
}
  • 不会产生杂波的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
  * @brief This function handles DMA1 stream4 global interrupt.
  */
void DMA1_Stream4_IRQHandler(void)
{<!-- -->
  HAL_DMA_IRQHandler(&hdma_tim3_ch1);
  /* 传输完成后,关闭DMA传输 */
  HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_1);
}
/**
  * @brief This function handles DMA1 stream5 global interrupt.
  */
void DMA1_Stream5_IRQHandler(void)
{<!-- -->
  HAL_DMA_IRQHandler(&hdma_tim3_ch2);
  /* 传输完成后,关闭DMA传输 */
  HAL_TIM_PWM_Stop_DMA(&htim3, TIM_CHANNEL_2);
 
}

感觉非常不能理解的一点是:HAL_DMA_IRQHandler()函数中会调用HAL_TIM_PWM_PulseFinishedCallback()函数,这就相当于产生杂波的方式比不产生杂波的方式提前调用了HAL_TIM_PWM_Stop_DMA()函数.

如有大佬知道,希望能够不吝赐教!