你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32 HAL库使用SPI+DMA驱动WS2812优化方案  

[复制链接]
waiman 发布时间:2018-2-6 15:03
本帖最后由 waiman-156411 于 2018-2-6 17:57 编辑

看到zoomdy 的驱动例子启发 https://www.stmcu.org.cn/module/forum/thread-610279-1-1.html
效果虽然不错,可以节省不少MCU资源,但用一个byte的SPI数据代替WS2812一个bit,很浪费RAM资源,而且生成像素的效率也很慢。
2017-01-21 09_12_30的屏幕截图.png

仔细一看发现 WS2812一个bit 周期是:
         TH+TL=1250ns (±600ns), Min=650ns,Max=1850ns
如果把SPI提速到4Mbits/S 的时候,SPI一个bit的周期是250ns,刚好和符合WS2812 T0H或T1L 400ns ±150ns范围。SPI 4个bit的周期刚好1000ns,刚好可以满足WS2812的时序需求。
SPI=0x8 等于 WS2812的 0
SPI=0xE 等于  WS2812的 1
也就变成一个SPI的byte,可以表示2个Ws2812的2个bit。一RGB像素颜色只需要 24bit/2bit = 12byte


SPI速度及极性配置:
捕获.PNG


SPI只需要配置主机只发模式,这样可以节省一个IO口
捕获2.PNG

驱动整盘WS2812都很轻松
微信图片_20180206141317.jpg    微信图片_20180206135738.jpg

驱动库说明:
例子使用Stm32CubMx 4.23,STM32L151C8T6,IAR/MDK工程
程序移植了Adafruit NeoPixel库函数,
采用HAL库驱动方式(struct),可以方便移植到其他STM32芯片上,
只需要分配多个struct变量,硬件稍微改下,就能分时复用,控制多串灯珠。
捕获3.PNG


SPI_DMA_WS281X.rar

下载

584.49 KB, 下载次数: 1202

驱动库

评分

参与人数 4 ST金币 +16 收起 理由
yogolu + 5 赞一个!
hacker + 2 赞一个!
g921002 + 4 很给力!
Inc_brza + 5 赞一个!

查看全部评分

1 收藏 28 评论77 发布时间:2018-2-6 15:03

举报

77个回答
jjbboox 回答时间:2018-4-10 13:34:21
本帖最后由 jjbboox 于 2018-4-10 13:39 编辑
翱翔云端的鸟 发表于 2018-4-10 09:45
选择数据当做0码 1码的时候  是不是需要 首尾有限制

用3位代表1个bit通过SPI方式驱动WS2812时,SPI的速度请调整到2.25Mbps

以下是我用的代码,供你参考。ptr指向SPI Buf,value 是要转码的值。

  1. #define        PIXEL_BYTE_0        (0x92)                                //10010010
  2.         #define        PIXEL_BYTE_1        (0x49)                                //01001001
  3.         #define        PIXEL_BYTE_2        (0x24)                                //00100100

  4.         uint16_t ws2812_spi::setbuffer(){
  5.                 uint8_t *ptr = buf_ptr + 16;
  6.                 if(pixel_count == 0 || pixels == NULL || buf_ptr == NULL)
  7.                         return 0;
  8.                 else {
  9.                         for(int i = 0; i < pixel_count; i ++){
  10.                                 ptr = setPixelBuf(ptr, (pixels[i].green) * pixels[i].brightness / 0x100);
  11.                                 ptr = setPixelBuf(ptr, (pixels[i].red) * pixels[i].brightness / 0x100);
  12.                                 ptr = setPixelBuf(ptr, (pixels[i].blue) * pixels[i].brightness / 0x100);
  13.                         }
  14.                 }
  15.                 return (ptr - buf_ptr);
  16.         }

  17.         uint8_t* ws2812_spi::setPixelBuf(uint8_t *ptr, uint8_t value)
  18.         {
  19.                 ptr[0] = PIXEL_BYTE_0;
  20.                 ptr[1] = PIXEL_BYTE_1;
  21.                 ptr[2] = PIXEL_BYTE_2;

  22.                 ptr[0] |= (value & 0x80)?(0x40):0x00;
  23.                 value <<= 1;
  24.                 ptr[0] |= (value & 0x80)?(0x08):0x00;
  25.                 value <<= 1;
  26.                 ptr[0] |= (value & 0x80)?(0x01):0x00;
  27.                 value <<= 1;
  28.                 ptr[1] |= (value & 0x80)?(0x20):0x00;
  29.                 value <<= 1;
  30.                 ptr[1] |= (value & 0x80)?(0x04):0x00;
  31.                 value <<= 1;
  32.                 ptr[2] |= (value & 0x80)?(0x80):0x00;
  33.                 value <<= 1;
  34.                 ptr[2] |= (value & 0x80)?(0x10):0x00;
  35.                 value <<= 1;
  36.                 ptr[2] |= (value & 0x80)?(0x20):0x00;
  37.                 value <<= 1;

  38.                 return (ptr + 3);
  39.         }
复制代码


Yv-Yu 回答时间:2019-12-5 23:56:10
首先膜拜一下大佬,感谢大佬的分享,然后想请教一下各位,下面这段代码的实现是个啥意思啊,scale是干啥的啊?
void Sw28_SetBrightness(SW28_HandleTypeDef *swObj, uint8_t b)
{
    uint8_t newBrightness = b + 1;
    uint8_t  oldBrightness = swObj->Brightness - 1; // De-wrap old brightness value
    uint32_t c;
    uint16_t scale,i;
    if(newBrightness != swObj->Brightness)
      {    // Compare against prior value
            // Brightness has changed -- re-scale existing data in RAM

         if(oldBrightness == 0)
                scale = 0; // Avoid /0
         else if(b == 255)
                scale = 65535 / oldBrightness;
         else
                scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness;

        for(i=0; i<swObj->PixelLen; i++)
         {
            c = Sw28_GetPixelColor(swObj,i);        //获取16bit颜色  
            c = Sw28_ScaleColor(scale, c);
            Sw28_SetPixelsColor(swObj,i,c);//设置颜色
         }
        swObj->Brightness = newBrightness;
    }
}


翱翔云端的鸟 回答时间:2018-4-10 09:42:55
jjbboox 发表于 2018-4-10 07:30
是的,其实两头各还要加一个RESET信号,大概在32个字节左右吧。
比如8颗粒的灯条,那么分配的内存就应该是 ...

我现在遇到一个问题    3bit表示一个code     001  表示0code         110表示1code     
当我要发送9byte的一个24bit颜色值的时候  比如是传输红色
按照G R B  传输 为   0x00  0xFF  0x00   

转换为二进制
001 001 001 001 001 001 001 001 001 001 001
110 110 110 110 110 110 110 110 110 110 110
001 001 001 001 001 001 001 001 001 001 001

SPI数据为:
        0x24                0x92                0x49
0010 0100   1001 0010    0100 1001  
        0xDB                0x6D                0xB6
1101 1011   0110 1101    1011 0110
        0x24                0x92                0x49
0010 0100   1001 0010    0100 1001


这里的问题是当我SPI发送完0x24之后  发送0x92的时候  0x24的最后一位是0  0x92最后一位是1   导致0x24的最后一个0码和0x92的1码混合了  
七哥 回答时间:2018-2-6 15:43:14
这个思路很有想法,应该加精
waiman 回答时间:2018-2-6 17:56:19
楼上代码有个BUG,回去修改后再放上
waiman 回答时间:2018-2-6 21:28:57
修补改BUG后的代码:
SPI_DMA_WS281X.rar (584.8 KB, 下载次数: 916)
onev 回答时间:2018-2-8 11:17:30
我只想知道楼主图中的代码显示是MDK的还是其他文本编辑器的,如果是MDK的话配置高亮的配置文件是否可以发我一份?如果是文本编辑器看起来不像是vs code  更不是sublime text。
zero99 回答时间:2018-2-12 14:16:58
感谢分享,已汇总到2月技术原创  https://www.stmcu.org.cn/module/forum/thread-614799-1-1.html
waiman 回答时间:2018-2-13 01:05:25
onev 发表于 2018-2-8 11:17
我只想知道楼主图中的代码显示是MDK的还是其他文本编辑器的,如果是MDK的话配置高亮的配置文件是否可以发我 ...

mdk的,论坛里有人分享过了,你可以搜一下
Hackerpro 回答时间:2018-2-26 14:32:08
非常棒的想法,赞一个
jjbboox 回答时间:2018-2-26 15:14:01
厉害,这个帖子要收藏起来的。
好方法。
板子粉丝 回答时间:2018-2-28 09:36:53
先看看
jjbboox 回答时间:2018-3-1 09:35:48
很容易就实现了,非常方便,感谢楼主分享技术。
turingcode 回答时间:2018-3-5 00:36:15
学习学习啦啦啦啦
幻想卤蛋 回答时间:2018-3-7 22:11:47
谢谢楼主,学习下
xiaoxiao111 回答时间:2018-3-21 10:25:51
ertwhtrh
xujianhao 回答时间:2018-3-21 15:40:11
刚学,来看看

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版