试用 LVGL Pro,一套完整的工具包,助您高效构建、测试、分享和交付 UI!
LVGL
教程

使用 LVGL 和 ESP32 驱动 iPod Nano 6 LCD

详细指南:使用 ESP32 和 SSD2805 桥接芯片驱动 iPod Nano 6 MIPI 显示屏并集成 LVGL。

John LeungJohn Leung12 分钟阅读

本教程展示如何使用 Espressif ESP32 WiFi/BLE SoC 为 LVGL 改造 Apple iPod Nano 6 的屏幕。

所有源代码可在本页末尾下载。

LVGL 在 iPod Nano 6 显示屏上运行
LVGL 在 iPod Nano 6 显示屏上运行

理解 MIPI DSI#

iPod Nano 6 的 LCD 使用 MIPI 显示串行接口(MIPI DSI),这是主机处理器与显示模块之间的高速串行接口。此类 LCD 在智能手机、平板电脑和智能手表中非常常见。参考规范可从 MIPI Alliance 页面获取。

各种 MIPI 显示屏
MIPI 显示屏集合

在 Google 上搜索关键词 MIPI 会出现数百页的 PDF 文档。从像这样的规范中学习总是很有趣。它指出"MIPI DSI 规定了主机处理器与显示器之间的接口……",并附有如下图表:

MIPI 接口图
MIPI 接口图

如果 100 页的规范需要太多时间,这篇 EDN 文章可能就是您需要了解的关于 MIPI D'PHY RX 的全部内容。

MIPI 的传输速度非常高,从 1.0 Gbps/lane 到 4.5 Gbps/lane 不等,有 1-4 条数据通道加上 1 条时钟信号,全部使用差分总线。差分总线驱动的电压摆幅也与 RGB/MCU 类型的 LCD 不同。对于 MIPI DSI,有高速(HS)和低速(LS)模式,分别驱动 200mV 峰峰值和 1.2V,而 RGB/MCU 类型 LCD 的数据使用与 MCU 主机 VDDIO 匹配的单端信号传输。

MIPI 与传统 LCD 对比表
MIPI 和传统 LCD 接口的对比

通常,MIPI LCD 的接口需要的引脚数量和电压都远低于其 MCU/RGB 对应产品。

MIPI 与传统 LCD 引脚对比
引脚对比显示 MIPI 所需引脚更少

SSD2805 MIPI 桥接芯片#

问题是:当我们的 MCU(如 ESP32)没有 DSI 输出时,如何驱动 MIPI 显示屏,以及如何将其移植到 LVGL?这时就需要 MIPI 桥接 IC - SSD2805,它是一种接口芯片,可在 RGB/8080 视频信号和 MIPI 信号之间进行转换。

SSD2805 芯片顶视图
SSD2805 芯片顶视图

这是一个非常小的芯片,5×5mm,0.5mm 间距 BGA!

SSD2805 芯片底视图
SSD2805 芯片底视图

系统架构#

显示 ESP32、SSD2805 和 iPod Nano 6 LCD 连接的系统框图
完整设置的框图

ESP32 使用 ESP-IDF(Espressif IoT 开发框架)编程。安装步骤在 Espressif 文档网站有详细描述。我的主机是 Windows 7 Pro SP1 64 位,Intel Core i5 处理器和 8GB 内存。我遵循 ESP-IDF 入门指南中描述的默认安装路径,该路径在 C:\msys32\ 下提供了 mingw32.exe 应用程序。

mingw32 文件夹结构
mingw32 文件夹结构

起初我对像 mingw32.exe 这样的命令行工具不太习惯。经过无数次 Google 搜索后,我尝试安装 Eclipse IDE。不幸的是,在 Eclipse 上花费的所有时间都白费了。最后我发现配置 Eclipse 的时间甚至比编程本身还多,所以我放弃了。不要误会 - Eclipse 并不差,我只是无法让它工作。

由于没有 ESP32 + SSD2805 + MIPI 显示屏组合的标准评估套件,我被迫使用跳线来连接所有东西,搞得一团糟,如下所示:

杂乱的跳线连接
原型开发时不可避免的线缆混乱

硬件设置#

使用的开发板包括:

  1. ESP32-Pico-Kit v4
  2. SSD2805 扩展板 Release 3
  3. 1.54 英寸 LH154Q01 MIPI 显示屏,PCB 上带有 CTP。SSD2541 CTP 驱动焊接在此板上。
  4. 加上大量跳线!

引脚图如下所示:

ESP32 到 LCD 引脚图
完整的引脚连接

重要说明#

  1. 在 SSD2805 扩展板上,VDDIO_CTRL 引脚应拉低以导通 VDDIO_CORE 的 MOSFET。
  2. EXT_5V 应提供 5V 电源(USB 供电即可)。这是为背光控制器 IC 供电。
  3. 背光控制器 IC 的 PWM 引脚应拉高(3.3V)以启用它。
  4. SSD2805 EVK 上的 DIP 开关设置从左到右为:01000011(DIP 开关上 0=ON)。
  5. SSD2805 EVK 板上的 PCLK/RD# 应拉高,而不是悬空。此引脚默认为下拉引脚。如果不需要读取操作,将其拉高以永久驱动 RD# 引脚为高电平。

软件开发#

要使用 LVGL,前提是在其外部有完全工作的 LCD 和触摸屏驱动。我从 5 个源文件的程序开始驱动 LCD:

1. i2s_8080_hello_world.c
2. SSD2805_8080_drv.c and .h
3. i2s_lcd.c and .h

源文件 i2s_lcd.c.h 从它们的 GitHub 源代码修改而来。

ESP32 使用 I2S 模块以 8080 8 位并行模式写入。DMA 用于排队命令和数据。

i2s_8080_lcd 项目的完整源代码可在本页末尾下载。

要编译此项目,将完整文件夹复制到方便的位置(我的情况是 D:\esp32\i2s_8080_lcd)。

C:/msys32 启动 mingw32.exe

启动 mingw32
启动 mingw32

使用 cd D:/esp32/i2s_8080_lcd 切换到 Makefile 的根目录:

切换到项目目录
切换到项目目录

使用 make menuconfig 设置正确的串口:

运行 make menuconfig
运行 make menuconfig

浏览到 Serial flasher config 并将其设置为 COM2(我的情况):

将串口设置为 COM2
将串口设置为 COM2

多次点击 EXIT,最后点击 <Yes> 保存新配置。

最后一步是 make flash

运行 make flash
运行 make flash

现在可以看到一个假的 Apple Watch!

显示 Apple Watch 界面的屏幕
显示 Apple Watch 界面的屏幕

下面的截图显示了 SSD2805 的所有公共函数。没有文本打印、图形绘制或帧缓冲操作。所有 GUI 相关功能都留给 LVGL,只有一个 API 函数 SSD2805_dispFlush(args),它的设计恰好符合要求 - 不多也不少。这也是需要刷新或更新屏幕时调用的唯一函数。

SSD2805 驱动头文件
SSD2805 驱动头文件

类似地,CTP 的驱动程序已开发并用一个基本程序进行了测试,该程序将手指坐标和压力打印到串口。SSD2541.h 的截图如下所示。API 函数 SSD2541_getPoint(args) 是 LVGL 唯一需要的接口。

SSD2541 驱动头文件
SSD2541 驱动头文件

在 mingw32 控制台中,输入 cd D:/esp32/SSD2541_drv_test,然后重复与 SSD2805 相同的步骤:make menuconfig,将 Serial flasher config 设置为 COM2(我的情况),保存更改,最后 make flash。这次我们需要一个终端程序,比如 Arduino 的串口监视器。下面的截图显示了串口监视器的数据流,手指从 (96,113) 释放,在 (88,117) 触摸并有不同的压力,然后再次释放。LVGL 要求触摸坐标应该是手指释放时的最后一个有效点。

显示触摸事件的串口监视器
串口监视器中显示的触摸事件

移植到 LVGL#

一切似乎都准备好移植 LVGL 了。最终程序 littlevgl_port 演示了几个 LVGL 功能(不是全部),包括标签、按钮和图像显示。浏览到 components 文件夹,您会看到完全相同的 SSD2805 和 SSD2541 驱动。LVGL(版本 5.3 commit 17c19fc)直接从 GitHub 拉取。

项目组件结构
项目组件结构

在使用 LVGL 之前需要做几件事:

1. 修改 lv_conf.h#

从模板修改 lv_conf.h 以适配我们的屏幕分辨率。此头文件位于与 Makefile 相同的根目录,即项目目录。

/* Horizontal and vertical resolution of the library.*/
#define LV_HOR_RES          (240)
#define LV_VER_RES          (240)
#define LV_DPI              100
c

2. 定义显示刷新函数#

在主文件 littlevgl_example.c 中,定义一个本地函数来调用 SSD2805_dispFlush(args),然后用 lv_flush_ready() 通知 LVGL 屏幕刷新已准备就绪。

/**
 * @brief   API for LittlevGL with LV_VDB_SIZE!=0 in lv_conf.h
 */
static void ex_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
    SSD2805_dispFlush(x1, y1, x2, y2, (const uint16_t*)color_p);
    lv_flush_ready();
}
c

3. 定义触摸读取函数#

在主文件 littlevgl_example.c 中,定义一个本地函数来调用 SSD2541_getPoint(args),将最后一个有效的手指位置存储到 data->point.xdata->point.y。LVGL 不需要压力值,因此传递 NULL。

/**
 * @brief   API for touch screen
 */
static bool ex_tp_read(lv_indev_data_t * data)
{
    int16_t ctp_x, ctp_y;
    bool sta = SSD2541_getPoint(&ctp_x, &ctp_y, NULL);
 
    (sta==true)? (data->state = LV_INDEV_STATE_PR):(data->state = LV_INDEV_STATE_REL);
 
    data->point.x = ctp_x;
    data->point.y = ctp_y;
 
    return false;
}
c

4. 定义时钟函数#

定义一个时钟函数作为 LVGL 的心跳,并为 ESP32 注册此函数。

/**
 * @brief   Heart beat for LittlevGL
 */
static void lv_tick_task(void)
{
    lv_tick_inc(portTICK_RATE_MS);
}
//...
esp_register_freertos_tick_hook(lv_tick_task); //this is specific to ESP32
c

5. 初始化和注册#

最后一步是初始化 SSD2805、SSD2541、lv_init(),并注册 API 函数。

    SSD2805_begin();
    SSD2541_begin();
    lv_init();
 
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.disp_flush = ex_disp_flush;
    lv_disp_drv_register(&disp_drv);
 
    lv_indev_drv_t indev_drv;                       /*Descriptor of an input device driver*/
    lv_indev_drv_init(&indev_drv);                  /*Basic initialization*/
    indev_drv.type = LV_INDEV_TYPE_POINTER;         /*The touchpad is pointer type device*/
    indev_drv.read = ex_tp_read;                    /*Library ready your touchpad via this function*/
    lv_indev_drv_register(&indev_drv);              /*Finally register the driver*/
c

结果#

结果是一个完全可操作的电容触摸面板,具有按钮、图像显示和文本打印功能!

下载源代码#

关于作者

John Leung
John Leung

社区贡献者

硬件爱好者和 LVGL 社区贡献者,探索 LCD 显示屏在嵌入式系统中的创新应用。

认识博客背后的作者们

了解那些分享 LVGL 知识的优秀作者们

查看作者

订阅我们的通讯 不错过任何关于 LVGL 的新闻。我们每月最多发送 2 封邮件。

LVGL

LVGL 是最受欢迎的免费开源嵌入式图形库,支持任何 MCU、MPU 和显示类型,助您构建精美的用户界面。

我们还提供 UI 设计、实现和咨询等服务。

© 2026 LVGL。保留所有权利。
YouTubeGitHubLinkedIn