尧图精选

ESP-IDF MIPI DSI 接口 LCD 驱动指南:从 DSI 总线到 DBI/DPI 双通道显示

🕒 发布时间:2026/9/16 10:24:49 📁 来源:尧图网络
ESP-IDF MIPI DSI 接口 LCD 驱动指南从 DSI 总线到 DBI/DPI 双通道显示【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf本文基于 ESP-IDFEspressif IoT Development Framework的 esp_lcd 组件系统讲解如何驱动 MIPI DSI 接口的 LCD 屏。文章以 dsi_lcd.rst 为核心脉络结合 esp_lcd_mipi_dsi.h 源码与 mipi_dsi 示例完整覆盖从创建 DSI 总线、派生 DBI 控制通道、安装 LCD 控制器驱动到通过 DPI 数据通道刷帧的全流程。读完本文你将掌握 MIPI DSI LCD 在 ESP-IDF 下的完整初始化链路、关键配置参数含义以及 DMA2D 加速与自定义 draw bitmap 钩子的进阶用法。MIPI DSI 与 esp_lcd 的分层模型MIPI DSIDisplay Serial Interface是一种高速串行显示接口常用于高分辨率 LCD。与传统的 SPI/MCU 接口 LCD 不同DSI LCD 的控制器内通常没有 GRAM显存因此主机侧必须维护帧缓冲frame buffer并通过持续刷新把像素数据流式送入屏幕。在 esp_lcd 组件中MIPI DSI 被抽象为三层结构DSI 总线Bus对应物理层的 D-PHY 与 DSI 主机控制器负责时钟与数据通道data lanes的物理传输DBI 接口控制通道基于 DSI 的 command mode用于读写 LCD 控制器芯片内部的配置寄存器发命令、传参数DPI 接口数据通道基于 DSI 的 video mode用于持续传输像素数据即刷帧。这套分层的实现位于 components/esp_lcd/dsi 目录下核心文件包括 esp_lcd_mipi_dsi_bus.c、esp_lcd_panel_io_dbi.c 和 esp_lcd_panel_dpi.c。接下来按官方推荐的初始化顺序逐步展开。第一步创建 DSI 总线并初始化 D-PHY创建 DSI 总线是整个过程的第一步调用esp_lcd_new_dsi_bus()时驱动会一并完成 D-PHY 的初始化。需要填充esp_lcd_dsi_bus_config_t结构体定义见 esp_lcd_mipi_dsi.hesp_lcd_dsi_bus_handle_t mipi_dsi_bus NULL; esp_lcd_dsi_bus_config_t bus_config { .bus_id 0, // index from 0, specify the DSI host to use .num_data_lanes 2, // Number of data lanes to use, cant set a value that exceeds the chips capability .lane_bit_rate_mbps EXAMPLE_MIPI_DSI_LANE_BITRATE_MBPS, // Bit rate of the data lanes, in Mbps }; ESP_ERROR_CHECK(esp_lcd_new_dsi_bus(bus_config, mipi_dsi_bus));各字段说明bus_id选择使用哪个 DSI 控制器从 0 开始编号num_data_lanes使用的数据通道数量。从源码注释可知若设为 0驱动会自动回退到使用芯片支持的最大通道数lane_bit_rate_mbps每条数据通道的比特率单位 Mbps直接影响最大带宽此外结构体还包含phy_clk_srcPHY PLL 的时钟源与可选标志位flags.clock_lane_force_hs强制时钟通道进入高速模式这些在基础应用中可保持默认。调用失败时可能返回的错误码包括ESP_ERR_INVALID_ARG参数非法、ESP_ERR_NO_MEM内存不足、ESP_ERR_NOT_FOUND无空闲的 DSI 硬件实例、ESP_FAIL其他错误。对应销毁接口为esp_lcd_del_dsi_bus()。第二步从 DSI 总线派生 DBI 控制接口DSI 总线创建好后需要从中派生一个 DBI 接口作为控制 IO 层用于读写 LCD 设备内部的配置寄存器例如初始化序列、背光、伽马等命令。esp_lcd_panel_io_handle_t mipi_dbi_io NULL; esp_lcd_dbi_io_config_t dbi_config { .virtual_channel 0, .lcd_cmd_bits 8, // according to the LCD spec .lcd_param_bits 8, // according to the LCD spec }; ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, dbi_config, mipi_dbi_io));esp_lcd_dbi_io_config_t见 esp_lcd_mipi_dsi.h中两个关键字段virtual_channel虚拟通道号。虚拟通道是 DSI 中用于多路复用不同数据源的逻辑通道。如果只接一块 LCD直接设为0lcd_cmd_bits/lcd_param_bitsLCD 控制器芯片能识别的命令与参数的位宽这是芯片相关的需要事先查阅你的 LCD 规格书。绝大多数 MIPI DSI LCD 控制器使用 8 位命令、8 位参数。需要留意的一点源码注释中有明确说明虽然这里命名为 DBI但驱动内部实际使用的是 DSI 的 generic 接口来收发 LCD 命令与参数。第三步安装 LCD 控制器驱动有了 DBI IO 句柄后即可安装 LCD 控制器驱动。控制器驱动负责把命令与参数真正发送给 LCD 控制芯片。这里以常见芯片 ILI9881C 为例对应实现文件 esp_lcd_ili9881c.h 位于 esp_lcd 组件esp_lcd_panel_handle_t ili9881c_ctrl_panel NULL; esp_lcd_panel_dev_config_t lcd_dev_config { .bits_per_pixel 24, // MIPI LCD usually uses 24 bit (i.e., RGB888) per pixel .rgb_ele_order LCD_RGB_ELEMENT_ORDER_RGB, .reset_gpio_num EXAMPLE_PIN_NUM_LCD_RST, }; ESP_ERROR_CHECK(esp_lcd_new_panel_ili9881c(mipi_dbi_io, lcd_dev_config, ili9881c_ctrl_panel));esp_lcd_panel_dev_config_t中三个对本场景最重要的字段bits_per_pixel每个像素的位宽。LCD 驱动会用它计算需要发送给控制芯片的字节数。MIPI LCD 通常使用 24 bit即 RGB888reset_gpio_num复位引脚对应的 GPIO 编号。若 LCD 控制器芯片没有复位引脚可设为-1示例中EXAMPLE_PIN_NUM_LCD_RST即定义为-1rgb_ele_order像素数据的 RGB 元素顺序可选LCD_RGB_ELEMENT_ORDER_RGB或LCD_RGB_ELEMENT_ORDER_BGR枚举定义见 esp_lcd_types.h。拿到控制面板句柄后就可以复位 LCD、执行基础初始化并点亮显示ESP_ERROR_CHECK(esp_lcd_panel_reset(ili9881c_ctrl_panel)); ESP_ERROR_CHECK(esp_lcd_panel_init(ili9881c_ctrl_panel)); ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(ili9881c_ctrl_panel, true));注意这里esp_lcd_panel_disp_on_off(..., true)控制的是 LCD 控制器的显示开关与背光 GPIO 的亮灭由 BSP 层自行管理是两回事。第四步分配 DPI 数据面板用于刷帧此时还不能用控制面板发送像素数据——因为 MIPI LCD 分辨率高且控制器内没有 GRAM。必须由主机侧维护帧缓冲并通过 MIPI DSI 的 DPI 接口把帧缓冲持续刷到 LCD 上。创建 DPI 数据面板需要提供包括 DPI 时钟频率、像素格式、视频时序在内的大量参数esp_lcd_panel_handle_t mipi_dpi_panel NULL; esp_lcd_dpi_panel_config_t dpi_config { .virtual_channel 0, .dpi_clk_src MIPI_DSI_DPI_CLK_SRC_DEFAULT, .dpi_clock_freq_mhz 1 * 1000, .in_color_format LCD_COLOR_FMT_RGB888, .video_timing { .h_size EXAMPLE_MIPI_DSI_LCD_H_RES, .v_size EXAMPLE_MIPI_DSI_LCD_V_RES, .hsync_back_porch EXAMPLE_MIPI_DSI_LCD_HBP, .hsync_pulse_width EXAMPLE_MIPI_DSI_LCD_HSYNC, .hsync_front_porch EXAMPLE_MIPI_DSI_LCD_HFP, .vsync_back_porch EXAMPLE_MIPI_DSI_LCD_VBP, .vsync_pulse_width EXAMPLE_MIPI_DSI_LCD_VSYNC, .vsync_front_porch EXAMPLE_MIPI_DSI_LCD_VFP, }, }; ESP_ERROR_CHECK(esp_lcd_new_panel_dpi(mipi_dsi_bus, dpi_config, mipi_dpi_panel)); ESP_ERROR_CHECK(esp_lcd_panel_init(mipi_dpi_panel));esp_lcd_dpi_panel_config_t见 esp_lcd_mipi_dsi.h关键字段逐一说明virtual_channel与 DBI 接口同理仅接一块屏时设为0dpi_clk_srcDPI 接口的时钟源可选值见mipi_dsi_dpi_clock_source_t枚举常用MIPI_DSI_DPI_CLK_SRC_DEFAULTdpi_clock_freq_mhzDPI 像素时钟频率MHz。像素时钟越高刷新率越高但如果 DMA 带宽不足或 LCD 控制器芯片不支持高像素时钟可能引起闪烁需要按 LCD 规格书与硬件带宽综合权衡in_color_format输入像素数据格式可选值见lcd_color_format_t。MIPI LCD 通常用RGB888以获得最佳色彩深度video_timingLCD 屏特有的时序参数类型为esp_lcd_video_timing_t必须按 LCD 数据手册填写。esp_lcd_video_timing_t定义见 esp_lcd_types.h各成员含义成员含义h_size水平分辨率即每行像素数v_size垂直分辨率即每帧行数hsync_pulse_width水平同步脉冲宽度以像素时钟计hsync_back_porch水平后廊hsync 结束到行有效数据开始之间的像素时钟数hsync_front_porch水平前廊行有效数据结束到下一个 hsync 之间的像素时钟数vsync_pulse_width垂直同步脉冲宽度以行数计vsync_back_porch垂直后廊vsync 结束到帧起始之间的无效行数vsync_front_porch垂直前廊帧结束到下一个 vsync 之间的无效行数时序参数与刷新率的换算关系刷新率 dpi_clock_freq_mhz × 1e6 / (H_total × V_total)其中H_total h_size hsync_pulse_width hsync_back_porch hsync_front_porchV_total v_size vsync_pulse_width vsync_back_porch vsync_front_porch。示例 mipi_dsi_lcd_example_main.c 中给出了两组可直接验证的配置ILI9881C800×1280刷新率 80000000/(4014040800)/(416161280) 60Hz即dpi_clock_freq_mhz 80EK790071024×600刷新率 48000000/(101201201024)/(12010600) 60Hz即dpi_clock_freq_mhz 48。另外esp_lcd_dpi_panel_config_t还包含两个进阶字段out_color_format输出像素格式即面板可接受的格式用于输入输出格式不一致时的转换场景与num_fbs驱动分配的整屏帧缓冲数量默认 0 或 1 表示只创建一个帧缓冲。DPO 面板创建成功后可用esp_lcd_dpi_panel_get_frame_buffer()拿到驱动分配的帧缓冲地址也可用esp_lcd_dpi_panel_set_pattern()输出预定义测试图案用于调试。第五步配置 draw bitmap 钩子可选DPI 面板驱动支持通过钩子机制接管esp_lcd_panel_draw_bitmap()的像素搬运过程适用于 DMA2D 加速、旋转、缩放等场景。内置 DMA2D 加速如果希望用DMA2D来实现 draw bitmap驱动已经内置了对应的钩子函数只需调用esp_lcd_dpi_panel_enable_dma2d()即可启用ESP_ERROR_CHECK(esp_lcd_dpi_panel_enable_dma2d(mipi_dpi_panel));硬件限制提醒由于硬件限制若使能了外部内存加密flash encryptionDMA2D 只能访问地址与长度均按SOC_GDMA_EXT_MEM_ENC_ALIGNMENT字节对齐的内存。你必须保证 draw buffer 的地址与长度按该值对齐。官方示例peripherals/lcd/mipi_dsi演示了如何用 LVGL 的LV_EVENT_INVALIDATE_AREA事件回调来约束重绘区域、强制把刷新区域对齐到 16 字节从而规避 MSPI 错误。在示例 mipi_dsi_lcd_example_main.c 中可以看到这段对齐逻辑void example_rounder_flush_area_cb(lv_event_t * event) { lv_area_t * area lv_event_get_invalidated_area(event); area-x1 ESP_ALIGN_DOWN(area-x1, 16); area-x2 ESP_ALIGN_UP(area-x2, 16) - 1; }同时示例在使能 flash encryption 时把 LVGL draw buffer 的分配对齐到SOC_GDMA_EXT_MEM_ENC_ALIGNMENT见 mipi_dsi_lcd_example_main.c。与之对称的关闭接口为esp_lcd_dpi_panel_disable_dma2d()。自定义 draw bitmap 钩子如需更高级的应用例如用PPA硬件加速器实现旋转、缩放、色彩空间转换等可以注册自定义钩子esp_lcd_panel_hooks_t hooks { .draw_bitmap_hook custom_draw_bitmap_hook, }; ESP_ERROR_CHECK(esp_lcd_dpi_panel_register_hooks(mipi_dpi_panel, hooks, user_ctx));钩子回调的原型为esp_lcd_panel_draw_bitmap_hook_t其参数esp_lcd_draw_bitmap_hook_data_t见 esp_lcd_mipi_dsi.h携带了完整的目标/源缓冲信息目标帧缓冲指针与目标区域坐标、源位图数据指针与源区域坐标、每像素位宽以及钩子完成时回调on_hook_end。源码注释特别强调钩子需要自行保证绘制操作的同步。此外多次调用esp_lcd_dpi_panel_register_hooks()会覆盖之前注册的钩子。除 draw bitmap 钩子外DPI 面板还支持事件回调注册esp_lcd_dpi_panel_register_event_callbacks()包括on_color_trans_done用户 draw buffer 拷贝到帧缓冲完成可安全回收 draw buffer、on_frame_buf_complete帧缓冲可安全复用的信号替代已废弃的on_refresh_done以及on_vsyncVSYNC 事件。示例中正是利用on_color_trans_done回调去通知 LVGL 刷新完成static bool example_notify_lvgl_flush_ready(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx) { lv_display_t *disp (lv_display_t *)user_ctx; lv_display_flush_ready(disp); return false; }MIPI DPHY 的电源供应MIPI DSI 驱动能否正常工作硬件上还有一个前提条件芯片上的 MIPI DPHY 需要一路专用的 2.5V 电源。请对照原理图确认电源引脚丝印通常为VDD_MIPI_DPHY已正确连接到 2.5V 电源再使用 MIPI DSI 驱动。在支持内部可调 LDO对应 Kconfig 能力SOC_GP_LDO_SUPPORTED的芯片上MIPI DPHY 可以由内部 LDO 供电把 LDO 通道的输出引脚接到 MIPI DPHY 电源引脚并在初始化 DSI 驱动之前使用 LDO 调节器 API参见文档 ldo_regulator把 LDO 输出电压配置为 2.5V。示例 mipi_dsi_lcd_example_main.c 中的 BSP 层演示了完整做法定义EXAMPLE_MIPI_DSI_PHY_PWR_LDO_CHAN 3LDO_VO3 连接到 VDD_MIPI_DPHY与EXAMPLE_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV 2500然后在创建 DSI 总线之前调用esp_ldo_acquire_channel()使能该通道使 DPHY 从 No Power 状态进入 Shutdown 状态随后才执行esp_lcd_new_dsi_bus()。从示例工程看完整落地流程官方示例 examples/peripherals/lcd/mipi_dsi 将上述步骤串成了一个可运行的 LVGL 应用其主流程见 mipi_dsi_lcd_example_main.c可归纳为初始化刷新监测 GPIO可选→ 使能 DSI PHY 电源 → 初始化并熄灭背光创建 DSI 总线esp_lcd_new_dsi_bus安装 DBI 控制 IOesp_lcd_new_panel_io_dbi按 Kconfig 选择 ILI9881C 或 EK79007填充vendor_config内含 DSI 总线句柄与 DPI 配置后创建数据面板esp_lcd_new_panel_ili9881c/esp_lcd_new_panel_ek79007按需使能 DMA2Desp_lcd_dpi_panel_enable_dma2d复位并初始化面板点亮背光初始化 LVGL创建 display、设置 RGB888 色彩格式、从 PSRAM 分配双 draw buffer、设置 flush 回调注册 DPI 面板事件回调on_color_trans_done通知 LVGL 刷屏完成on_vsync用于刷新率监测用esp_timer提供 LVGL tick创建 LVGL 任务并加载示例 UI。其中第 4 步值得注意ILI9881C/EK79007 这类控制器驱动的vendor_config中携带了dsi_bus与dpi_config指针这意味着控制面板与数据面板共用同一条 DSI 总线——DBI 负责初始化命令DPI 负责持续刷帧二者通过虚拟通道在同一物理链路上协同工作。小结MIPI DSI LCD 的驱动链路可以概括为一条总线、两条通道esp_lcd_new_dsi_bus()建立物理层esp_lcd_new_panel_io_dbi()建立寄存器控制通道esp_lcd_new_panel_dpi()建立像素数据通道。相比 SPI LCDDSI LCD 的关键差异在于主机侧必须自建帧缓冲并持续刷帧因此video_timing与dpi_clock_freq_mhz的取值直接决定了画面能否稳定刷新。在此基础上DMA2D 内置钩子与自定义 draw bitmap 钩子如 PPA 旋转/缩放为高性能 UI 渲染提供了扩展空间。动手实践时建议从examples/peripherals/lcd/mipi_dsi示例出发对照本文各字段说明修改为自家 LCD 的规格参数并务必先确认VDD_MIPI_DPHY的 2.5V 供电已就绪。【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →