先交代一下背景。今年有个项目要在1.8寸TFT彩屏上做一套带按钮、滑块和简单动画的交互界面,屏幕分辨率128x160,主控用的是STM32F103系列。第一反应是直接用LVGL手写布局,但写到一半就发现效率太低,一个圆角面板加一个按钮的样式微调,改代码、烧录、看效果,来回折腾差不多要十分钟。后来换了SquareLine Studio做UI,拖拽布局、实时预览,导出代码后整个屏幕直接能跑,这个效率差距让我彻底回不去了。
这篇文章就是把“SquareLine Studio + STM32F103 SPI + TFT彩屏”这套流程完整展开,从硬件连接到CubeMX配置,从SquareLine Studio界面绘制到LVGL代码移植,最后再把刷新卡顿、花屏白屏这些典型问题的排查过程整理出来。适合手里有一块SPI接口小屏、想把界面开发从“像素级手写”变成“可视化拖拽”的开发者。不管你之前用没用过LVGL,照着这个流程走下来,基本都能在半天内把一块空屏变成能触控、能刷动画的完整UI。
1. 整体方案选型:为什么要用SquareLine Studio搭SPI TFT界面
1.1 这套组合解决了什么问题
过去写嵌入式屏幕界面,最痛苦的不是驱动,而是“界面布局”这件事。用纯LVGL代码画界面的体验,和用CSS写网页但不允许刷新预览一样,所有参数都靠想象,改一个像素级别的边距都要反复烧录验证。
SquareLine Studio做的事情,就是把这一步彻底可视化。它是一款基于LVGL的图形化UI编辑器,界面设计类似PPT或者Figma,往画布里拖组件、调属性、设置动画,点击运行后还能在电脑上实时预览效果。编辑完成后一键导出C代码,生成一个独立的ui目录,里面是用户界面相关的所有源码,拿进STM32工程里编译即可运行。
当UI被拆分到独立工具链之后,整个项目的分工就变了。界面层不用再关心底层屏幕怎么初始化、SPI怎么收发光子,只管在SquareLine Studio里堆组件、配动画;底层up到LVGL之后,把屏幕当作一个“显示内存”的设备,LVGL负责把界面渲染成像素,再通过SPI刷到TFT面板上。这样上层和底层解耦,两边可以并行推进。
1.2 为什么选择SPI接口的TFT屏幕
TFT彩屏常见的并行接口是8080/6800并口,数据线有8根、16根甚至18根,引脚占用非常夸张。SPI接口屏幕只需要SCLK、MOSI,再加CS、DC、RST、BLK,总共6个引脚就能搞定,这对引脚资源紧张的STM32F103系列特别友好。
SPI接口的劣势是刷新带宽低,但128x160分辨率的1.8寸屏,RGB565格式一帧数据量是1281602约40KB,SPI工作在18MHz时理论刷新率可以到18Mbps,实际大概7到10毫秒刷一帧,跑动态界面和人眼感知的30帧率已经非常接近。如果追求更高刷新率,一是上DMA,二是把SPI时钟尽量拉高,这两个优化后面会单独展开。
1.3 需要提前理解的核心概念:帧缓冲与脏矩形
LVGL的渲染机制和其他GUI库不太一样,它不是每帧整屏重绘,而是通过脏矩形算法只重绘变化的区域,这直接关系到刷屏效率。我们要在SPI TFT这种低带宽屏上获得流畅体验,必须理解这个机制。
LVGL内部有一个或者两个帧缓冲,这个缓冲是RAM里的一个二维数组,大小至少覆盖屏幕的一部分。UI组件变化时,LVGL先把变化区域渲染到这个缓冲里,然后调用底层flush回调,把缓冲内容一次性推给屏幕。SPI TFT驱动的本分,就是在flush回调里把RAM里的像素数据转换成一串SPI时序发出去。
理解了这套机制后,后面遇到的“UI界面卡顿”“刷新闪烁”等问题就都有了解题思路,大概率是帧缓冲配置不合理、flush回调里加了阻塞延时、或者SPI传输没有用DMA导致CPU被占满了。
2. 硬件连接与CubeMX底层配置:SPI、DMA、GPIO一次配齐
2.1 硬件清单和引脚规划
用到的核心硬件如下:
- 主控板:STM32F103C8T6最小系统板
- 屏幕:1.8寸TFT LCD,分辨率128x160,主控芯片ST7735S,SPI接口
- 工具:ST-Link或USB转TTL(烧录用)、逻辑分析仪(强烈建议准备一个,排查SPI时序非常好用)
我这块屏幕的引脚定义是VCC、GND、CS、RESET、DC、SDI(MOSI)、SCK、LED背光。与STM32F103的连线方案:
| 屏幕引脚 | STM32引脚 | 说明 |
|---|---|---|
| VCC | 3.3V | 屏幕供电 |
| GND | GND | 共地 |
| CS | PA4 | 软件片选,用普通GPIO控制 |
| RESET | PA3 | 复位脚,低电平复位 |
| DC | PA2 | 数据/命令选择,高电平时数据,低电平时命令 |
| SDI(MOSI) | PA7 | SPI1_MOSI |
| SCK | PA5 | SPI1_SCK |
| LED | 3.3V或通过电阻接3.3V | 背光 |
关于片选这里先埋个伏笔:很多人习惯直接用SPI外设的硬件NSS引脚,这在单设备场景下问题不大,但SPI驱动TFT屏幕时,我强烈建议用普通GPIO做软件片选。原因是硬件NSS在一些STM32型号上会和DMA传输产生竞争,传输过程中片选被外设自动拉高,导致命令序列被截断,屏幕花屏,这个坑我在第6章会详细讲。
2.2 CubeMX配置SPI1和DMA
打开STM32CubeMX,选择STM32F103C8T6芯片,按以下步骤配置:
- SYS选择Serial Wire调试口,避免烧录一次后SWD被禁用。
- RCC选择HSE外部晶振,时钟树里把HCLK配到72MHz。
- SPI1使能,Mode选择Full-Duplex Master。注意我们用的是软件片选,SPI硬件片选NSS可以不配置,或者配成NSS Soft模式,反正不用它。
- 参数配置里,Baud Rate Prescaler先选32分频,即SPI时钟为36MHz/32=1.125MHz,先用低速把通信跑通,后面再逐步提速。
- CPOL和CPHA选择Mode 0,即CPOL=0、CPHA=0,这是ST7735S最常见的模式,少数屏幕是Mode 3,调试时如果花屏可以切换试试。
- 数据帧格式为8bit,MSB First。有些屏幕支持LSB First,但绝大多数TFT驱动库默认按MSB处理。
- 添加DMA Request:为SPI1_TX添加一个DMA通道,Direction选择MemoryToPeripheral,Mode选择Normal。这一步是后面流畅刷屏的关键,如果暂时不想用DMA也可以先跳过,但本文的实际代码会基于DMA实现。
GPIO配置部分,PA3(RESET)、PA2(DC)、PA4(CS)都设置成GPIO Output推挽输出。其中RESET和DC属于控制功能,速度可以设Low;CS作为片选,设成High也没关系,GPIO速度影响力不大。
2.3 关于SPI时钟分频和波形质量
SPI时钟频率是影响TFT刷新率的最直接因素,但不能一上来就无脑拉高。STM32F103的SPI1挂在APB2总线上,APB2默认72MHz,SPI1最高支持18MHz。理论上分频系数最小可以到4,即SPI时钟18MHz,但实际使用中要考虑杜邦线长度、屏幕PCB走线、主控板电源质量。
我个人的调参顺序是:先用32分频(1.125MHz)验证通信是否正常,确认能刷出纯色后,逐步改成16分频(2.25MHz)、8分频(4.5MHz)、4分频(9MHz)。如果屏幕和主控板之间用的是10cm以上的杜邦线,4分频可能会出现条纹干扰,这时候用逻辑分析仪抓一下SCLK和数据波形,确认边沿是否干净,如果波形边缘有明显振铃就把频率降回8分频。最终项目里我稳定跑在9MHz,刷一帧大约需要40ms,配合LVGL局部刷新完全够用。
如果想把时钟再往上推,可以用SPI2,但它挂APB1上最高只有36MHz,天然受限;或者换用F103的高主频版本,但STM32F103系列的SPI外设本身就限制在18MHz,再往上就只能换主控平台了。
2.4 打开SPI接收DMA通道(后续扩展用)
原本的UI显示工程只需要SPI发送,不需要接收。但热词里提到了“STM32F103 SPI通过DMA方式读取芯片数据”的需求,我在配置时顺手也把SPI1_RX的DMA通道打开了,这种方式在项目后续扩展读取外部Flash或者传感器数据时会非常有用。
CubeMX里添加SPI1_RX DMA,方向PeripheralToMemory,Mode也是Normal。这样以后只需要在外设回调里写数据解析逻辑,读取外部设备时就不需要CPU轮询读取寄存器了。和TFT共用SPI1总线也没问题,因为屏幕的CS是独立控制的,片选选中谁,总线就归谁,互不干扰。
3. SquareLine Studio端实操:从空画布到可导出UI
3.1 创建工程时的关键设置
SquareLine Studio目前主流版本默认支持LVGL 8.x,创建工程时需要选择硬件平台和屏幕参数。由于我们用的是STM32F103 + ST7735S,这一套不在官方预设的硬件模板里,所以选择Empty Arduino或者Empty自定义工程都行,关键是把屏幕尺寸设成128x160。
颜色深度选择RGB565,这是LVGL在嵌入式设备上最常用的颜色格式,一个像素占两个字节,颜色损失小,传输量适中。如果选ARGB8888,虽然颜色更丰富,但一帧数据量变成1281604约80KB,对SPI带宽是成倍压力,没有特殊需求不要选。
字体方面,如果界面只有英文和数字,默认字体就够用。如果需要显示中文,SquareLine Studio自带的字体是矢量字体,体积较大,STM32F103的Flash只有64KB,直接内置一套中文字体基本放不下。这种情况建议用LVGL的字体转换工具生成16x16点阵字库,只包含需要的字符,二三十个汉字占用的Flash很好控制。
3.2 界面布局设计要点
SquareLine Studio的使用逻辑类似前端页面编辑器,左侧是组件面板,中间是画布,右侧是属性面板。核心组件分为四类:
- 基础显示组件:Label(文本)、Image(图片)、Arc(圆弧)、Line(线)等
- 交互组件:Button(按钮)、Slider(滑块)、Switch(开关)、Dropdown(下拉)
- 容器组件:Panel(面板,用于分组布局)
- 特殊组件:Chart(图表)、Keyboard(键盘)、Spinner(加载圈)
布局设计上,128x160的屏幕不算大,组件之间留白要克制。我习惯用Panel作为底部分组容器,按钮尺寸设置成40x40以上,保证手指触摸的容错率。如果做的是旋钮表盘类界面,Arc组件配合Value可调数值,非常适合做进度环效果。
SquareLine Studio最有价值的特性是可以给组件添加动画。比如点击按钮切换页面时,给新页面加一个从右向左滑入的动画,在“Animation”面板里设置起始位置和动画时长。这些动画在PC端预览是什么效果,烧录到真机上就是什么效果,因为动画逻辑会生成LVGL的动画API代码。
3.3 导出代码时要注意哪些选项
UI设计完成后,点击右上方的Export导出。导出前重点检查两个地方:
- 导出的LVGL版本要和工程里移植的LVGL版本对应,SquareLine Studio 1.3.x默认导出LVGL 8.3代码,如果你工程里用的LVGL 7.x,生成的代码大概率编译不过去。
- Export Path选择工程目录下的一个独立文件夹,比如项目根的SquareLine_UI,导出的内容以ui开头,包含ui.c、ui.h、ui_events.c以及若干资源文件。
如果工程里原先已经有LVGL的初始化代码,建议保持导出目录独立,不要覆盖自建的lv_port_disp.c和lv_port_indev.c这些外围移植文件。ui目录只负责界面定义,不负责驱动,二者职责分离。
另外,如果界面里用到了按钮点击回调,SquareLine Studio会把这些回调生成到ui_events.c里,函数签名都是声明的空函数,拿到工程后再填充业务逻辑即可。这一层隔离很干净,UI变更后重新导出的代码不会覆盖你已经写好的逻辑。
4. LVGL移植与ST7735S驱动对接:让SquareLine Studio代码跑起来
4.1 LVGL在STM32上的内存规划
LVGL的运行需要一个RAM缓冲来渲染界面,这是整个移植里最容易翻车的环节。STM32F103C8T6只有20KB RAM,128x160的屏幕如果做全屏双缓冲,需要2*40KB=80KB,直接劝退。所以必须按小内存平台的方式来配置。
仅对128x160屏幕,单缓冲推荐设成屏幕高度的1/4到1/10,即约20行像素,也就是128202等于5KB。设置方法在lv_conf.h里的LV_MEM_SIZE(LVGL自己的动态内存池大小)和disp_buf数组大小。我这边LV_MEM_SIZE配了16KB,显示缓冲配了5KB,这在内核资源和界面控件数量足够的前提下是合理的。
注意,LVGL的动态内存池不是等价于缓冲区,LV_MEM_SIZE是给控件对象、动画、事件回调等的内存分配器用的,控件越多、动画越多,这个值就要越大。在RAM吃紧时可以对控件进行精简、减少动画,而不是压缩LV_MEM_SIZE。
4.2 实现disp_flush回调和DMA发送
LVGL需要底层提供一个“把缓冲推给屏幕”的回调函数,名字一般是disp_flush。在lv_port_disp.c里找到这个函数,改成如下结构:
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { // 设置显示窗口为需要刷新的区域 ST7735_SetWindow(area->x1, area->y1, area->x2, area->y2); // 拉低片选 LCD_CS_LOW(); // 数据模式 LCD_DC_HIGH(); // 将RGB565像素数据通过SPI DMA发送 HAL_SPI_Transmit_DMA(&hspi1, (uint8_t *)color_p, (uint16_t)((area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2)); // 记录当前传输状态,待发送完成后再调用 lv_disp_flush_ready isFlushing = 1; }DMA发送是异步的,CPU发完指令后立即返回,不用在这里阻塞等待,这样LVGL能继续渲染下一块区域,刷屏效率大幅提升。
需要配套一个DMA传输完成回调,在这个回调里把片选拉高,并通知LVGL本次刷新结束:
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { if (hspi->Instance == SPI1) { LCD_CS_HIGH(); isFlushing = 0; lv_disp_flush_ready(&disp_drv); } }lv_disp_flush_ready的作用是告诉LVGL“这块缓冲已经发完了,你可以继续渲染新的内容了”。如果忘了调用,整个界面会卡死或者不刷新,这是最常见的移植问题。
4.3 ST7735S的窗口设置和小屏初始化
ST7735S初始化需要发送几十个寄存器配置命令,这个环节一般不会手写,直接用市面常见的ST7735S驱动代码或者Adafruit库里的初始化序列即可。核心要理解的是地址窗口设置命令CASET(0x2A)和RASET(0x2B)。
TFT屏幕的行列驱动电路本质上是一个线性寻址空间,要让像素写进指定矩形,必须先通知屏幕控制芯片“接下来我要往这个矩形写像素”。CASET设置列范围,RASET设置行范围,之后通过RAMWR(0x2C)命令开始传输像素数据。这个窗口大小如果设置不对,画面就会出现错位、截断、滚屏等现象。
对于128x160分辨率,注意ST7735S的偏移参数。屏幕玻璃内部可能有一圈边框区域,实际可见区域不是从(0,0)开始,常见偏移有(0,0)、(2,1)、(0,2)。如果初始化后发现画面整体偏移或者有黑边,试着修改驱动里setAddrWindow函数的偏移量。
还有个细节:LVGL的显示驱动结构体里有一个lv_disp_drv_t的user_data字段,可以在初始化时把屏幕宽高传进去,但大多数情况下ST7735S偏移不会影响LVGL的坐标系,因为LVGL的坐标按逻辑像素走,最终通过flush回调映射到屏幕的物理像素。只要flush里把area正确换算成窗口指令就行。
4.4 启动流程:先初始化LVGL还是先初始化屏幕
正确的启动顺序是:
- 初始化ST7735S屏幕,刷一次纯色背景
- 初始化LVGL库,调用lv_init()
- 注册显示驱动和触摸/按键输入驱动
- 调用SquareLine Studio导出的ui_init()函数
- 进入主循环,周期调用lv_timer_handler()
顺序不能乱,特别是lv_init()必须在ui_init()之前。ui_init里会创建大量控件对象,如果LVGL核心还没初始化,控件创建会直接断言失败。
主循环里lv_timer_handler的执行频率决定了UI的流畅度,一般建议每1到5毫秒调用一次。如果主循环同时要处理其他业务,比如读取传感器,可以用一个定时器中断,每2ms设置一个标志位,主循环检测到标志后调用lv_timer_handler,避免在中断上下文中直接执行。
5. 从CubeMX到界面点亮:一次完整的链路打通
5.1 工程目录结构与关键文件
经过前面的步骤,工程目录结构大致如下:
Project/ ├── Core/ │ ├── Inc/ │ ├── Src/ │ │ ├── main.c │ │ ├── st7735.c // 屏幕底层驱动 │ │ └── lv_port_disp.c // LVGL显示适配层 ├── Drivers/ ├── LVGL/ │ ├── lvgl.h │ ├── lv_conf.h // LVGL配置文件 │ └── src/ ├── SquareLine_UI/ │ ├── ui.c // SquareLine Studio导出的UI代码 │ ├── ui.h │ ├── ui_events.c │ └── ui_helpers.cui目录下的文件是通过SquareLine Studio导出的,后续界面修改后直接重新导出并覆盖这个目录即可。我一般不手动改ui目录里的代码,所有业务逻辑都写在ui_events.c的事件回调里,这样重新导出时不会被冲掉。
5.2 核心代码串联
main.c里的初始化序列伪代码如下:
int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_SPI1_Init(); ST7735_Init(); // 初始化屏幕 ST7735_FillScreen(0x0000); // 刷黑屏,验证驱动正常 lv_init(); // 初始化LVGL lv_port_disp_init(); // 注册显示驱动 lv_port_indev_init(); // 如果有按键,注册输入设备 ui_init(); // 加载SquareLine Studio生成的UI while(1) { lv_timer_handler(); // 处理LVGL任务 delay_ms(2); // 让出CPU } }主循环里的延时不能太长,否则按钮动画会有明显卡顿感。LVGL官方推荐周期是5ms以内,我用2ms表现正常。
5.3 第一次上电:预期和实拍验证
代码编译烧录后,第一眼应该看到的是屏幕按SquareLine Studio里的布局显示出来,按钮、标签、圆弧都正常呈现。我建议在工程里做一个“自检模式”:上电后先刷纯红、纯绿、纯蓝三色,每色停留500ms,再进入UI。这样能最快确认屏幕驱动本身没问题,还是LVGL层的问题。
如果你的屏幕直接白屏,大概率是RESET引脚时序问题,ST7735S在上电后需要一个低电平脉冲再拉高,这个脉冲必须保持至少10ms。如果直接花屏,先检查SPI模式是不是Mode 0、CLOCK分频是不是太快,再检查CASET和RASET的偏移量。
6. 常见问题与排查技巧实录
6.1 SPI通信不生效、屏幕一直白屏或黑屏
刚连好硬件时最容易出现的现象是屏幕始终一个颜色,怎么发指令都没反应。按照优先级排查:
- 供电是否足够。1.8寸屏背光全开时电流约20-40mA,直接用STM32的3.3V输出供电没问题,但如果你用USB转TTL的3.3V供电,压降后可能只有2.8V,屏幕会出现能上电但不响应指令的情况。
- RESET时序。ST7735S的RESET低电平时间要超过10us,我习惯写20ms低电平再拉高。如果RESET接的是STM32的GPIO,初始化时一定要确认这个GPIO默认输出高电平,避免上电瞬间复位引脚被拉低。
- SPI模式。前面说过,ST7735S绝大多数是Mode 0,但也有少数兼容屏要Mode 3。如果指令发出去没反应,试着把CPOL和CPHA都改成1。
6.2 SPI硬件片选与软件片选:为什么推荐GPIO控制
CubeMX里SPI的NSS有硬件和软件两种模式。硬件NSS模式下,SPI外设会在每次传输开始时自动拉低NSS,结束时自动拉高,看似方便,但它和DMA配合时有个隐患——如果你在手动模式里对NSS电平进行控制,外设又会根据自己的状态覆盖你的设置,两者互相打架。
在TFT驱动场景里,一次有效的“写像素”操作需要先发命令,再连续发数据,中间CS必须保持低电平。如果用硬件NSS,DMA传输的每个字节之间都可能导致NSS被拉高,屏幕驱动芯片会认为一次传输结束,出现漏数据或者花屏。
我测试过至少三种不同品牌的ST7735S屏幕,软件片选(GPIO拉低拉高)在所有情况下都稳定,硬件NSS却在快速刷新时出现偶发花屏。所以最终方案是CS接普通GPIO,CubeMX里NSS类型选Disable或者NSS Soft。
6.3 UI界面卡顿:刷屏慢的瓶颈到底在哪
UI界面卡顿的源头几乎没有例外,都是flush回调里用了阻塞式发送。HAL_SPI_Transmit()会等待整个缓冲全部发送完才返回,128x160区域20行像素的数据量是5120字节,9MHz SPI下阻塞发送约4.5ms。看起来不多,但LVGL渲染一帧往往要多次调用flush,累加起来CPU就全部耗在等SPI上了。
解决办法就是本文前面用的DMA方案。改成HAL_SPI_Transmit_DMA之后,CPU发完开始指令就立即返回,刷新一帧占用的CPU时间从几十毫秒降到几微秒。之所以UI能流畅,核心不是SPI变快了,而是CPU被释放出来去执行lv_timer_handler的下一轮渲染任务。
如果已经用了DMA还觉得卡,检查是否有第三方驱动库在每次flush里主动加了HAL_Delay。有些ST7735S驱动在写数据函数里自带延时,这是为了兼容低速设备,但对DMA发送来说是多余的,把它去掉或者做成条件编译。
6.4 FreeRTOS环境下SPI中断优先级怎么设置
如果把这套工程往FreeRTOS里迁移,DMA中断优先级是个容易踩坑的地方。FreeRTOS的SysTick中断优先级一般配置为最低优先级(数值最大,比如15),FreeRTOS要求所有使用API的中断优先级数值不能低于configMAX_SYSCALL_INTERRUPT_PRIORITY。
SPI DMA的传输完成中断里如果调用了BaseType_t相关的FreeRTOS API(比如从ISR给任务发信号量),那这个中断优先级必须设置成等于或低于configMAX_SYSCALL_INTERRUPT_PRIORITY,否则会触发断言或者系统崩溃。
我这边实际配置是PendSV为最低,SysTick为次低,SPI DMA中断比SysTick高一级但比系统调用最高优先级低。这样DMA完成回调不会打断关键临界区,同时又比普通外设中断更优先,保证SPI传输完能及时通知LVGL刷新。
6.5 用逻辑分析仪抓SPI波形确认时序
调试SPI屏幕,逻辑分析仪是性价比极高的工具。不用买很贵的型号,几十块的8通道逻辑分析仪配合PulseView就够用。抓取时把SCLK、CS、DC、MOSI四根线接上,触发条件设成CS下降沿,就能看到一次完整命令序列的波形。
通过波形能快速判断几个问题:SCLK频率是否与配置一致,CS低电平时MOSI上是否有稳定数据,DC的高低电平切换是否在CS拉低之前完成。DC信号必须在CS拉低前稳定,否则屏幕会把数据误判为命令,导致显示内容错乱。
还有一个实用技巧:用逻辑分析仪测量DMA序号模式下的实际传输间隔,能看到SPI波形中间有没有异常的高电平时间片。如果在两次数据帧之间CS意外拉高,那就是硬件NSS或片选控制逻辑出了问题,直接检查片选代码。
6.6 针对128x160分辨率的具体优化建议
最后针对这块1.8寸屏整理几个终极优化方向:
- 分频系数从8分频降到4分频(即SPI时钟从9MHz提到18MHz)时,如果杜邦线长度在5cm以内且电源稳定,可以尝试。刷新率上限能提升约一倍,但稳定性需要实机验证。
- LVGL缓冲从单缓冲改成双缓冲,即两个5KB缓冲交替使用。LVGL渲染一块,SPI同时发送另一块,能让渲染和传输流水线并行。代价是RAM增加5KB,F103C8T6勉强能放下。
- 关闭LVGL不必要的特效。lv_conf.h里的LV_USE_SHADOW、LV_USE_OPA_SCROLL等特效会额外消耗CPU,在小内存平台上建议关闭。
- 如果屏幕只用于显示不触控,输入设备驱动可以完全不要,indev初始化这步跳过即可。少了输入设备的轮询,CPU占用还能再降一点。
7. 踩坑之后的一点体会
这套流程我前后跑了两轮才完全理顺。第一轮没上DMA,界面动起来以后响应迟缓,按钮按下去要等小半秒才有动画反馈;第二轮加上了DMA,又遇到硬件NSS和软件片选的问题,换来换去最终全改成GPIO控制片选才算稳定。
如果你也打算从零做SPI TFT界面,建议不要一上来就同时弄SquareLine Studio + LVGL + DMA全链路。先把屏幕驱动单独点亮,刷出纯色和简单图形;再用LVGL自带的示例工程跑一个widget页面;最后接SquareLine Studio,确认导出代码和手写LVGL代码行为一致。每一步都验证洋气了再往下一步走,翻车排查范围就会小很多。
最后留一个小技巧:SquareLine Studio在导出代码时会生成一个ui_setup.h文件,里面有一些屏幕分辨率之类的宏定义。如果你的屏幕分辨率不是128x160,比如是240x320或者320x480,修改这个文件里的宏,然后在SquareLine Studio里同步修改画布大小,重新导出,适配过程会顺畅得多。这个工具的价值就是让界面设计回归设计,而不是让程序员在坐标计算里消耗热情。