打印
[技术相关]

华芯微特SWM34-IO速度优化之模拟SPI写速度提速

[复制链接]
3145|55
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本文以在SWM34S(M33内核,150Mhz,编译器Keil MDK 5.36)上优化为例,说明优化方法和需要注意的地方,其他MCU可以参考。
在编写模拟SPI通信驱动LCD的例子的时候,会用到一个发送字节的核心函数,其基本实现方式如下:


static void Spi4_WriteByte(uint8_t d)
{
        uint8_t i,spidat;
        spidat = d;
        for(i=0; i<8; i++)                       
        {  
                if( (spidat&0x80)!=0 )
                        LCD0_SPI4_MOSI_HIGH();
                else
                        LCD0_SPI4_MOSI_LOW();
                spidat <<= 1;
                LCD0_SPI4_CLK_LOW();
                LCD0_SPI4_CLK_HIGH();               
        }
}




使用特权

评论回复

相关帖子

沙发
自动化陈稳|  楼主 | 2023-7-23 18:46 | 只看该作者


如上图,我们可以看到时钟的低电平时间非常的短,高电平时间很长。从如上代码我们也能看出来,是因为时钟高低电平只有一条指令,基本已经是最短的了,高电平持续期间还有其他代码运行。

使用特权

评论回复
板凳
自动化陈稳|  楼主 | 2023-7-24 00:15 | 只看该作者
参考一下ST7735的spi时序图:

使用特权

评论回复
地板
自动化陈稳|  楼主 | 2023-7-24 00:16 | 只看该作者

使用特权

评论回复
5
自动化陈稳|  楼主 | 2023-7-24 00:17 | 只看该作者
重点看写参数:时钟低电平最低宽度Tshw(15ns),时钟高电平最低宽度Tslw(15ns),时钟最小周期Tscycw(66ns)。我们在实现模拟spi驱动的时候要严格遵循这个时序要求,很明显上面测试到的时序,低电平6ns太短了,需要处理。

使用特权

评论回复
6
自动化陈稳|  楼主 | 2023-7-24 00:17 | 只看该作者
简单的方法,在时钟低电平后插入延时,但是会导致整个速度变慢

使用特权

评论回复
7
自动化陈稳|  楼主 | 2023-7-24 00:17 | 只看该作者
简单的方法,在时钟低电平后插入延时,但是会导致整个速度变慢

                LCD0_SPI4_CLK_LOW();
                __NOP();
                LCD0_SPI4_CLK_HIGH();       

使用特权

评论回复
8
自动化陈稳|  楼主 | 2023-7-24 00:18 | 只看该作者
优化第一步:
把时钟拉低的时间移动到前面来,整个执行时间和代码并没有增加:
static void Spi4_WriteByte(uint8_t d)
{
        uint8_t i,spidat;
        spidat = d;
        for(i=0; i<8; i++)                       
        {  
                LCD0_SPI4_CLK_LOW();
                if( (spidat&0x80)!=0 )
                        LCD0_SPI4_MOSI_HIGH();
                else
                        LCD0_SPI4_MOSI_LOW();
                spidat <<= 1;
                LCD0_SPI4_CLK_HIGH();               
        }
}

使用特权

评论回复
9
自动化陈稳|  楼主 | 2023-7-24 00:19 | 只看该作者



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

使用特权

评论回复
10
自动化陈稳|  楼主 | 2023-7-24 00:20 | 只看该作者
优化第二步,将变量i定义为32bit,看看发生了什么变化:

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 (41.02 KB )

QQ截图20230724001952.jpg

使用特权

评论回复
11
自动化陈稳|  楼主 | 2023-7-24 01:00 | 只看该作者


看看效果,一个字节的发送时间从714ns降低到628ns,一帧的数据时间降低到94.16ms。是不是很惊奇,说明在32bit的mcu上,效率最高的内存访问还是32bit的方式,在需要极度时间优化的时候请正确使用。
优化第三步,将变量spidat也定义为32bit:
最终全部代码如下:
<div><div>
</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>



使用特权

评论回复
12
自动化陈稳|  楼主 | 2023-7-24 01:00 | 只看该作者






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

使用特权

评论回复
13
ufbycd| | 2023-7-27 18:36 | 只看该作者
自动化陈稳 发表于 2023-7-24 00:19
由于编译器的优化(而且一定要开优化(O1以上),速度才会快,开与不开大约相差3倍),从低电平到高电平 ...

32位CPU上的数据排列按32位对齐才能跑得快。

使用特权

评论回复
14
51xlf| | 2023-8-3 22:04 | 只看该作者
SPI模块使用寄存器直接操作的方式可以提升1/5的速度

使用特权

评论回复
15
minzisc| | 2023-8-3 22:18 | 只看该作者
通过对代码进行优化,可以提高执行效率。

使用特权

评论回复
16
tifmill| | 2023-8-3 22:42 | 只看该作者
不同的SPI硬件设备的性能可能会有所不同

使用特权

评论回复
17
bestwell| | 2023-8-3 22:53 | 只看该作者
增加SPI时钟频率可以加快数据传输速度。

使用特权

评论回复
18
chenjun89| | 2023-8-3 23:42 | 只看该作者
模拟的效率没有硬件SPI高

使用特权

评论回复
19
cemaj| | 2023-8-4 20:23 | 只看该作者
可以考虑使用批量传输数据,而不是逐个字节地传输。

使用特权

评论回复
20
uytyu| | 2023-8-4 20:53 | 只看该作者
提高SPI写速度的同时也可能会增加系统的复杂度

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

82

主题

1200

帖子

1

粉丝