首页 > 编程语言 >使用SPI+DMA控制算法驱动WS2812

使用SPI+DMA控制算法驱动WS2812

时间:2024-04-09 17:23:45浏览次数:16  
标签:DMA 控制算法 uint8 ws2812 SPI bit WS2812 模拟

1、ws2812b是一款集控制电路与发光电路于一体的智能外控LED光源,采用单线归0码协议,每个像素点的三基色颜色可实现256级亮度显示。速率能达到1024pixel × 30fps / s,故被广泛用于各种需要大量使用RGB灯的场合。

2、不同厂商生产的ws2812存在不同的时序要求,下图是一款最常见的ws2812b通信协议。由此可以看出,我们一个0码或1码的周期在800ns~1400ns左右。

 

 

3、如果使用GPIO直接控制该总线,不但时序不好保证(编译器优化不同、不同库的汇编编译结果不同),而且十分占用CPU资源。

4、如果采用外设去模拟IO口的翻转,则可以极大的减少CPU的资源占用。目前常见的通用外设控制方案为IIC、SPI、PWM等。

  考虑IIC可能使用得较多,故采用相对较少使用得SPI总线模拟该归0协议。若使用IIC模拟的思路相同。

 

5、SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010

     通过修改不同的内容,即可修改SPI01的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。

 

 

 

 

由于需要控制某个电平持续一定时间,那么数据采样需要在时钟周期的结束,而不是开始,即CPHA = 1

 

3.设计思路

由于控制高低电平占比(ws2812 bit)的时间需要多个SPI bit,故SPI发送的长度肯定大于通信的内容,即用多个SPI bit去模拟一个ws2812 bit。常见的SPI传输是8bit,但也可配置为12、16等比特。但为了DMA搬运数据时方便对齐,故配置为8bit。

在SPI 8bit的数据长度下,我们采用2,4,8,12,16的SPI bit去模拟一个ws2812 bit。比如可以得出一下组合(实际上的ws2812时序并没有数据手册上那么严格,且不同厂家的配置不同):

用4个SPI bit去模拟,则用SPI bit表示ws2812 bit0为:1000;bit1可表示为1110。且一个SPI bit在250~420ns均可。
用8个SPI bit去模拟,则用SPI bit表示ws2812 bit0为:1100 0000;bit1可表示为1111 1100。且一个SPI bit在120~210ns均可。
当然不同比例的SPI bit可以调整出不同的SPI时间,具体根据SPI的配置时间。8个SPI bit能将时间调整得更精细,而4个SPI bit更省RAM。具体怎么配置还要和SPI的速度匹配。故我采用4个SPI bit模式。那么SPI的通信速率为2.4Mbps~4Mbps。

 

4.实现

用4个SPI bit去模拟,则用SPI bit表示ws2812 bit0为:1000bit1可表示为1110。即LOW=0x08 HIGH=0x0E

首先将SPI调整发送模式数据长度大小端分频系数CPHA

#define  WSLEDNUM    8                                                // 定义灯的数量
uint8_t  wsFillMap[4] = {0x88, 0x8E, 0xE8, 0xEE};                     // 这是一个哈希表 00=0x88 01=0x8E 10=0xE8 11=0xEE
uint8_t  ws2812Buffer[WSLEDNUM*12+2] = {0};                            // 数组缓冲区

void setOnePixRGB(uint8_t R, uint8_t G, uint8_t B, uint16_t index)
{
    uint8_t i;
    uint8_t *bufHead = ws2812Buffer + (12 * index);                    // 通过bufHead确定该像素的首地址,减少后面计算
    
    for (i = 0; i < 4; ++i)                                            // 每次位移两位,通过哈希表来填充缓存区(当然你可以写一个4位的哈希表,就不用位移了)。并同时为GRB赋值,减少循环次数。
    {
            bufHead[0+i] = wsFillMap[(G >> (6 - 2 * i)) & 0x03];
            bufHead[4+i] = wsFillMap[(R >> (6- 2 * i)) & 0x03];
            bufHead[8+i] = wsFillMap[(B >> (6 - 2 * i)) & 0x03];
    }
}

void flushWs2812(void)                                                // 刷新函数,多发两个低电平稳定电平(心里安慰,其实没用)
{
    HAL_SPI_Transmit_DMA(&hspi1, ws2812Buffer, WSLEDNUM*12+2);
}

这段代码实现了刷新一个灯的缓冲区,并通过哈希表减少运算量。最后通过DMA发送缓冲区数据即更新所有灯的状态。

注意,同时因为下拉的存在,所以不需要发送很多的0来发送RESET,但必须需保证两帧间隔大于文档中的RESET码时间。

5.总结与展望
实际上,这次买的ws2812b系列的灯,并不是该厂家的。通过调整系统主频发现可以稳定“超频”到5Mbps的SPI速率,由于STM32G431CBU6可以达到150M甚至170M,所以最终固定为:150MHz的主频,4.6875Mbps的SPI。

在150M的主频下,执行setOnePixRGB()这个函数1000次仅用时800us,故在不考虑DMA效率下,连续设置250个灯的时间也小于RESET200us的时间,可以放心用,不用考虑双Buffer,更省RAM。

最后,这段代码仅提供思路,哈希表可以更加优化,对长灯带的缓存区数据填充有更合适的方法。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/u011017694/article/details/130765095

标签:DMA,控制算法,uint8,ws2812,SPI,bit,WS2812,模拟
From: https://www.cnblogs.com/icaowu/p/18124352

相关文章

  • DMA第四版代码
    描述:我发现并不是所有的任务都有同步信号,这一期版本使用参数来控制是否需要同步信号;Test_Flow_Mode参数为高的时候意味着需要同步,否则不需要,仅检测数据流。不需要同步的情况如果丢包会出现严重后果。参考这篇笔记:https://www.cnblogs.com/VerweileDoch/p/18111545代码:`tim......
  • STM32CubeMX+MDK通过I2S接口进行音频输入输出(全双工读写一个DMA回调)
    一、前言目前有一个关于通过STM32F411CEUx的I2S总线接口控制SSS1700芯片进行音频输入输出的研究。SSS1700是具有片上振荡器的3S高度集成的USB音频控制器芯片。SSS1700功能支持96KHz24位采样率,带外部音频编解码器(24位/96KHzI2S输入和输出)并具有内置立体声16/24......
  • pdmaner-代码生成器的使用
    一、什么是pdmanerPDManer是一款开源免费的数据库模型建模工具,它以其用户友好的界面和简单的操作流程而受到用户的欢迎。以下是一些关于PDManer的特点:多平台支持:支持Windows、Mac和Linux等多种操作系统,甚至包括国产操作系统。高颜值界面:界面设计简洁美观,使得用户上手更为容易......
  • DMA-BUF
    学习资料:https://blog.csdn.net/hexiaolong2009/category_10838100.htmlhttps://www.cnblogs.com/sky-heaven/category/1288321.htmlhttps://www.kernel.org/doc/html/v6.6/driver-api/dma-buf.html#dma-fences-functions-reference 此处初步记录,后学习总结 ......
  • DMA_CYCLIC使用
    DMA传输类型:enumdma_transaction_type{DMA_MEMCPY,//内存拷贝DMA_XOR,//异或操作DMA_PQ,//乘方操作DMA_XOR_VAL,//异或值操作DMA_PQ_VAL,......
  • 3dmax效果图制作辅助工具-渲染100优化工具箱使用方法
    (1)打开渲染100官网,点击客户端下载(注:已有客户端的朋友也一定要至官网下载最新客户端,未注册用户填写邀请码1899领取渲染券)渲染100官网网址:http://www.xuanran100.com?ycode=1899(2)点击面板上的优化工具箱,如满足开启条件点击【开启工作箱】即可在3dsmax中使用。客户端点击开启......
  • m基于OFDM系统的PAPR性能matlab仿真,对比LFDMA,IFDMA,DFDMA
    1.算法仿真效果matlab2022a仿真结果如下:   2.算法涉及理论知识概要       在正交频分复用(OrthogonalFrequencyDivisionMultiplexing,OFDM)系统中,信号的峰值功率相对于其平均功率的比例称为峰均功率比(Peak-to-AveragePowerRatio,PAPR)。由于多个子载波的叠......
  • DMA Engine框架(二)
    参考资料:Linux内核4.14版本——DMAEngine框架分析(3)_dmacontroller驱动_dma_cookie_status-CSDN博客linux内核之dmaengine_dmaengine总线地址-CSDN博客  structdma_device:structdma_device{structkrefref;unsignedintchancnt;un......
  • DMA pool
    在Linux内核中,用于管理DMA内存池的相关函数通常包含在内核的DMAAPI中。以下是一些常见的DMA内存池管理函数:structdma_pool*dma_pool_create(constchar*name,structdevice*dev,size_tsize,size_talign,size_tallocation);功能:创建一个新的DMA内存池。参数:name:......
  • DMA cache一致性二
    参考资料:宋宝华:那些年你误会的LinuxDMA(关于LinuxDMAZONE和API最透彻的一篇)-CSDN博客https://blog.csdn.net/waterhawk/article/details/50723677https://www.linuxidc.com/Linux/2012-09/69591p2.htm注:本节有一些个人理解,如有误请谅解 dma_alloc_coherent与dma_alloc_wr......