ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

ESP32 上的 ST77903 QSPI LCD 驱动:从 esp_lcd_st77903_qspi 组件看接口实现与工程演进

2026/9/18 10:44:46 拓冰建站 浏览量
ESP32 上的 ST77903 QSPI LCD 驱动:从 esp_lcd_st77903_qspi 组件看接口实现与工程演进 ESP32 上的 ST77903 QSPI LCD 驱动从 esp_lcd_st77903_qspi 组件看接口实现与工程演进【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solutionST77903 是一款支持 QSPI 与 RGB 接口的 LCD 显示控制器本文聚焦 esp-iot-solution 仓库中的esp_lcd_st77903_qspi组件位于 components/display/lcd/esp_lcd_st77903_qspi完整讲解该组件在esp_lcd框架下的 QSPI 驱动实现、初始化代码、配置参数与内部工作机制。读完本文你将掌握如何基于esp_lcd_new_panel_st77903_qspi()快速点亮 400×400 级 QSPI 屏理解帧缓冲、bounce buffer、刷新/搬运双任务与 VSYNC 前后沿等底层原理并了解该组件从 v0.3.0 到 v2.0.0 的关键演进脉络。组件概览基于 esp_lcd 框架的 ST77903 QSPI 实现esp_lcd_st77903_qspi是 Espressif IoT Solution 中对 ST77903 液晶控制器的 QSPI 接口驱动实现它基于 ESP-IDF 的 esp_lcd 组件esp_lcd_panel_*抽象接口以esp_lcd_panel_t的标准操作集init、reset、draw_bitmap、mirror、swap_xy、set_gap、disp_on_off、del暴露给上层使用与 esp_lcd 生态内的其他面板驱动保持一致的 API 风格。LCD 控制器通信接口组件名称ST77903QSPIesp_lcd_st77903_qspi驱动核心源文件为 esp_lcd_st77903_qspi.c约 1310 行公共 API 定义在 esp_lcd_st77903_qspi.h组件 CMake 依赖见 CMakeLists.txtREQUIRES driver esp_lcdPRIV_REQUIRES esp_timer esp_psram。从源码结构看该驱动并非简单的SPI 刷像素而是采用了一套段segment级多事务流水线机制利用 ESP32 SPI 控制器的 multi-transactionsegment mode能力将一帧图像按行切分成多个 SPI 事务、通过事务池与中断回调连续送出配合独立的任务实现搬运-发送解耦从而在保持 QSPI 接口低成本的同时获得接近连续刷屏的带宽。版本演进从 RGB/QSPI 双接口到纯 QSPI 与 IDF v6 兼容组件的 CHANGELOG.md 记录了清晰的演进脉络读懂它有助于理解当前驱动形态的由来v2.0.02025-10-29兼容 ESP-IDF v6.0。使用新版本 IDF 的用户应优先使用此版本及之后的分支。v1.0.02024-08-12组件版本维护、代码改进与文档增强标志接口趋于稳定。v0.4.12024-05-09驱动正式上传至 espressif 仓库并同步更新 test_apps改用xPortInIsrContext()判断当前是否处于 ISR 上下文对应 load_trans_pool() 中bool in_isr (xPortInIsrContext() pdTRUE)的写法修复了lcd_write_cmd函数不可重入的问题——旧版本在中断与服务线程中同时调用写命令可能存在竞争新版本通过引入专用的write_cmd_seg事务缓冲并在写命令时以spi_device_queue_multi_trans排队解决。v0.4.02024-01-30在 esp-iot-solution 仓库中保留 RGB 接口驱动本仓库仅保留 QSPI 接口驱动。也就是说当前esp_lcd_st77903_qspi组件是经过一次接口拆分后的产物RGB 支持已被移出组件职责更聚焦。v0.3.12023-11-03修复 RGB 接口对auto_del_panel_io与mirror_by_cmd标志缺失的检查同时从 QSPI 初始化序列中移除了29h命令即 SLPOUT 之外被误加的指令。v0.3.02023-09-08首次实现 ST77903 控制器驱动同时支持 QSPI 与 RGB 接口。这一演进说明ST77903 驱动从双接口一体走向QSPI 单接口专职并在稳定性可重入、ISR 判断、构建兼容性IDF v6上持续打磨。当前版本的默认初始化序列vendor_specific_init_default也因此不再包含29h如需自定义初始化请参照下文配置方式。快速上手初始化代码与关键配置组件 READMEREADME.md给出了完整的初始化示例下面结合头文件中的配置结构体做逐段解读。1. 准备 QSPI 总线配置st77903_qspi_config_t qspi_config ST77903_QSPI_CONFIG_DEFAULT(EXAMPLE_LCD_HOST, EXAMPLE_PIN_NUM_LCD_QSPI_CS, EXAMPLE_PIN_NUM_LCD_QSPI_PCLK, EXAMPLE_PIN_NUM_LCD_QSPI_DATA0, EXAMPLE_PIN_NUM_LCD_QSPI_DATA1, EXAMPLE_PIN_NUM_LCD_QSPI_DATA2, EXAMPLE_PIN_NUM_LCD_QSPI_DATA3, 1, // fb_num帧缓冲个数 EXAMPLE_LCD_QSPI_H_RES, // 水平分辨率 EXAMPLE_LCD_QSPI_V_RES); // 垂直分辨率宏ST77903_QSPI_CONFIG_DEFAULT定义于 esp_lcd_st77903_qspi.h其默认值如下配置字段默认值说明write_pclk_hz40 MHz写时钟频率QSPI 四线并发下带宽可观read_pclk_hz1 MHz读寄存器时钟频率task.refresh_priority/load_priority23刷新/搬运任务优先级task.refresh_size/load_size3×1024 字节任务栈大小task.refresh_core/load_coretskNO_AFFINITY不固定核fb_num由宏参数传入帧缓冲个数传 0 或 1 时只分配 1 个trans_pool_size20每个事务池包含 20 个行事务trans_pool_num3事务池个数推荐至少 2最好 3flags.skip_init_host0由驱动初始化 SPI 总线flags.fb_in_psram1帧缓冲优先分配在 PSRAMflags.enable_read_reg0不使能寄存器读取flags.enable_cal_fps0不计算 FPS各字段在结构体中的语义注释见 esp_lcd_st77903_qspi.htrans_pool_size决定一个池内包含多少行数据事务同时也决定启用 PSRAM 帧缓冲时 bounce buffer 的尺寸bb_size trans_pool_size * bytes_per_linetrans_pool_num是事务池的数量池间轮转可以隐藏 SPI 发送间隙。2. 装配 vendor 配置与面板配置st77903_vendor_config_t vendor_config { .qspi_config qspi_config, // .init_cmds lcd_init_cmds, // 需要自定义初始化序列时取消注释 // .init_cmds_size sizeof(lcd_init_cmds) / sizeof(st77903_lcd_init_cmd_t), .flags { .mirror_by_cmd 1, // 通过 LCD 命令 36h 实现镜像 }, }; const esp_lcd_panel_dev_config_t panel_config { .reset_gpio_num EXAMPLE_PIN_NUM_LCD_RST, .rgb_ele_order LCD_RGB_ELEMENT_ORDER_RGB, // 通过命令 36h 生效 .bits_per_pixel EXAMPLE_LCD_BIT_PER_PIXEL, // 通过命令 3Ah 生效16/18/24 .vendor_config vendor_config, };st77903_vendor_config_t是 QSPI 专属配置入口定义见头文件 esp_lcd_st77903_qspi.h必须通过esp_lcd_panel_dev_config_t.vendor_config传入否则esp_lcd_new_panel_st77903_qspi()会直接返回ESP_ERR_INVALID_ARG。rgb_ele_order只支持LCD_RGB_ELEMENT_ORDER_RGB与LCD_RGB_ELEMENT_ORDER_BGR对应源码中madctl_val是否置位LCD_CMD_BGR_BIT见 esp_lcd_st77903_qspi.c。bits_per_pixel支持 16RGB565COLMOD0x05、18RGB6660x06、24RGB8880x07三种映射逻辑见 esp_lcd_st77903_qspi.c。3. 创建面板并按序启动esp_lcd_panel_handle_t panel_handle NULL; ESP_ERROR_CHECK(esp_lcd_new_panel_st77903_qspi(panel_config, panel_handle)); ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false)); // 仅在刷新任务未运行时调用 ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); // 控制显示开关与刷新任务启停 ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); // 启动刷新任务调用顺序是有讲究的esp_lcd_new_panel_st77903_qspi()完成 SPI 总线初始化、读写设备创建、帧缓冲/事务池/bounce buffer 分配以及esp_lcd_panel_t各操作函数的挂载esp_lcd_st77903_qspi.c。esp_lcd_panel_reset()先停止刷新任务再做硬件复位拉低/拉高/拉低 RST各延时后保持 120 ms若reset_gpio_num 0则退化为软件复位发送SWRESET见 esp_lcd_st77903_qspi.c。若启用mirror_by_cmdesp_lcd_panel_mirror()通过改写 MADCTL 寄存器的 MH/ML 位实现命令36h且必须在刷新任务未运行时调用否则返回ESP_ERR_INVALID_STATE见 esp_lcd_st77903_qspi.c。esp_lcd_panel_disp_on_off(true)发送DISPON后启动刷新任务esp_lcd_panel_disp_on_off(false)则先停止刷新任务再发送DISPOFF见 esp_lcd_st77903_qspi.c。4. 自定义初始化命令序列可选驱动默认使用vendor_specific_init_default初始化序列定义于 esp_lcd_st77903_qspi.c包含厂商解锁序列F0h/C3h、F0h/96h、F0h/A5h、Gamma 寄存器、分辨率、Sleep Out11h后延时 120 ms 等。不同厂商的 ST77903 面板初始化可能不同此时可传入自定义序列static const st77903_lcd_init_cmd_t lcd_init_cmds[] { // {cmd, {data}, data_size, delay_ms} {0xf0, (uint8_t []){0xc3}, 1, 0}, {0xf0, (uint8_t []){0x96}, 1, 0}, {0xf0, (uint8_t []){0xa5}, 1, 0}, // ... 其余命令 };st77903_lcd_init_cmd_t的四个字段分别为命令码cmd、数据指针data、数据字节数data_bytes、命令后延时毫秒delay_ms头文件 esp_lcd_st77903_qspi.h。数组须声明为static const并置于函数体外。需要特别留意的是驱动在发送自定义序列时会做冲突检查见 esp_lcd_st77903_qspi.c若序列中包含MADCTL(36h)或COLMOD(3Ah)驱动会以序列中的值覆盖内部计算的madctl_val/colmod_val并打印警告若序列中包含分辨率命令DISCN(B6h)或BPC(B5h)且数值与驱动根据hor_res/ver_res、Kconfig 中 VFP/VBP 计算出的不一致则直接跳过该条命令并打印错误避免配置冲突。深入原理段模式流水线与双任务架构这一节剖析驱动刷新一帧的完整数据通路帮助你在调参时理解各配置项的真实影响。事务池与段模式Segment Mode驱动为 QSPI 写通道创建了写设备并调用spi_bus_multi_trans_mode_enable(spi_write_dev, true)开启 SPI 段模式esp_lcd_st77903_qspi.c。在该模式下一次可连续提交一组事务每个事务的帧格式为命令段cmd ST77903_INS_DATA (0xDE)表示像素数据、ST77903_INS_CMD (0xD8)表示命令、ST77903_INS_READ (0xDD)表示读地址段24 bit((uint32_t)ST77903_CMD_HSYNC) 8即60h行同步命令置于高 16 位颜色数据事务还包含HSYNC指令字数据段一行像素bytes_per_line hor_res * bytes_per_pixel并以SPI_TRANS_MODE_QIO四线 I/O 模式传输。每个事务池trans pool包含trans_pool_size个一行一个事务的段事务trans_pool_num个池循环使用。这样一帧图像ver_res行只需按池大小分块提交ver_res / trans_pool_size次显著降低了逐行提交的系统开销。VSYNC 前后沿VFP 与 VBPST77903 在 QSPI 模式下需要主机在每帧数据前后插入行同步序列。驱动在st77903_qspi_alloc_buffers()中预先构建了两组非颜色段事务esp_lcd_st77903_qspi.cvsync_back_poolLCD_VSYNC_BACK_NUM 1个事务首条为ST77903_CMD_VSYNC (61h)其后为HSYNC(60h)占位构成后沿back porchvsync_front_poolLCD_VSYNC_FRONT_NUM个事务全部为HSYNC占位构成前沿front porch。刷新任务每帧按后沿 → 整帧颜色数据 → 前沿的顺序提交见 refresh_task。LCD_VSYNC_FRONT_NUM与LCD_VSYNC_BACK_NUM默认均为 8可通过 Kconfig 调整见下节。双任务refresh_task 与 load_memory_taskrefresh_tasklcd_refresh专职把事务池中的段事务提交给 SPI。它等待计数信号量sem_count_free_trans获得许可后将当前事务池整体spi_device_queue_multi_trans送出然后轮转池索引lcd_write_color。load_memory_tasklcd_load_mem仅当fb_in_psram使能时创建。由于当前 ESP32 SPI DMA 不能直接搬运 PSRAM 中的数据该任务从队列queue_load_mem_info取出搬运请求将帧缓冲PSRAM中的行数据memcpy到 bounce bufferSRAM32 字节对齐、MALLOC_CAP_DMAESP32-S3 上还会调用Cache_Start_DCache_Preload()预取下一段数据load_memory_task。发送完成回调post_trans_color_cb运行在 ISR 上下文颜色事务结束时调用load_trans_pool()装载下一个事务池的数据SRAM 帧缓冲场景直接释放信号量PSRAM 场景向搬运队列投递任务并借助xPortInIsrContext()判断采用 ISR 安全版本的队列/信号量操作VSYNC 后沿结束时触发on_vsync回调VFP 结束且处于等待寄存器读取状态时释放读就绪信号量post_trans_color_cb。内存分配策略st77903_qspi_alloc_buffers()esp_lcd_st77903_qspi.c按以下优先级分配内存帧缓冲fb_in_psram使能且 PSRAM 已初始化时从MALLOC_CAP_SPIRAM分配对 ESP32-C6 等无 PSRAM 或无需 PSRAM 的场景测试中会显式置fb_in_psram 0回退到内部 DMA 内存否则从MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA分配bounce buffer按trans_pool_num个、每个bb_size字节、32 字节对齐分配在内部 DMA 内存事务池trans_pool_num × trans_pool_size个spi_multi_transaction_t分配在MALLOC_CAP_DMA。从源码结构看trans_pool_size越大单次提交的行数越多、SPI 间隙越少但 bounce buffer 与事务内存占用也线性增长调参时需在带宽与内存间权衡。Kconfig 调优项组件提供 Kconfig 菜单 LCD ST77903 QSPI Configuration可调项如下配置项类型默认值范围含义LCD_ST77903_ISR_IRAM_SAFEbooln—使能后中断回调须位于 IRAM保证 cache 关闭如 SPI Flash 写入时刷新不中断代价是 IRAM 占用增加LCD_VSYNC_FRONT_NUMint80–65535VSYNC 前沿VFP行数LCD_VSYNC_BACK_NUMint80–65535VSYNC 后沿VBP行数LCD_LINE_INTERVAL_MIN_USint4240–100行间隔最小微秒数用于计算段间隙SPI_SEG_GAP_GET_USLCD_TASK_CHECK_TIME_MSint101–100刷新任务停止轮询的检查周期LCD_TASK_STOP_WAIT_TIME_MSint2001–1000停止任务后的等待时间LCD_TASK_STOP_TIME_MAX_MSint10001–10000停止刷新/搬运任务的最长等待时间超时返回ESP_ERR_TIMEOUT错误日志会提示提高任务优先级或增大此值LCD_READ_WAIT_TIME_MAX_MSint101–100等待帧结束以执行寄存器读取的超时时间其中LCD_LINE_INTERVAL_MIN_US直接影响刷屏时序段间隙时钟长度由SPI_SEG_GAP_GET_US(hor_res, bytes_per_line) MAX(LCD_LINE_INTERVAL_MIN_US, (hor_res 9) / 10) - bytes/20 - 2us计算得出esp_lcd_st77903_qspi.c对时序敏感的面板若出现花屏可优先微调该值与 VFP/VBP 行数。扩展 APIFPS、寄存器读取与帧缓冲访问除标准esp_lcd_panel_t操作外组件还提供以下专用接口均声明于 esp_lcd_st77903_qspi.hesp_lcd_st77903_qspi_register_event_callbacks()注册on_vsyncVSYNC 事件与on_bounce_frame_finishbounce buffer 完成整帧拷贝回调。回调运行在 ISR 环境当LCD_ST77903_ISR_IRAM_SAFE使能时回调与user_ctx都必须位于 IRAM源码中通过esp_ptr_in_iram()校验见 esp_lcd_st77903_qspi.c。esp_lcd_st77903_qspi_get_fps()读取当前刷新帧率仅当flags.enable_cal_fps 1时可用否则返回ESP_ERR_INVALID_STATE。刷新任务每累计 100 帧用esp_timer计算一次平均 FPS见 esp_lcd_st77903_qspi.c。esp_lcd_st77903_qspi_get_frame_buffer()获取驱动分配的帧缓冲地址fb_num可变参数形式配合draw_bitmap直接传入帧缓冲地址可跳过一次拷贝——draw_bitmap内部会先比对color_data是否命中已有帧缓冲esp_lcd_st77903_qspi.c。esp_lcd_st77903_qspi_read_reg()读取 LCD 寄存器。仅在flags.enable_read_reg 1时可用驱动会临时创建 3-wire 半双工读设备等待当前帧 VFP 结束READ_WAIT_TIME_MAX_MS超时后执行读取读取期间会临时关闭写设备的段模式lcd_read_reg。测试用例与验证方式组件自带 Unity 测试工程位于 test_apps/main/test_esp_lcd_st77903_qspi.c在 400×400、16 bpp、SPI2_HOST 的配置上验证了三条核心链路test st77903_qspi to draw color bar初始化面板后通过esp_lcd_panel_draw_bitmap绘制逐位色条验证像素格式测试中使用SPI_SWAP_DATA_TX处理字节序test st77903_qspi to read registerTEST_LCD_READ_ENABLE编译开关控制读取RDDST (0x09)寄存器并断言等于0x00265284验证读时序test st77903_qspi to rotate遍历 8 种旋转组合swap/mirror 的 x、y 组合每次先disp_on_off(false)停止刷新 → 设置mirror→disp_on_off(true)重启正是对mirror_by_cmd只能在刷新停止时调用约束的实践验证。每个测试用例前后还通过heap_caps_get_free_size检查 8-bit/32-bit 内存泄漏阈值 300 字节。测试环境的 GPIO 分配CS12、PCLK10、D013、D111、D214、D39、RST47可作硬件接线参考ESP32-C6 目标下测试会关闭 PSRAM 帧缓冲并将trans_pool_num降为 2提示了资源受限平台上的配置策略。组件测试配置见 test_apps/sdkconfig.defaults 与 test_apps/sdkconfig.defaults.esp32s3。小结esp_lcd_st77903_qspi组件为 ST77903 提供了标准、高效、可裁剪的 QSPI 驱动对外是纯正的esp_lcd面板接口对内则是事务池 段模式 刷新/搬运双任务 bounce buffer的流水线设计。使用时牢记三点mirror_by_cmd下镜像操作须在刷新任务停止时调用PSRAM 帧缓冲需要load_memory_task与 bounce buffer 兜底内存紧张的平台应关闭该选项自定义初始化序列需避开与内部分辨率/VFP/VBP 冲突的命令。参考 README.md 的初始化示例、CHANGELOG.md 的演进记录与本组件源码即可快速完成 ST77903 QSPI 屏的驱动移植与调优。【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考