STM32 G431RB 中实现对WS2812灯带的控制(PWM + DMA)

项目中需要对WS2812灯带进行控制,项目中的灯带是21颗等,需求要求对所有的LED等设置颜色的时候是统一的颜色,

如果需要设置不同的颜色,也可以参考代码进行修改。

实现方式是 PWM + DMA的方式,一次将21颗灯的颜色值都设定好。

参考的是这篇英文文章来实现的。 Interface WS2812 with STM32(https://controllerstech.com/interface-ws2812-with-stm32/)

我的代码实放在Github上了。 https://github.com/magicduan/demo_pwm_dma

我的板子是G431RB,处理上稍微有些不同,详细的原理等就不在这里说明了,这里整理一下按照这个参考例子开发出的问题。

  • Direction需要设置为 "Memory To Peripheral",也就是将Memory的内容搬运到PWM寄存器中。开始设置的时候没有注意,时间浪费了。
  • Mode 设置为"Normal", 有的例子文章说要设置为"Circular". "Normal"与"Circular"的区别是,"Normal" Mode下DMA搬运完数据后就不再自动继续搬了,“Circular” Mode会自动的循环搬运数据
  • 英文文章中Data Width 是Peripheral :Half Word, Memory:Half Word. 选Half Word的原因是PWM的Counter Period是16 bit的。我之前是参考英文文章做的,这样处理没有什么问题,就是PWM 的Buffer的需要用uint16_t保存Duty Value。而我的Counter Period是(75-1),也就是最大值是75,使用uint8_t就可以,这样能节省一半的内存。  由于其他代码的需要我这边的代码的实际处理是 Presaler = 15-1, Counter Period = 5-1. 

              

 

  • 由于我Memory的Data Width是Byte,这里就碰见了字节对齐问题
  • Buffer声明的时候需要边界对齐
  • #define DMA_TYPE  uint8_t
    __attribute__((aligned(4))) volatile  DMA_TYPE pwm_buffer[BUFFER_LEN];

     

  • 今天碰见一个巨大的坑,STM32 CubeIDE生成代码的时候有Bug,在main函数中DMA初始化顺序与TIM的初始化顺序的问题,STM32 CubeIDE有时候生成的是反的,反了DMA执行就会被卡在,执行不成功。花了很长时间比较代码才找出来。具体的原因参考这篇CSD的文章(STM32 DMA传输的Bug)
  • 正常顺序:
  •   MX_DMA_Init();
      MX_TIM1_Init();

    错误顺序:

  • MX_TIM1_Init();  
    MX_DMA_Init();

     

 

posted @ 2022-01-11 19:25  magicduan  阅读(1182)  评论(0编辑  收藏  举报