简介:面向智能手表与穿戴设备显示开发的ST77903实战DEMO,基于STM32H743、RT-Thread与LVGL构建,重点解决Sitronix小体积LCD驱动IC无内置显存、QSPI必须连续传输的难点。工程在HOST侧设置专门刷屏线程,演示QSPI持续搬运与LVGL刷新协同,并内置3个手表表盘,便于理解UI框架、显示驱动与RTOS任务划分的配合方式。压缩包共2591个文件、约13.66MB,以C/H源码、汇编启动文件、链接脚本与ICF配置、SConscript构建脚本及说明文档为主,兼有少量图片、PDF与工程配置,目录覆盖驱动、系统移植和构建配置。已有2592人学习,适合具备STM32与RT-Thread基础、希望掌握QSPI屏连续刷屏与LVGL穿戴UI落地的开发者参考。可从中获取表盘UI组织、刷屏线程设计、QSPI时序调试与多文件工程构建的完整思路。
1. 拿到 ST77903 DEMO 却卡在第一步:STM32H743 环境先列清
上周帮一个做工业面板的团队处理 ST77903 点亮问题,板子焊好了、屏也贴上了,QSPI 一接上电却是满屏花点——他们并不是不会写代码,问题在于 DEMO 的环境没有准备好:RT-Thread 版本、LVGL 版本、QSPI 时钟和 ST77903 的初始化序列,只要有一处对不上,屏幕就会黑屏或花屏。矽创 ST77903 是 400×400 的圆形 AMOLED 常用驱动 IC,接口走 QSPI,自带显存,对时序相当严格。看着只是“跑个 DEMO”,实际却是 STM32H743 + RT-Thread + LVGL + QSPI + ST77903 五层环境叠在一起,装不好就会变成一个难以排查的问题。这篇笔记写的是我按顺序把这套环境装过一遍的过程:适合刚从仓库下载 DEMO 就想直接烧录的开发者,也适合要在 H743 上复现 QSPI 屏驱动的熟手。
2. 环境准备:ST77903 SITRONIX LCD 依赖的版本与工具链
在动手建工程之前,先把“装什么”确定下来。ST77903 SITRONIX LCD 这套组合里,最容易出错的就是版本之间的隐性依赖:RT-Thread 的 SPI/QSPI 框架在 5.x 前后改动不小,LVGL 8 和 9 的显示接口几乎不一样,而 ST77903 的 DEMO 往往只针对某一个组合验证过。我一般会先做一张版本对照表,再逐项安装,避免边装边猜。
2.1 版本对照:H743 + RT-Thread + LVGL 的兼容矩阵
下表是我在这块 STM32H743 上实际跑通的一组组合。它不代表唯一答案,但作为起点是安全的;如果已经在用更新的 LVGL,请优先看lv_port_disp是否还保留原名,而不是硬把旧代码搬过去。
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| STM32H743 | 任意 H743VI/H743ZI 板 | 主频 480MHz,QSPI 内核时钟需在 200MHz 以下配置 |
| RT-Thread | 5.0.x 或 5.1.x | 使用BSP_USING_QSPI与RT_USING_SPI框架 |
| LVGL | 8.3.x | 显示接口为disp_drv.flush_cb,与 9.x 不通用 |
| ST77903 驱动 | 随 DEMO 附带的.c初始化序列 | 初始化命令表必须与供应商给的版本一致 |
| 工具链 | arm-none-eabi-gcc 10 及以上,或 Keil MDK 5.3x | GCC 与 MDK 二选一,不要中途更换 |
| 构建方式 | scons + menuconfig | 用于裁剪 RT-Thread 与 LVGL 组件 |
版本确定后还要确认一点:STM32H743 的 QSPI 与常规 SPI 是两套外设。ST77903 走的是四线 QSPI,不是 SPI1、SPI2,如果 DEMO 的底层用rt_spi_*接口去驱动,就要检查它有没有做单线模拟四线的“补丁”。这一点如果不先确认,装完之后真是会排查很久。
2.2 工具链与工程骨架搭建
先安装工具链,GCC 路径加进环境变量后,用一行命令确认版本。这里给的是 Linux 和 macOS 下常见做法;Windows 下建议用官方 ARM 工具链压缩包解压后手动加入 PATH,不要用包管理器随意安装一个不匹配的版本。
# 安装 arm-none-eabi 工具链(以 10.3 为例,版本以实际安装包为准) arm-none-eabi-gcc --version # 确认输出含 10.3 或以上 scons --version # RT-Thread 构建依赖 scons接下来拉取 RT-Thread 源码,并切换到对应 BSP。STM32H743 的 BSP 一般位于bsp/stm32/stm32h743-xxx,不同开发板的 BSP 目录名称略有差异,以仓库实际结构为准,不要照搬路径。
# 获取 RT-Thread 主仓库源码 git clone https://github.com/RT-Thread/rt-thread.git cd rt-thread/bsp/stm32/stm32h743-xxx # 注意替换成自己板子的 BSP 目录 scons --menuconfig # 进入配置界面,准备开启 QSPI 与 LVGL命令背后的逻辑不复杂:scons --menuconfig负责裁剪组件,决定编译哪些驱动进来;scons负责按 Kconfig 生成.config并调用交叉编译。这里有个习惯可以省很多时间:配置完成后,先执行一遍scons,让空工程完整编译通过,再往里加 ST77903 驱动和 LVGL。如果空工程都编译不过,就根本不是屏的问题。
2.3 QSPI 与引脚配置:先确认外设归属再写代码
/* stm32h743 QSPI 引脚初始化片段,具体引脚以板级原理图为准 */ static void qspi_pin_init(void) { /* QSPI_CLK / QSPI_NCS / QSPI_IO0~IO3 全部复用为 AF10 */ GPIO_InitTypeDef gpio = {0}; gpio.Mode = GPIO_MODE_AF_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; gpio.Alternate = GPIO_AF10_QUADSPI; /* 逐个初始化 CLK/NCS/IO0..IO3,漏掉 IO2/IO3 会退化成单线 */ HAL_GPIO_Init(QSPI_GPIO_PORT, &gpio); }要注意的是,QSPI 的四条数据线必须全部配置为复用功能,只要漏掉 IO2 或 IO3,驱动就只会以单线模式运行。可以正常显示图像,但刷新速度会慢到让你怀疑人生。QSPI 内核时钟建议先降到 100MHz 左右调通,再逐步提高到板子能稳定运行的频率,不要一上来就拉满。
3. 工程集成:把 ST77903 驱动和 LVGL 接进 RT-Thread
环境装好了,接下来是“怎么装进去”。这一步的目标很明确:让 QSPI 能发命令,让 ST77903 能收到初始化序列,再让 LVGL 的刷新回调最终写到屏上。三者串起来的关键是接口对齐,任何一层接口签名不匹配,编译能过但屏幕不会亮。
3.1 开启 RT-Thread 的 QSPI 与 SPI 框架
进入menuconfig后依次确认:RT-Thread Components → Device Drivers → Using SPI Bus/Device device drivers打开,同时在 BSP 的 board 配置里打开BSP_USING_QSPI。很多 BSP 默认只开了 SPI,没开 QSPI,编译时驱动源文件根本不会参与,现象就是“函数找不到定义”。
# 配置项检查,编译前确认这两个宏在 rtconfig.h 里存在 grep -E "RT_USING_SPI|BSP_USING_QSPI" rtconfig.h如果BSP_USING_QSPI没有出现,不用怀疑代码写错了,回到 menuconfig 里的 BSP 外设选项逐级确认;有些 BSP 把 QSPI 放在On-chip Peripheral下面,位置与 SPI 不在一处,找的时候得有耐心。
3.2 ST77903 初始化序列的移植要点
ST77903 的初始化是一张大命令表,供应商给的 DEMO 里通常是st77903_init_cmd[]这样的数组,每条包含命令、数据长度、数据内容。移植的时候最忌讳“看差不多就复制”,因为里面包含像素格式、圆形屏的窗口设置和 Gamma 参数,删几条可能还能亮,但颜色会偏。
/* ST77903 初始化:先软复位,再按顺序下发供应商命令表 */ static int st77903_init(void) { st77903_write_cmd(0x01); /* 软件复位,等待 120ms 稳定 */ rt_thread_mdelay(120); for (int i = 0; i < ARRAY_SIZE(st77903_init_cmd); i++) { /* 每条命令按 cmd + len + data 的结构依次下发 */ st77903_write_cmd(st77903_init_cmd[i].cmd); if (st77903_init_cmd[i].len) st77903_write_data(st77903_init_cmd[i].data, st77903_init_cmd[i].len); } return 0; }代码后要说明两点:st77903_write_cmd与st77903_write_data在 QSPI 模式下通常是靠命令字的高位区分“命令/数据”,不同 DEMO 写法不同,移植时以原 DEMO 的底层实现为准。另外,软复位后的延时不能省,AMOLED 面板上电稳定需要时间,时间不够时表现就是偶发白屏,重启几次又能亮,非常容易误判成焊接问题。
3.3 LVGL 显示接口对接:flush_cb 是唯一入口
LVGL 8.x 只认一个显示接口:disp_drv.flush_cb。ST77903 自带显存,所以这里有两种接法——一种是让 LVGL 直接往屏幕坐标区域写,另一种是 LVGL 画到内存 buffer 再整块刷过去。DEMO 里常见的是第二种,配合圆形屏的窗口命令使用。
/* LVGL 8.x 显示刷新回调:把 LVGL 的缓冲区刷到 ST77903 指定窗口 */ static void disp_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) { /* 先设置窗口区域,再连续写像素数据 */ st77903_set_window(area->x1, area->y1, area->x2, area->y2); st77903_write_pixels((uint8_t *)color_p, lv_area_get_width(area) * lv_area_get_height(area) * 2); lv_disp_flush_ready(drv); /* 必须调用,否则 LVGL 停在等待状态 */ }这里最容易忽略的是最后那行lv_disp_flush_ready。如果忘了调用,LVGL 会一直认为上一次刷新没结束,界面就停在那里不动,日志也没有报错。另一个参数是颜色深度:ST77903 一般用 RGB565,那么 LVGL 的LV_COLOR_DEPTH必须设成 16,设成 32 会在屏上看到错位和偏色,看起来像驱动坏了,实则只是宏没对齐。
3.4 编译下载与第一次点屏验证
# 编译并生成可烧录文件,具体输出名依赖 BSP 配置 scons -j8 # 使用 openocd 烧录,接口与目标按实际调试器修改 openocd -f interface/stlink.cfg -f target/stm32h7x.cfg \ -c "program rtthread.elf verify reset exit"烧录后先看串口日志,确认 ST77903 初始化函数返回成功、LVGL 心跳在跑。第一次点屏不要急着上复杂界面,先刷纯色块,红绿蓝各刷一次,能稳定切换就说明 QSPI 写数据和窗口设置都对了。如果颜色对调,那是 RGB565 的字节序问题,改一下lv_conf.h里的交换选项即可,不用动驱动。
4. 避坑排查:ST77903 + QSPI 组合最常见的五种翻车
这套环境能正常跑起来,往往不是因为装得顺利,而是因为遇到问题后知道该检查什么。下面几条都是我在 H743 上实际遇到过的,按“现象 → 原因 → 解决”记录,供对照排查。
4.1 花屏或雪花点
现象:上电后屏幕不是黑屏,而是随机彩色噪点,有时重启一次就正常。原因多半在 QSPI 时序:时钟频率超过面板能承受的范围,或者初始化序列没有完整下发。解决是先降到 50~80MHz 调通,再把st77903_init的命令表逐条对着供应商版本核对,重点看软复位后有没有等待足够延时。还有一种情况是 QSPI 的 dummy cycles 设置不对,读 ID 能过、写像素就乱,这类问题必须回到 QSPI 参数里改。
4.2 屏幕全黑但串口日志正常
现象:初始化函数返回成功,LVGL 也在跑,但屏幕一点反应都没有。原因通常是背光或供电没开:AMOLED 面板一般有独立的使能脚和电压轨,DEMO 里可能有一句st77903_display_on()藏在初始化末尾,被裁剪掉了。解决是回到原理图确认使能引脚,在初始化后手动拉高,再发一次 Display ON 命令(常见为 0x29)。
4.3 编译报错找不到 QSPI 相关函数
现象:驱动源文件里调用的 QSPI 接口全部报未定义。原因是没有打开 RT-Thread 的对应框架,或者 BSP 没有把 QSPI 源文件加入编译。解决是回到 menuconfig 打开BSP_USING_QSPI与 SPI 设备框架,然后执行一次scons --target=mdk5或重新生成 Makefile,让新加的源文件进入工程。只改配置不重新生成工程,是这一条最常见的遗漏。
4.4 界面能显示但刷新极慢
现象:静态画面正常,一动就卡顿,帧率低到个位数。原因一般是 QSPI 退化成了单线模式,或者 LVGL 缓冲区开得太小导致频繁分块刷新。解决是先确认 IO2、IO3 是否配置成复用,再在lv_conf.h里把LV_DISP_DEF_REFR_PERIOD和缓冲区大小调整到合理值。H743 内存够用,缓冲区开到屏幕的十分之一大小是常见做法。
4.5 烧录后反复重启
现象:程序跑几秒就复位,串口打印到一半断掉。原因大多在中断优先级或栈溢出:QSPI 中断优先级高于 RT-Thread 的系统调度,或者 LVGL 的绘制线程栈给小了。解决是检查NVIC优先级分组,保证 QSPI 中断不高于系统节拍中断,同时把 LVGL 线程栈从默认值加大到 8KB 以上再试。
5. 装完怎么验证:三个动作确认 ST77903 真的跑通
环境装完不代表跑通,必须有一组可以重复执行的验证动作。我一般在第一次调通后固定做三件事:读 ID、刷色块、跑帧率,三步都过才算这套 STM32H743 + RT-Thread + LVGL + QSPI 环境真正可用。
5.1 读 ID 与命令回读验证
/* 读取 ST77903 的 ID,确认 QSPI 双向通信正常 */ uint32_t id = st77903_read_id(); rt_kprintf("ST77903 ID: 0x%06X\n", id); /* 与手册给出的 ID 值比对 */读 ID 通过说明命令通道没问题,但它不能证明数据通道正常。有些板子读 ID 正常、写像素就异常,所以必须继续做第二步。这里也是黑匣子思维的用处:把 ID、初始化返回值、LVGL 心跳三行日志都打出来,出问题时能立刻定位是通信还是刷新环节。
5.2 色块与圆形屏边界验证
| 验证项 | 操作 | 通过标准 |
|---|---|---|
| 纯色填充 | 依次刷红、绿、蓝全屏 | 颜色正、无噪点、切换无残影 |
| 圆形边界 | 在四角与圆心各画一个矩形 | 边缘不越界、圆形区域外不显示 |
| 局部刷新 | 只刷新屏幕中心 100×100 区域 | 其余区域保持不变 |
| 帧率 | 持续刷新动画 30 秒 | 无明显卡顿、日志无复位 |
色块验证能暴露大部分窗口设置错误。ST77903 是圆形屏,如果窗口命令里的坐标没有按屏的可见区域处理,四角会出现本不该显示的像素,这一点在纯黑背景上尤其明显。
5.3 稳定性烤机与参数回退习惯
最后一件事是让画面连续跑半小时以上,同时观察串口有没有异常复位日志,用手背轻触主控和屏排线附近,确认没有明显发热。QSPI 频率如果是在临界值上调通的,短时间看不出来,跑久了才会偶发花屏,所以烤机这一步不要省。
从那以后,我每次在新板子上跑 ST77903 的 DEMO,都强制先走一遍“读 ID → 刷三色 → 烤机半小时”的流程,再往上叠 UI。这套流程本身不复杂,难的是忍住不跳步。希望这套顺序也能帮到你,少在花屏和黑屏之间来回折腾。
本文还有配套的精品资源,点击获取