前段时间开发ws2812驱动。网上有一些参考,但是全部是在单片机上用pwm实现,估计是考虑实时性和时间高精度要求。
而我的项目的架构中,就只有一个高通的8939,并且只有一路pwm,还被红外ir给霸占了,被逼到墙角了。没办法,活还的干,想到用其他频率高的通讯方式。
最后尝试了几种,选择了spi+bam的方式,这玩意就类似spi+dma,只是bam是高通家定义的。
ws2812们的要求如下:
思路如下:
1、选择合适高的频率,例如4.8MHZ或者9.6MHZ,我选用9.6M,这样spi传1bit花的时间大概是100ns;
2、结合上面的数据传输时间,换算出0码和1码的组合数据;
3、输入rgb的数组,例如(255,0,0)这个是红色,换算出相应的要发送的数据,放到spidev的tx buffer中。
for(i =0; i<8; i++){
temp = ((pData[0]<<i)&0x80) ? logic_one:logic_zero;
spidev_t->buffer[next++]=(temp>>8)&0xff;
spidev_t->buffer[next++]=(temp)&0xff;
}
pData[0]就是上面255,g和b的数据转换采用一样的方式。
4、把转换的数据全部转换完以后,就放到
status = spidev_sync_write(spidev, (size_t)next);
进行传输。
这样就完成了数据的传输,这样就可以亮起一个灯。想要亮多个灯,就在这个数据转换外面(第三步)加上一个led_nums的循环就可以了。注意,全部的数据转换完了,这个时候才执行(第四步)。
但是,不要以为这样就能轻易的按照你的想法点亮,坑还在后面,硬件坑(碰到这种情况,直接diao硬件)。
=================软硬分割线=================
硬件一定要看清楚ws这家伙的电器特性并且按照电器特性连接电路和供电,不然会让软件怀疑自己的实现能力的。直接上图,一看就知道了。
*高通的芯片gpio是1.8v 输出,要做电平转换。
插曲:
之前试过的几种方法中,有一种是gpio操作,发现时间精度达不到,我不调用它的封装函数,直接操作寄存器,测量出来的最低时间那就400ns多,所以不满足要求,放弃了。
完结。