资讯动态

STM32H743上RT-Thread+LVGL+QSPI驱动ST77903全流程

发布时间:2026/10/20 11:46:37 来源:尧图企业网站定制
简介这份资源是矽创ST77903小体积LCD驱动IC的完整使用DEMO面向嵌入式显示开发工程师与穿戴设备方案开发者运行环境为STM32H743 RT-Thread LVGL通过QSPI接口驱动屏幕。由于ST77903内部不带显存QSPI必须连续传输HOST端需使用专门线程完成刷屏DEMO中已给出这一关键机制的实现范例并内置3个手表表盘界面可直接作为穿戴类UI项目的参考起点。压缩包共2591个文件约13.66MB以1090个h头文件与1016个c源文件为主体配合135个s汇编、69个SConscript构建脚本、48个icf与16个ld链接配置另有Kconfig、Makefile、CMake等工程文件及少量png、gif素材与pdf文档完整呈现RT-Thread与LVGL的目录组织方式。目前已有2588人学习下载适合希望快速跑通ST77903显示链路、理解QSPI连续刷屏线程设计的开发者参考。1. 矽创 ST77903 驱动 DEMOSTM32H743 上跑通 RT-Thread LVGL QSPI 的完整路径如果你手头正好有一块 ST77903 的屏又不想从零去啃矽创那份寄存器手册这个 DEMO 值得先跑一遍。它把 STM32H743、RT-Thread、LVGL、QSPI 和 ST77903 这几层串成了一条能直接编译下载的链路省掉了自己搭工程、对时序、调初始化的时间。ST77903 是矽创面向中小尺寸 TFT 的驱动 IC常见于 320×480 到 480×800 这类分辨率接口支持 SPI/QSPI很多便携设备、工控面板都在用。这个 DEMO 的价值不在于功能多花哨而在于它把 QSPI 四线高速刷屏和 LVGL 的对接做通了适合已经熟悉 STM32 和 RT-Thread、想快速验证 ST77903 显示效果的嵌入式开发者。2. 工程结构与三层驱动模型从 QSPI 到 LVGL 的数据流拿到一个 DEMO先别急着编译把目录结构和数据流理清楚后面改起来才不慌。这个工程的分层思路很典型底层是 STM32H743 的 QSPI 外设配置中间是 ST77903 的寄存器操作和显存刷新上层是 RT-Thread 的设备框架和 LVGL 的显示驱动接口。三层各管各的耦合点集中在两个地方——QSPI 的读写函数和 LVGL 的 flush_cb 回调。2.1 目录布局与关键文件职责工程大致会分成这么几块bsp下放 STM32H743 的时钟、GPIO、QSPI 初始化drivers下是 ST77903 的驱动文件通常叫drv_st77903.c和对应的头文件lvgl是移植好的 LVGL 源码和lv_port_disp.capplications里是 main 线程和界面 demo。RT-Thread 的rtconfig.h决定了开哪些组件QSPI 设备驱动是否使能、LVGL 的 tick 来源都在这里配。关键文件职责可以对照下面这张表文件职责改动频率bsp_qspi.cQSPI 时钟、引脚、DMA 配置换板子才改drv_st77903.c初始化序列、读写寄存器、刷屏换屏或调时序时改lv_port_disp.cLVGL 显示注册、flush 回调分辨率或颜色格式变时改rtconfig.h组件开关、QSPI 设备使能按需调整我一般会先看drv_st77903.c里的初始化序列因为 ST77903 上电后需要一串寄存器写入才能正常显示顺序错了就是白屏或者花屏。2.2 QSPI 四线模式与 ST77903 的对接逻辑STM32H743 的 QSPI 支持单线、双线、四线模式ST77903 在 QSPI 下通常用四线发数据。这里有个容易忽略的点命令和地址阶段可能还是单线只有数据阶段切四线具体要看 ST77903 的时序要求。DEMO 里一般会配成QSPI_ACCESS_INDIRECT_WRITE模式把要发的数据塞进 FIFO 再触发传输。下面是一段典型的 QSPI 写数据函数基于 HAL 库风格/* 向 ST77903 写入数据使用 QSPI 间接写模式 */ void st77903_qspi_write(uint8_t *buf, uint32_t len) { QSPI_CommandTypeDef cmd {0}; cmd.Instruction 0x02; /* QSPI 写命令具体值看 ST77903 手册 */ cmd.InstructionMode QSPI_INSTRUCTION_1_LINE; cmd.AddressMode QSPI_ADDRESS_NONE; cmd.DataMode QSPI_DATA_4_LINES; /* 数据阶段走四线 */ cmd.NbData len; cmd.DummyCycles 0; HAL_QSPI_Command(hqspi, cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); HAL_QSPI_Transmit(hqspi, buf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); }这段代码的逻辑是先配置命令结构体指定命令阶段单线、数据阶段四线然后发命令再发数据。参数里Instruction的值必须和 ST77903 手册对上不同批次或不同模式可能不一样。DataMode改成QSPI_DATA_1_LINE就退回单线刷屏速度会明显下降调试时可以先用单线确认能显示再切四线提速。提示QSPI 时钟频率不要一上来就拉满STM32H743 的 QSPI 在高频下对 PCB 走线敏感先降到 20MHz 左右确认稳定再逐步往上加。2.3 RT-Thread 设备框架下的驱动注册RT-Thread 的好处是设备管理统一QSPI 可以注册成qspi10这样的设备名ST77903 驱动通过rt_device_find拿到句柄再操作。DEMO 里通常会在drv_st77903.c的初始化函数里完成注册然后在 main 线程里打开设备。/* ST77903 驱动初始化注册为 RT-Thread 设备 */ static int st77903_init(void) { rt_device_t qspi_dev rt_device_find(qspi10); if (qspi_dev RT_NULL) { rt_kprintf(qspi10 not found!\n); return -RT_ERROR; } rt_device_open(qspi_dev, RT_DEVICE_FLAG_RDWR); /* 执行 ST77903 上电初始化序列 */ st77903_hw_init(); /* 注册显示设备供 LVGL 使用 */ st77903_disp_register(); return RT_EOK; } INIT_DEVICE_EXPORT(st77903_init);这里用INIT_DEVICE_EXPORT把初始化挂到 RT-Thread 的自动初始化流程里系统启动时会自己调用。st77903_hw_init里就是那一长串寄存器写入st77903_disp_register负责把显示设备挂到 RT-Thread 的设备链表上。如果启动后找不到设备先查rt_device_find的返回值再看rtconfig.h里 QSPI 驱动有没有使能。3. LVGL 移植与刷屏优化flush_cb 怎么写才不撕裂LVGL 本身不直接操作硬件它通过一个flush_cb回调把渲染好的区域推给屏幕。这个回调写得好不好直接决定刷屏流不流畅、有没有撕裂感。DEMO 里这部分是重点也是新手最容易翻车的地方。3.1 LVGL 显示驱动注册与缓冲区配置LVGL 需要至少一个绘制缓冲区大小可以是屏幕的 1/10 到全屏。缓冲区越大刷新越流畅但吃 RAM。STM32H743 有 1MB RAM跑 480×800 的屏开 1/4 屏缓冲比较稳妥。/* LVGL 显示缓冲区配置放在 SDRAM 或内部 RAM */ #define DISP_BUF_SIZE (480 * 800 / 4) static lv_color_t buf1[DISP_BUF_SIZE]; void lv_port_disp_init(void) { static lv_disp_draw_buf_t draw_buf; lv_disp_draw_buf_init(draw_buf, buf1, NULL, DISP_BUF_SIZE); static lv_disp_drv_t disp_drv; lv_disp_drv_init(disp_drv); disp_drv.hor_res 480; disp_drv.ver_res 800; disp_drv.flush_cb st77903_flush_cb; disp_drv.draw_buf draw_buf; lv_disp_drv_register(disp_drv); }lv_disp_draw_buf_init的第三个参数是缓冲区能存的像素数这里取了屏幕的四分之一。hor_res和ver_res必须和 ST77903 实际分辨率一致填错了画面会错位。flush_cb指向自己实现的刷屏函数LVGL 每次渲染完一块区域就会调它。3.2 flush_cb 的实现与 DMA 传输flush_cb收到的是lv_disp_drv_t和lv_area_t里面标了要刷新的区域坐标和颜色数据指针。ST77903 需要先设窗口再写数据所以回调里分两步设窗口、发像素。/* LVGL 刷屏回调把渲染好的区域推给 ST77903 */ static void st77903_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) { /* 设置 ST77903 显示窗口 */ st77903_set_window(area-x1, area-y1, area-x2, area-y2); /* 计算像素字节数RGB565 每像素 2 字节 */ uint32_t px_cnt (area-x2 - area-x1 1) * (area-y2 - area-y1 1); st77903_qspi_write((uint8_t *)color_p, px_cnt * 2); /* 通知 LVGL 刷新完成 */ lv_disp_flush_ready(drv); }st77903_set_window里发的是列地址和行地址设置命令把要写的区域框出来。px_cnt * 2是因为 RGB565 每个像素占两个字节。最后必须调lv_disp_flush_ready否则 LVGL 会一直等界面就卡住了。如果刷屏有撕裂常见做法是开双缓冲或者用 DMA 传输加垂直同步但 ST77903 一般没有 TE 引脚引出所以 DEMO 里多半是单缓冲直接刷靠提高 QSPI 速率来压撕裂。注意color_p指向的缓冲区在lv_disp_flush_ready调用前不能被改写如果用了 DMA要等 DMA 传输完成再调 ready否则会花屏。3.3 刷屏速率实测与参数调整刷屏速率主要受三个因素影响QSPI 时钟、数据线数、以及每次刷新的区域大小。我一般会用一个简单的计数法测在flush_cb里翻转一个 GPIO用示波器看频率或者用 RT-Thread 的rt_tick_get算每秒刷新次数。假设 QSPI 时钟 50MHz四线模式下理论带宽是 50M × 4 / 8 25MB/s刷一屏 480×800×2 768KB理论最快约 30 帧。实际因为命令开销和 LVGL 渲染耗时能到 15 到 20 帧就算不错。如果帧率明显偏低先查 QSPI 时钟是不是被分频拉低了再看flush_cb里有没有多余的延时。4. 避坑与排查ST77903 调试中最容易翻车的五个点这个 DEMO 跑通不难但中间有几个坑几乎每个人都会踩一遍。下面这五条是我自己调试时记下来的按现象、原因、解决来写。现象一上电后屏幕全白背光亮但没图像。原因通常是初始化序列没发完或者发错了。ST77903 上电后需要等一段时间再发初始化命令有些 DEMO 里用rt_thread_mdelay延时如果延时不够芯片还没准备好后续命令全丢。解决方法是把上电延时加到 120ms 以上再逐条确认初始化命令的寄存器地址和参数值是否和手册一致。现象二画面能显示但颜色不对红色变蓝色。这是 RGB 顺序配错了。ST77903 支持 RGB 和 BGR 两种像素顺序初始化序列里有一个寄存器控制这个。LVGL 默认按 RGB565 发数据如果屏幕端设成了 BGR红蓝就对调。解决办法是找到初始化序列里控制颜色顺序的寄存器改成和 LVGL 一致或者在flush_cb里手动交换 R 和 B 分量。现象三刷屏时画面撕裂上半屏和下半屏不同步。单缓冲直接刷屏时如果 QSPI 传输还没完成LVGL 已经开始渲染下一帧并改写缓冲区就会撕裂。常见做法是开双缓冲让 LVGL 渲染和 QSPI 传输交替进行。如果 RAM 不够开双缓冲可以缩小刷新区域让每次传输的数据量小一点撕裂会减轻但不会完全消失。现象四QSPI 四线模式一开就花屏单线正常。四线模式对时序和走线要求高如果 PCB 上 QSPI 的四根数据线长度差异大或者没有做等长高频下就会采样错误。先降 QSPI 时钟到 20MHz 试试如果单线正常四线花屏基本就是信号完整性问题。解决方法是降低时钟、检查走线或者在 QSPI 配置里增加 dummy cycles 给信号留出建立时间。现象五LVGL 界面卡死点按钮没反应。先查lv_disp_flush_ready有没有被调用。如果flush_cb里因为 QSPI 传输失败提前返回没调 readyLVGL 就会一直等整个界面线程卡住。另外 RT-Thread 里 LVGL 的 tick 来源要确认通常用rt_tick_get或者一个硬件定时器tick 不走 LVGL 的任务就不处理。解决方法是加错误处理QSPI 传输失败也要调 ready同时确认 tick 中断正常。5. 进阶技巧用 RT-Thread 的 SFUD 和 DMA 把刷屏做到极致DEMO 跑通之后如果想把刷屏速率再往上推一截有两个方向可以挖一是把 QSPI 传输改成 DMA 模式二是用 RT-Thread 的 SFUD 组件管理 QSPI 设备。DMA 模式能让 CPU 在刷屏时去干别的LVGL 渲染和 QSPI 传输可以并行帧率提升明显。先看 DMA 配置。STM32H743 的 QSPI 支持 MDMA 和 DMA用 HAL 库的话把HAL_QSPI_Transmit换成HAL_QSPI_Transmit_DMA然后在 DMA 传输完成回调里调lv_disp_flush_ready。/* QSPI DMA 传输完成回调通知 LVGL 刷新完成 */ void HAL_QSPI_TxCpltCallback(QSPI_HandleTypeDef *hqspi) { if (hqspi-Instance QUADSPI) { /* 传输完成通知 LVGL 可以渲染下一帧 */ lv_disp_flush_ready(disp_drv); } } /* flush_cb 里改用 DMA 传输 */ static void st77903_flush_cb(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); uint32_t px_cnt (area-x2 - area-x1 1) * (area-y2 - area-y1 1); /* 用 DMA 发数据完成后在回调里调 ready */ st77903_qspi_write_dma((uint8_t *)color_p, px_cnt * 2); }这里的关键是lv_disp_flush_ready不能在flush_cb里直接调了要挪到 DMA 完成回调里。否则 DMA 还没传完LVGL 就以为刷完了会改写缓冲区导致花屏。参数上DMA 的优先级要设得比 LVGL 任务高不然传输会被打断。另一个方向是用 SFUD。RT-Thread 的 SFUD 组件本来是用来管理 SPI Flash 的但它的设备框架可以借鉴把 ST77903 的 QSPI 操作封装成标准设备接口这样换屏或者换 QSPI 控制器时上层代码不用动。我一般会在drv_st77903.c里实现一套rt_qspi_device的操作函数注册到 RT-Thread 的 QSPI 设备框架下LVGL 那边只认显示设备不关心底层是 QSPI 还是 SPI。最后说一个验证方法在flush_cb里加一个计数器每秒打印一次刷新次数同时用rt_tick_get算实际帧率。如果帧率和理论值差距大先查 QSPI 时钟再查 DMA 有没有真正启用最后看 LVGL 的渲染耗时是不是成了瓶颈。我习惯在调刷屏时把 LVGL 的LV_USE_PERF_MONITOR打开它能直接显示 CPU 占用和帧率比手动算省事。从那以后我每次拿到新的屏驱动 DEMO都强制先跑一遍单线模式确认初始化序列没问题再切四线、加 DMA、调时钟一步一步来不跳步。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑