好处:相比于gpio控制,可以大大节省CPU的时间,CPU只要将要传输的数据计算好放入内存中,然后发动DMA传输即可,后续整个过程并不需要CPU干预,CPU可以用于做其他的事情。特别是某些带蓝牙的芯片,需要给到CPU足够的时间进行协议栈的维护。
以下是ws2812b的时序:
我们只用SPI的一条data线,注意spi有四种mode,会影响spi data在闲时的数据高低,建议调试时使用示波器来检测数据的对错。
我们将SPI的速率设置到3.2M/s,那么每个spi的比特位对应的是312.5ns,此时若spi的数据是4’b1000,那么则对应ws2812b的0 code,如果spi的数据是4‘b的1110,那么则对应ws2812b的1 code。
也就是将spi设定到某个频率, 然后用4bit表示ws2812b的0 码或者1码。
如果本来某个灯的数据是24bit的0x00000000_111111111_00000000,那么对应的spi数据就应该是0x1000_1000_1000_1000_1000_1000_1000_1000____1110_1110_1110_1110_1110_1110_1110_1110___1000_1000_1000_1000_1000_1000_1000_1000=0x80808080_e0e0e0e0_80808080
如果假设以前是12个灯,那么对应288bit的数据,现在将是1152bit(通过SPI传输)的数据。
注意,一定要SPI+DMA方式,如果直接调用同步SPI方式,也就是CPU等待SPI时序发送完成后再退出,第一无法解放CPU,第二由于中断的存在,会出现ws2812b的时序不连续的情况(同步DMA传输可能被中断,在对面是SPI设备的情况下,不会出问题,因为中断时spi clk不动,设备不认为数据有效, 但是在控制ws2812b的情况下,只用到一根线,中间cpu被中断接管,那么会导致数据发送不连续,最后导致后面的灯不亮。
最极端的方法是使用spi clk=2.2M/s,那么可以用spi的3位来代表ws2812b的0码或者1码,但是这种方法不是很容易计算。好处是可以节省25%的内存
当然也可以用6.4M/s的spi速率,此时每个spi比特位对应的是156.25ns,那么用0xc0代表ws2812b的0 code。用0xffc0代表ws2812b的1 code。我当初就是这么做的,转换最简单,但是内存浪费最大。