lcd driver for MCU,常用小型LCD屏的驱动,如ST7735S,GC9A01等
最近网购了几片LCD显示模块,商家提供的驱动性能非常差,以128*160,16位颜色的 lcd TFT 屏为例, 整屏的颜色数据为128 * 160 * 16bit = 327,680, 以STM32 F103 的SPI最高频率18M计算, 每秒能发送的数据足够刷新50多次,即有一些损耗,也不至于FPS只有十几二十,在查看这些驱动的源代码时, 发现有一些错误的注释,网上也没有找到合适驱动代码. 于是自行查阅官方文档,并修改代码,比商家提供的程序性能要好一些,希望能对他人有用.
做了一些简单的测试,记录如下:
* 测试平台:SMT32F103C8T6核心开发板, 1.8寸 128*160, ST7735S驱动 LCD 显示屏
* 系统时钟: 72M
* SPI时钟: 18M
* 开发环境: Keil 5.29 , STM32 HAL 库
以下不同显存情况下,用不同颜色清屏(128*160)刷新的的 FPS 数据
DRAM(byte) | 256 | 512 | 1024 | 1536 | 2048 | 2560 | 3072 | 3584 | 4096 | 5120 | 7680 | 8192 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
无DMA | 49.86 | 50.59 | 50.9 | 50.93 | 50.89 | 50.83 | 50.74 | 50.65 | 50.56 | 50.35 | 49.84 | 49.75 |
有DMA | 51.19 | 52.84 | 53.63 | 53.81 | 53.85 | 53.84 | 53.76 | 53.71 | 53.63 | 53.45 | 52.94 | 52.85 |
性能提升 | 2.60% | 4.26% | 5.09% | 5.35% | 5.50% | 5.59% | 5.62% | 5.70% | 5.72% | 5.80% | 5.86% | 5.87% |
可以看出显存并不是越多性能越好
若开启编译优化, 无DMA的性能更略有提升,FPS能到达52-53左右
对于嵌入式开发,25以上的fps已足够使用,采用DMA方式再提升3,5个百分点的效果并不明显, 而由此占用了dma资源,并且由于DMA中断,数据要分批发送,导致代码结构复杂,与其它功能耦合,不利于调试与移植复用. 综合来看,不建议启用DMA.
但是,若RAM资源足够多能设置全屏显存,可以用DMA一次性刷新全屏,不需要分批发送,全屏显示可以做一些复杂的显示操作
若要得到更高的FPS,有三种方案:
* 采用更高速度的SPI, 国产某些MCU的SPI速度可以达到40M以上
* 采用4线SPI,两根据数据同时发送,理论上速率可以翻倍
* 若对颜色要求不高,可降低颜色深度, 有些屏支持12bit颜色
另外粗略测试了以下两个屏的粗略的性能测试数据
驱动IC | 分辨率 | 颜色深度 | SPI 18M | SPI 45M |
---|---|---|---|---|
ST7735S | 128*160 | 16 bit | 50.9 fps | 135.8 fps |
GC9A01 | 240*240 | 16 bit | 17.2 fps | 48.5 fps |
在商家提供的驱动代码注释中有以下一段话 (看代码中的配置 SPI时钟为36M)
//如果使用官方库函数定义下列底层,速度将会下降到14帧每秒,建议采用我司推荐方法
//以下IO定义直接操作寄存器,快速IO操作,刷屏速率可以达到28帧每秒!
//GPIO置位(拉高)
#define LCD_CS_SET GPIO_TYPE->BSRR=1<<LCD_CS //片选端口 PB11
#define LCD_RS_SET GPIO_TYPE->BSRR=1<<LCD_RS //数据/命令 PB10
#define LCD_RST_SET GPIO_TYPE->BSRR=1<<LCD_RST //复位 PB12
//GPIO复位(拉低)
#define LCD_CS_CLR GPIO_TYPE->BRR=1<<LCD_CS //片选端口 PB11
#define LCD_RS_CLR GPIO_TYPE->BRR=1<<LCD_RS //数据/命令 PB10
#define LCD_RST_CLR GPIO_TYPE->BRR=1<<LCD_RST //复位 PB12
以上认为是寄存器操作引起的速度变化是错误的, GPIO 速度的远小于 SPI, 最影响速度的操作是频繁的 GPIO 操作,即不断地操作CS,D/C, 在批量发送数据时,把D/C拉高,再用HAL_SPI_Transmit 发送数据即可大大减少 GPIO 的操作.
以下是用寄存器操作与HAL操作GPIO的对比(显存DRAM 256 byte, SPI时钟 18M,无DMA)
方式 | 寄存器操作 | HAL库操作 |
---|---|---|
FPS | 49.86 | 49.85 |
可以看出性能变化几乎可以忽略
在项目中,如果要向LCD屏发送命令/数据前,先拉低CS,甚至有些项目就一块屏,CS在硬件连接就已拉低,就没有必要再操作CS, 每次发命令或者数据前拉低或者拉低D/C,在批量发送数据时没有必要频繁操作D/C或者CS
若考虑同一个SPI接口控制多块屏的显示,则要在驱动层或者显示接口层加增加启用与禁用指定屏的功能函数
lcd显示屏的FPS性能除了受到MCU SPI速度的约束外,也受自身驱动IC与物理性能的约束,
根据S7735S的官方文档,时钟周期Serial Clock Cycle (Write) 最小值为66ns,可以支持15M的速度, 按全屏12816016bit数据计算,刷新一屏约21.6ms,FPS约46.
若假设时钟信号为理想的方波,只考虑时钟高低电平的持续时间,其最小周期约为 TSHW+TSLW=30ns, 可以支持33.3M的速率,FPS约102 从实际的测试结果看,官方文档非常保守(或者官方文档已过时,我参考的版本是V1.5_20150303). 用ACM32F403测试,SPI时钟在22.5M时, FPS可达到67左右,当SPI时钟置为45,开启编译优化后,测得FPS约136,刷新显示依然正常
GC9A01的屏没有测试,但是从文档中看Serial Clock Cycle (Write) 最小值为10,可以支持100M的速度,对于240*240,16位色, FPS大约可以刷到108
除了初始化,打开关闭显示等基本的功能外,还有以下功能
* 描点
* 画线,支持线宽
* 画空心矩形框,支持线宽
* 填充矩形
* 画空心圆
* 填充圆
* 显示ascii字符
* 显示汉字
* 显示图片
代码中用到的取字模,图片取模,颜色转换等,请访问
https://www.buziot.com/tools
若有需要,可以考虑增加显示功能,如 UI组件, 动画等
示例代码中的目录结构如下:
* proj 项目文件
* sys 系统文件,如CMSIS ,HAL库等
* msp mcu资源
* bsp 板载资源
* drv 驱动层
* api 接口层
* app 应用层
* lib 第三方库
* res 资源文件,如文字,图标,图片等
* ui ui组件
功能层次如下图:
本项目目前只提供 ST7735S,与GC9A01的两个驱动,其它驱动用户可以自行增加以支持其它驱动IC
example中有两个示例代码, src只有核心内容,即驱动屏,显示接口与配置文件,显示接口几乎不需要修改 src的驱动中没有DMA内容, example中的示例有DMA,在spi.h中可以设置关闭或者开启
若有任何意见与意见请提交 issue 或 发送邮件到此邮箱: [email protected]