嵌入式Lee

文章数:196 被阅读:578672

账号入驻

嵌入式开发极致性能优化案例-CW32饭盒派开发板TFT刷屏为例

最新更新时间:2023-04-29
    阅读数:

前言

我们之前进行了 TFT 刷屏测试确认了基本功能。刷屏速度是决定 GUI 显示帧率最根本的一环,只有优化到极致的刷屏速度,才能有基础实现更好效果的 GUI 。本篇就进行刷屏的优化,其实其思想是通用的,对于其他代码也可以参考。

1. 减少 if 条件判断

if 等条件判断会导致分支处理 , 一方面会增加指令 , 尤其是跳转指令一般执行时间比一般指令长,另外也会影响流水线和 cache

if(Data&0x80)
LCD_SDA_SET; //输出数据
else LCD_SDA_CLR;

改为串行操作

#define LCD_SDA_SET_VAL(val) LCD_CTRLB->BSRR=val;LCD_CTRLB->BRR=val^LCD_SDA

2. 使用寄存器变量

频繁操作的局部变量尽量使用寄存器进行缓存,避免反复从内存去加载,寄存器直接操作速度快很多。

register unsigned int data;

3. 空间换时间 8 for 循环改为 直接 8 次操作

其实在 memcpy 等处理中也是类似操作 , 比如连续 8 次读写组合一起,再循环。以减少 for 判断次数,也利于内部 cache 流水线处理,有一些 cpu 还有 burst 处理,这也是有利的。

inline void SPI_WriteDataF(unsigned char Data)
{
#if 0
unsigned char i=0;
for(i=8;i>0;i--)
{
if(Data&0x80)
LCD_SDA_SET; //输出数据
else LCD_SDA_CLR;

LCD_SCL_CLR;
LCD_SCL_SET;
Data<<=1;
}
#else
//LCD_SDA_LOCK;
register unsigned int data = (Data & 0x80) << 0;
LCD_SDA_SET_VAL(data);
LCD_SCL_CLR;
LCD_SCL_SET;

data = (Data & 0x40) << 1;
LCD_SDA_SET_VAL(data);
LCD_SCL_CLR;
LCD_SCL_SET;

data = (Data & 0x20) << 2;
LCD_SDA_SET_VAL(data);
LCD_SCL_CLR;
LCD_SCL_SET;

data = (Data & 0x10) << 3;
LCD_SDA_SET_VAL(data);
LCD_SCL_CLR;
LCD_SCL_SET;

data = (Data & 0x08) << 4;
LCD_SDA_SET_VAL(data);
LCD_SCL_CLR;
LCD_SCL_SET;

data = (Data & 0x04) << 5;
LCD_SDA_SET_VAL(data);
LCD_SCL_CLR;
LCD_SCL_SET;

data = (Data & 0x02) << 6;
LCD_SDA_SET_VAL(data);
LCD_SCL_CLR;
LCD_SCL_SET;

data = (Data & 0x01) << 7;
LCD_SDA_SET_VAL(data);
LCD_SCL_CLR;
LCD_SCL_SET;
//LCD_SDA_UNLOCK;
#endif
}

4. 使用内联函数减少函数跳转时间

inline void SPI_WriteDataF(unsigned char Data)

函数跳转需要时间,减少函数调用即可节约时间,尤其频繁调用的函数效果明显,但是可能增加存储空间。

5. 减少 for 循环嵌套 双重 for 嵌套改为一层 for

For 嵌套导致多重循环嵌套判断 , 浪费时间,顺序执行一般是优于分支处理的。

void Lcd_ClearF(unsigned int Color) //刷新全屏           {
unsigned int i,m;
Lcd_SetRegion(0,0,X_MAX_PIXEL-1,Y_MAX_PIXEL-1);
Lcd_WriteIndex(0x2C);
for(i=0;i
{
LCD_CS_CLR;
LCD_RS_SET;
SPI_WriteDataF(Color>>8); //写入高8位数据
SPI_WriteDataF(Color); //写入低8位数据
LCD_CS_SET;
}
}

6. 减少函数调用层级

函数调用影响流水线,并且需要额外的上下文处理时间

Lcd_ClearF 中直接调用 SPI_WriteDataF 不再调用函数 LCD_WriteData_16Bit

7. 使用汇编进行优化

这个实际看情况建议先用其他方式进行优化,因为人工编写汇编代码不一定比编译器编写的好,除非非常熟悉汇编并且有明确的优化方向。

8. 速度测试

循环刷屏使用定时器记录执行多次刷屏的时间,代码见附件。

9. 编译器速度优化选项

编译器-Ofast优化


执行时间分别是

660ms, 782ms

我们优化后的代码快 15.6%

编译器-O2优化

执行时间分别是 661 ms, 908ms

我们优化后的代 27.2%

- 从上可以看出不管用什么编译器优化,经过上面方式 人工 优化后的代码都不差不多, 660 661, 说明编译器已经无法对我们优化后的代码再进行优化

- 说明我们人工优化的代码不使用编译器优化也有很好的速度性能。

- 不同的编译器优化对原来的代码影响较大 -ofast 执行时间从 908 变为了 782

- 哪怕是采用 -ofsat 编译器优化,我们人工优化的代码依然还有比编译器优化的代码快 15.6%, 所以编译器优化无法替代人工优化。

- 只有从设计角度去优化,避免依赖编译器优化才是根本方案。

总结

1. 优化应该从设计上去优化而不是依赖编译器,应该先找大头,优先设计原理,算法上去优化,最后采取进行汇编等底层的优化,后者成本大效果不明显不具备可移植性等,前者成本小效果明显,不依赖于编译器。

2. 建议寄存器名字和手册对应 比如 gpio io 锁定寄存器,头文件中是 LOCK 手册里是 LCKR

2. 对于 IO 操作最好设置 LOCK ODR 寄存器,这样可以指定 bit 直接写值而其他位不修改,而不需要 if else 判断分别配置 BRR BSRR ,可以直接操作ODR寄存器,进一步优化速度。



最新有关嵌入式Lee的文章

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: TI培训

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved