[技术相关] 华芯微特SWM34-IO速度优化之模拟SPI写速度提速

[复制链接]
 楼主| 自动化陈稳 发表于 2023-7-23 17:15 | 显示全部楼层 |阅读模式
本文以在SWM34S(M33内核,150Mhz,编译器Keil MDK 5.36)上优化为例,说明优化方法和需要注意的地方,其他MCU可以参考。
在编写模拟SPI通信驱动LCD的例子的时候,会用到一个发送字节的核心函数,其基本实现方式如下:


  1. static void Spi4_WriteByte(uint8_t d)
  2. {
  3.         uint8_t i,spidat;
  4.         spidat = d;
  5.         for(i=0; i<8; i++)                       
  6.         {  
  7.                 if( (spidat&0x80)!=0 )
  8.                         LCD0_SPI4_MOSI_HIGH();
  9.                 else
  10.                         LCD0_SPI4_MOSI_LOW();
  11.                 spidat <<= 1;
  12.                 LCD0_SPI4_CLK_LOW();
  13.                 LCD0_SPI4_CLK_HIGH();               
  14.         }
  15. }




评论

———————————————— 版权声明:本文为CSDN博主「huangbinvip」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/huangbinvip/article/details/131480025  发表于 2023-7-24 01:01
———————————————— 版权声明:本文为CSDN博主「huangbinvip」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/huangbinvip/article/details/131480025  发表于 2023-7-24 01:01
 楼主| 自动化陈稳 发表于 2023-7-23 18:46 | 显示全部楼层


如上图,我们可以看到时钟的低电平时间非常的短,高电平时间很长。从如上代码我们也能看出来,是因为时钟高低电平只有一条指令,基本已经是最短的了,高电平持续期间还有其他代码运行。
 楼主| 自动化陈稳 发表于 2023-7-24 00:15 | 显示全部楼层
参考一下ST7735的spi时序图:
 楼主| 自动化陈稳 发表于 2023-7-24 00:16 | 显示全部楼层
 楼主| 自动化陈稳 发表于 2023-7-24 00:17 | 显示全部楼层
重点看写参数:时钟低电平最低宽度Tshw(15ns),时钟高电平最低宽度Tslw(15ns),时钟最小周期Tscycw(66ns)。我们在实现模拟spi驱动的时候要严格遵循这个时序要求,很明显上面测试到的时序,低电平6ns太短了,需要处理。
 楼主| 自动化陈稳 发表于 2023-7-24 00:17 | 显示全部楼层
简单的方法,在时钟低电平后插入延时,但是会导致整个速度变慢
 楼主| 自动化陈稳 发表于 2023-7-24 00:17 | 显示全部楼层
简单的方法,在时钟低电平后插入延时,但是会导致整个速度变慢

  1.                 LCD0_SPI4_CLK_LOW();
  2.                 __NOP();
  3.                 LCD0_SPI4_CLK_HIGH();       
 楼主| 自动化陈稳 发表于 2023-7-24 00:18 | 显示全部楼层
优化第一步:
把时钟拉低的时间移动到前面来,整个执行时间和代码并没有增加:
  1. static void Spi4_WriteByte(uint8_t d)
  2. {
  3.         uint8_t i,spidat;
  4.         spidat = d;
  5.         for(i=0; i<8; i++)                       
  6.         {  
  7.                 LCD0_SPI4_CLK_LOW();
  8.                 if( (spidat&0x80)!=0 )
  9.                         LCD0_SPI4_MOSI_HIGH();
  10.                 else
  11.                         LCD0_SPI4_MOSI_LOW();
  12.                 spidat <<= 1;
  13.                 LCD0_SPI4_CLK_HIGH();               
  14.         }
  15. }
 楼主| 自动化陈稳 发表于 2023-7-24 00:19 | 显示全部楼层
QQ截图20230724001901.jpg


由于编译器的优化(而且一定要开优化(O1以上),速度才会快,开与不开大约相差3倍),从低电平到高电平之间的时间似乎并没有完全和代码一致,但是宽度已经变成14ns了,已经能基本满足我们的需求了。
好了,到这里,我们把基本时序调整完成,发送一个字节大约需要714ns,此时发送一帧数据(320x240 16bit)大约需要110ms。
感觉速度还是不够,如何来进一步优化?
乍一看,貌似也没有多少优化空间了(那几个宏定义的操作已经是最优实现,可以不考虑)?那还能咋整?
细节决定成败,请记住我们用的是32bit mcu,代码中的i,spidat两个变量是采用8bit定义的,习惯了单片机的内存紧张,尽量用最小单位来定义了。

 楼主| 自动化陈稳 发表于 2023-7-24 00:20 | 显示全部楼层
优化第二步,将变量i定义为32bit,看看发生了什么变化:

  1. uint32_t i;<img src="https://bbs.21ic.com/forum.php?mod=image&aid=2137462&size=300x300&key=d4ce4a821f437c59&nocache=yes&type=fixnone" border="0" aid="attachimg_2137462" alt="">
QQ截图20230724001952.jpg
 楼主| 自动化陈稳 发表于 2023-7-24 01:00 | 显示全部楼层


看看效果,一个字节的发送时间从714ns降低到628ns,一帧的数据时间降低到94.16ms。是不是很惊奇,说明在32bit的mcu上,效率最高的内存访问还是32bit的方式,在需要极度时间优化的时候请正确使用。
优化第三步,将变量spidat也定义为32bit:
最终全部代码如下:
  1. <div><div>
  2. </div><div>static void Spi4_WriteByte(uint8_t d)</div><div>{</div><div><span style="white-space:pre">        </span>uint32_t i,spidat;</div><div><span style="white-space:pre">        </span>spidat = d;</div><div><span style="white-space:pre">        </span>for(i=0; i<8; i++)<span style="white-space:pre">                        </span></div><div><span style="white-space:pre">        </span>{  </div><div><span style="white-space:pre">                </span>LCD0_SPI4_CLK_LOW();</div><div><span style="white-space:pre">                </span>if( (spidat&0x80)!=0 ) </div><div><span style="white-space:pre">                        </span>LCD0_SPI4_MOSI_HIGH();</div><div><span style="white-space:pre">                </span>else sudu</div><div><span style="white-space:pre">                        </span>LCD0_SPI4_MOSI_LOW();</div><div><span style="white-space:pre">                </span>spidat <<= 1;</div><div><span style="white-space:pre">                </span>LCD0_SPI4_CLK_HIGH();<span style="white-space:pre">                </span></div><div><span style="white-space:pre">        </span>}</div><div>}</div></div><div></div>



 楼主| 自动化陈稳 发表于 2023-7-24 01:00 | 显示全部楼层






这个优化我们很容易忽略,因为spi传输8bit数据的时候,我们是msb在前,要先判断最高位,惯性的就用了8bit来表示数据,其实我们是需要判断第8bit,而不是一定需要8bit数据长度,在代码中,用32bit也是一样的效果
从图中实际测试数据来看,我们的字节传输时间再次下降到574ns,一帧数据86.09ms,提升还是比较明显。
综合来看,仅仅通过优化两个变量类型的定义,一帧数据的传输时间从110ms->94.16ms->86.09ms,提速约30%,并没有为cpu带来任何影响,也不会多ram开销,效果非常明显。

ufbycd 发表于 2023-7-27 18:36 | 显示全部楼层
自动化陈稳 发表于 2023-7-24 00:19
由于编译器的优化(而且一定要开优化(O1以上),速度才会快,开与不开大约相差3倍),从低电平到高电平 ...

32位CPU上的数据排列按32位对齐才能跑得快。
51xlf 发表于 2023-8-3 22:04 | 显示全部楼层
SPI模块使用寄存器直接操作的方式可以提升1/5的速度
minzisc 发表于 2023-8-3 22:18 | 显示全部楼层
通过对代码进行优化,可以提高执行效率。
tifmill 发表于 2023-8-3 22:42 | 显示全部楼层
不同的SPI硬件设备的性能可能会有所不同
bestwell 发表于 2023-8-3 22:53 | 显示全部楼层
增加SPI时钟频率可以加快数据传输速度。
chenjun89 发表于 2023-8-3 23:42 来自手机 | 显示全部楼层
模拟的效率没有硬件SPI高
cemaj 发表于 2023-8-4 20:23 | 显示全部楼层
可以考虑使用批量传输数据,而不是逐个字节地传输。
uytyu 发表于 2023-8-4 20:53 | 显示全部楼层
提高SPI写速度的同时也可能会增加系统的复杂度
您需要登录后才可以回帖 登录 | 注册

本版积分规则

105

主题

1379

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部