gmyu 发表于 2018-8-15 14:51:49

stm32和ws2812B相对较好的方案。SPI和UART

最近看不少人玩ws2812b。我搜了一下找到个比较好的。
这个程序是spi+dma的,我修改了下在F030F4上面跑着挺好。大概的意思是E表示1。8表示0。一个字节处理两位。

我想了一下UART+DMA,没有时间做。如果用UART,设置到2.4M,每个位400nS(spec.: 250-550),反转一下,每三位处理一个bit,高高低表示1(800+400),低低高表示0(800+400)。 这样start+76位,543,210,总共一个字节处理3个位,停止位因为反转了就是低电平,间隔时间不足50uS,应该没影响。
如此,每24/3=8个字节处理一个灯,比SPI的12个字节更少。个位有什么看法。

yoursnemo 发表于 2018-8-15 15:30:56

直接用IO,写得我要吐了。

Eiman 发表于 2018-8-15 15:38:26

uart还是比较复杂的吧,有校验位停止位什么的,还是PWM+DMA最直接明了。

amazing030 发表于 2018-8-15 15:40:59

SPI的方式不错,速度慢的单片机都可以做

lyg407 发表于 2018-8-15 15:48:48

谢谢楼主分享。

gmyu 发表于 2018-8-15 16:00:27

Eiman 发表于 2018-8-15 15:38
uart还是比较复杂的吧,有校验位停止位什么的,还是PWM+DMA最直接明了。

校验位可以没有的,电压反转后,开始位必须是高,和2812协议相同,停止位作为间隔可以忽略。

想问一下pwm占用多少RAM和CPU资源。是不是整个DMA发送完成才需要CPU参与一次,论坛那位貌似现在没搞定,不知卡在哪里。

Eiman 发表于 2018-8-15 16:18:47

gmyu 发表于 2018-8-15 16:00
校验位可以没有的,电压反转后,开始位必须是高,和2812协议相同,停止位作为间隔可以忽略。

想问一下pw ...

我的是PWM+DMA点亮60个WS2812B没问题啊。
占用空间如下:
8 808 bytes of readonlycode memory
    352 bytes of readonlydata memory
5 554 bytes of readwrite data memory

gmyu 发表于 2018-8-16 11:35:31

Eiman 发表于 2018-8-15 16:18
我的是PWM+DMA点亮60个WS2812B没问题啊。
占用空间如下:
8 808 bytes of readonlycode memory


我用F030F4,只有4K RAM, 你这个远远超出,假定100个灯,100*2*24就4.8k了,而用SPI就只需要100*12=1.2kbyte。 这个差距还是比较大的,毕竟还要做各种效果,加上buffer就更不敢用pwm了。

20061002838 发表于 2018-8-16 17:10:01

发送一个LED的数据所需要的时间是 1.25*24 = 32us
而CPU生成数据所需的时间远远小于32us
那么就有了使用双缓冲,乒乓操作的条件
两个缓冲区,每个缓冲区处理25个LED,总共占用RAM:SPI 25*12*2 = 600bytes; USART 25*24*2 = 1200bytes,而且扩展到更长的灯带时不需要增加缓冲区长度
DMA传输完成中断产生后,最后两个个字节(SPI是半字)数据一个在移位寄存器中发送,另一个在TDR寄存器中等待发送,中断函数里面等待TXE标志位置位,重新配置DMA

gmyu 发表于 2018-8-16 17:24:53

20061002838 发表于 2018-8-16 17:10
发送一个LED的数据所需要的时间是 1.25*24 = 32us
而CPU生成数据所需的时间远远小于32us
那么就有了使用双 ...

不用缓冲区,直接写DMA的buff会出现什么情况。基本上写buff很短时间,可以在刷新ws2812的时候做。或者就算正在发送spi,更新dma数据区会怎么样。

你已经用UART实现了,对么?貌似是一个bit对一个字节。

20061002838 发表于 2018-8-16 17:39:54

gmyu 发表于 2018-8-16 17:24
不用缓冲区,直接写DMA的buff会出现什么情况。基本上写buff很短时间,可以在刷新ws2812的时候做。或者就 ...

不用双缓冲,直接写DMA的buf,不就把正在发送的数据给破坏了吗

没玩过WS2812,UART是前两天给坛友设计的一个方案,很容易可以翻到,用USART,同步模式,外部用D触发器,通过时钟信号锁存数据
没验证过

gmyu 发表于 2018-8-16 18:13:05

20061002838 发表于 2018-8-16 17:39
不用双缓冲,直接写DMA的buf,不就把正在发送的数据给破坏了吗

没玩过WS2812,UART是前两天给坛友设计的 ...

我上面说了,TX反转电平,加开始位可以看作9个bit,这样可以处理3个LED位,不用外接器件,不过没有试过。

btw,上面的程序我运行有点问题,颜色编码通常是rgb,但是ws2812用的是gbr,他虽然做了处理,但是颜色不对。
改了一下这个函数,把循环也去掉,运行可能快点。
void Sw28_SetPixelsColor(SW28_HandleTypeDef *swObj, uint8_t pix, uint32_t color)
{
    uint8_t g; //r,g,b;
    uint8_t        *pb = swObj->BuffPoint + pix*12;

                        g= (uint8_t)(color>>8);
                        *pb++ = LED2B; g >>= 2;
                        *pb++ = LED2B; g >>= 2;
                        *pb++ = LED2B; g >>= 2;
                        *pb = LED2B;
                        g= (uint8_t)(color>>16);
                        *pb++ = LED2B; g >>= 2;
                        *pb++ = LED2B; g >>= 2;
                        *pb++ = LED2B; g >>= 2;
                        *pb = LED2B;
                        g= (uint8_t)(color);
                        *pb++ = LED2B; g >>= 2;
                        *pb++ = LED2B; g >>= 2;
                        *pb++ = LED2B; g >>= 2;
                        *pb = LED2B;
}

20061002838 发表于 2018-8-16 18:20:45

本帖最后由 20061002838 于 2018-8-16 18:25 编辑

gmyu 发表于 2018-8-16 18:13
我上面说了,TX反转电平,加开始位可以看作9个bit,这样可以处理3个LED位,不用外接器件,不过没有试过。 ...

查表最快,没有之一

看错了,你这个就是查表

gmyu 发表于 2018-8-16 18:41:12

本帖最后由 gmyu 于 2018-8-16 18:43 编辑

20061002838 发表于 2018-8-16 18:20
查表最快,没有之一

看错了,你这个就是查表

请问,查表返回的一个32bit常量放到8位数组buffer里面,那种方法最快?谢谢!

20061002838 发表于 2018-8-16 18:47:42

gmyu 发表于 2018-8-16 18:41
请问,查表返回的一个32bit常量放到8位数组buffer里面,那种方法最快?谢谢!...

指针,强制类型转换
void WS2812b_Display(void)
{
    registerunsigned long i;
    registerunsigned char temp = 0;

    registerunsigned short const *pSrc;
    registerunsigned short*pDrc;

    register unsigned short b1, b2, b3;

    pDrc = (unsigned short *)spi_SendBuf;

    for (i = 0; i < 48; i++)//轮询像素缓存区
    {
      temp = ws2812b_PixBuf >> 4;

      pSrc = (unsigned short const *)LUTbl;

      b1 = *pSrc++;
      b2 = *pSrc++;
      b3 = *pSrc++;

      *pDrc++ = b1;
      *pDrc++ = b2;
      *pDrc++ = b3;

      temp = ws2812b_PixBuf & 0x0F;

      pSrc = (unsigned short const *)LUTbl;

      b1 = *pSrc++;
      b2 = *pSrc++;
      b3 = *pSrc++;

      *pDrc++ = b1;
      *pDrc++ = b2;
      *pDrc++ = b3;

    }
#if 0   
    DMA_Cmd(DMA1_Channel3, DISABLE);
    DMA_ClearFlag(DMA1_FLAG_TC3);
    DMA1_Channel3->CNDTR = SENDLENGTH;
    DMA_Cmd(DMA1_Channel3, ENABLE);
#endif   
}

gmyu 发表于 2018-8-16 19:20:06

20061002838 发表于 2018-8-16 18:47
指针,强制类型转换





对C++不熟悉,高手可以移植这个到stm32就好了,我在arduino下运行很炫,53种模式,可扩展性很强,如果用systick处理里面的step,延时也不消耗cpu资源了。

Eiman 发表于 2018-8-17 09:56:31

gmyu 发表于 2018-8-16 11:35
我用F030F4,只有4K RAM, 你这个远远超出,假定100个灯,100*2*24就4.8k了,而用SPI就只需要100*12=1.2k ...

100灯也就100*24就可以了,我用了5K多主要是我没省着用,还用了HSB颜色空间转换保存每一个灯的参数。

gmyu 发表于 2018-8-17 10:36:25

Eiman 发表于 2018-8-17 09:56
100灯也就100*24就可以了,我用了5K多主要是我没省着用,还用了HSB颜色空间转换保存每一个灯的参数。 ...

pwm dma data你用的是16位还是8位?

Eiman 发表于 2018-8-17 11:26:48

gmyu 发表于 2018-8-17 10:36
pwm dma data你用的是16位还是8位?

是哦,一时没想起来。

ljx289 发表于 2018-8-22 08:40:49

stm32的io需要电平转换吗?ws2812是5V的,要3.5V才算高。我现在是把ws2812的vcc通过5V串1N4007后将为4.3V。你们是怎么做啊?

gmyu 发表于 2018-8-22 08:51:46

3.5才算高? 我直接连的。正常。

ljx289 发表于 2018-8-23 01:08:56

资料上写的是0.7倍的VCC才是高电平的啊吧?

LiLi-Long 发表于 2018-9-10 21:28:45

学习中 谢谢

weatt123456789 发表于 2018-10-30 03:53:19

Eiman 发表于 2018-8-15 15:38
uart还是比较复杂的吧,有校验位停止位什么的,还是PWM+DMA最直接明了。

我用stc的PWM好像有点搞不定,好像30M情况下,37个周器,进中断再处理就超过了

Eiman 发表于 2018-10-30 09:27:10

weatt123456789 发表于 2018-10-30 03:53
我用stc的PWM好像有点搞不定,好像30M情况下,37个周器,进中断再处理就超过了 ...

所以用DMA处理就简单些

weatt123456789 发表于 2018-11-3 18:45:39

为什么不用PWM呢

huangqi412 发表于 2018-11-3 19:02:39

楼主最后结果呢

gmyu 发表于 2018-11-3 19:15:51

UART没用,因为换207资源大大的有了。

clesun 发表于 2019-1-11 11:58:31

gmyu 发表于 2018-11-3 19:15
UART没用,因为换207资源大大的有了。

莫名碰到WS2812该亮得时候不亮,不亮得时候瞎亮

clesun 发表于 2019-1-11 12:00:01

gmyu 发表于 2018-11-3 19:15
UART没用,因为换207资源大大的有了。

不知道是不是0码和1码配置得问题。用的是SPI接口。

huarana 发表于 2019-1-11 12:22:36

有没有人搞过w2812做成点阵显示酷炫特效的?

不知道能否实现,就是类似跳舞机那种

ylshuan0221 发表于 2019-1-25 10:09:23

了解一下!!

一切那么自然 发表于 2019-2-16 13:48:44

20061002838 发表于 2018-8-16 18:47
指针,强制类型转换

STM32F103可以实现控制1024个灯珠?

smilelinux 发表于 2019-4-24 23:54:10

你的SPI接哪呢?简易的电路图有吗?或者说明一下接法。

gmyu 发表于 2019-4-26 09:57:45

smilelinux 发表于 2019-4-24 23:54
你的SPI接哪呢?简易的电路图有吗?或者说明一下接法。

sdo到2812的data脚

dragonbbc 发表于 2019-4-26 10:03:48

mark一下,空了画个电路板试试

yongd 发表于 2019-11-18 23:08:57

楼主,没看到你程序里面WS2812B的RESET信号怎么产生

gmyu 发表于 2022-10-14 16:06:57

花了一天在arm926上用UART dma实现了。每个UART发3个bits。24bits需要8个串口bytes。
下面是查表转颜色到UART数据。
UINT8 RGB2UART[] = {0xDB,0x9B,0xD3,0x93,0xDA,0x9A,0xD2,0x92};

void Send_24b_1LED(UINT8* Led_Arr, UINT32 u32color)
{UINT8 u8bit3,u8color;
        for(UINT8 i = 0; i<8; i++){
                u8color = (UINT8)(u32color >> (21-3*i));//先高后低G-R-B
                u8bit3 = u8color & 0x7 ;
                * (Led_Arr+i) = RGB2UART;

}
}

这个内存有64M,所以再不用考虑内存了,开两个buff采用乒乓的形式去刷新。

gmyu 发表于 2022-10-14 16:14:06

改了一下,把乘法那个去掉了。
void Send_24b_1LED(UINT8* Led_Arr, UINT32 u32color)
{UINT8 u8bit3,u8shift;
        u8shift = 21;
        for(UINT8 i = 0; i<8; i++){
                u8bit3 = ((UINT8)(u32color >> u8shift)) & 0x7;//
                u8shift -= 3;
                * (Led_Arr+i) = RGB2UART;

}
}

gmyu 发表于 2022-10-15 11:58:36

https://github.com/lamik/WS2812B_STM32_HAL
https://blog.csdn.net/Tkwer/article/details/104740550
别人的移植

zhcj66 发表于 2022-10-15 16:15:14

gmyu 发表于 2022-10-15 11:58
https://github.com/lamik/WS2812B_STM32_HAL
https://blog.csdn.net/Tkwer/article/details/104740550
别 ...
(引用自40楼)

看网上视频有用8s003做的很炫的,不知道咋搞出来的,我 感觉我的45MHz频率都吃力
页: [1]
查看完整版本: stm32和ws2812B相对较好的方案。SPI和UART