|
本帖最后由 t3486784401 于 2015-11-17 12:26 编辑
【背景】
前段时间跟着双十一的节奏,剁手收获了一大批乱七八糟的零件模块,WS2812灯串就是这其中之一。
本来想要买四脚版本的WS2812S,但是店里偏偏只有六脚版的WS2812搞活动,无奈买来几个玩玩。
相对于普通LED,这玩意真心不便宜,一块8灯串的模块就要¥10大洋,总之买来是这样的(背面焊了插座):
网上关于WS2812的驱动,通篇都是 Arduino/ARM/FPGA,既然这样说明 AVR 驱动这玩意还是有望的。
至于 Arduino 怎么做我也没去研究,只是觉着这个事情应该不至于困难到举步维艰的地步。
【C级分析】
看了手册后发现,WS2812的传输码率约为800kbps,直接拿AVR做C语言级别的循环,基本没戏,原因如下:
1. 我板子是 7.3728M 主频的,C转一圈几十个时钟周期松松的(移位、循环判断),直接分频至不到700k;
2. 写驱动就要有通用性,如果都用直接指令写死了(减少移位等运算),那这驱动也就没意义了;
3. AVR没有锁相环诶(PLL),这个在ARM里用烂了的东西,这里不能用了,而且AVR最快也就16M不能瞎搞了。
上述分析,被我第一版纯C的程序证实了:即使数据循环逻辑都对,比特间也有us级的延时,LED失控瞎JB亮。
【汇编分析】
本来就已放弃,打算某日换STM32再战,不想无意中算了下周期,发现很有趣的事情:
1. WS2812规定:逻辑1:H/L=0.85us/0.4us,逻辑0:H/L=0.4us/0.85us,时间比接近 2:1 和 1:2;
2. 对于 7.3728M 主频而言,800kbps 约为其 1/9,即需要每 9T 时间内,完成一个比特的传输;
3. 9T 按照 2:1 和 1:2 分配,居然可以整除!(瞬间RP爆棚了)
上述三条分析的结果是,如果可以实现 H/L=6T/3T、H/L=3T/6T 这样IO代码,就可以正确驱动!
想到这里,我已经开始去翻 AVR 的指令集了(手册上居然有),找到这么几个有希望的指令:
a) sbi P, b // 2T, P|= (1<<b)
b) cbi P, b // 2T, P&= ~(1<<b)
c) out P, Rr // 1T, P = Rr
d) ld Rd, X+ // 2T, Rd= *(X++)
由于需要间接寻址(内存中颜色数据影响到比特内容),所以 ld 这条指令基本必不可少了(2T);
访问端口的话,sbi/cbi虽然很好用,但一则需要 2T 太浪费,二则需要控制分支,最终选择用out,
置位、复位操作的数值用两个寄存器事先准备好,直接out就可以在 1T 时间内完成输出;
为了给循环控制挤出时间,将9T拆分为3*3T,前段确定为H输出,后段确定为L输出,中段为数据。
每段的最终输出使用out指令,因而每段当中还有2T空闲,可以用作加载、循环控制
【混编实现】
有了上述分析,就可以着手开始工作了。整个程序框架由C生成,在关键的 WS2812_Write 当中,
通过内嵌汇编的方式,确保 out 指令间隔严格为3T,实现WS2812驱动逻辑。
这个源码我在M64/M8上都跑过,除了头文件和MCU设置,其他直接移植就可用,
说明内嵌的汇编仅涉及AVR内核,在MEGA(甚至是TINY)系列当中还是可以复用的。
实测加载8个灯约5ms,这个性能将来刷动画是妥妥有希望的。
直接上源码(ICCAVR v7.22):
附带个手册(六脚WS2812):
【运行效果】
我只写了几个简单的颜色进去,稍后再改动画吧:
【后记】
不知不觉中感觉AVR也就那样了,毕竟有些年头了再加上ATMEL的态度,难怪新品都投奔ARM去了。
不过在稳定的平台上,做出些稳定的东西,终究是有人要的,Arduino就是很好的例子。
-----------------------------------------------------------------------------
不写了,[吃饭去鸟].....(((((ヾ( o=^•ェ•)o ┏━┓ |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|