十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

泰山派RK3566点亮0.23寸OLED屏:MIPI DSI驱动全流程解析

泰山派RK3566点亮0.23寸OLED屏:MIPI DSI驱动全流程解析 1. 背景为什么要在泰山派上点亮一块0.23寸OLED屏先交代一下使用背景。在嵌入式开发中很多时候我们并不是去驱动一块7寸、10寸的RGB/LVDS大屏而是需要驱动一种“看起来很小但协议并不简单”的屏——比如0.23寸OLED微型显示屏。这类屏大量出现在AR眼镜、电子取景器、瞄准镜、头戴显示器、双目夜视仪等设备中传统开发板很少默认适配资料也比较零散。泰山派是一块基于瑞芯微RK3566的国产ARM Linux开发板核心优势是接口全、资料开放、价格友好在国产化项目中经常作为主控方案。如果我们想让泰山派通过MIPI DSI接口驱动一块国产0.23寸OLED屏需要解决的问题就非常多MIPI DSI接口怎么配置屏的初始化序列如何加载RK3566的DSI控制器如何驱动设备树怎么写显示出来后颜色、帧率、分辨率如何确认正常本文将围绕“泰山派 MIPI DSI 0.23寸OLED屏”展开从协议基础、环境搭建、设备树配置、驱动框架到调试方法逐一说明。适合正在做ARM显示驱动、RK平台方案评估、国产屏适配的开发者阅读。学完后你可以掌握一套相对完整的MIPI点屏思路而不是只复制几行命令。2. 先搞清楚什么是MIPI DSI为什么小OLED屏用它2.1 MIPI DSI是什么MIPI是移动行业处理器接口联盟制定的一套标准。DSIDisplay Serial Interface是其中的显示串行接口专门用于处理器与显示屏之间传输图像数据。通俗理解MIPI DSI就像一条“窄但速度很快的高速公路”用少量信号线把主机端SoC的显示数据送到屏幕模组上。传统的RGB接口屏需要很多根线例如RGB888需要24根数据线加上时钟和同步信号PCB布线压力很大。而MIPI DSI把数据全部串行化将RGB分量拆到高速差分线对上传输常用配置是4 lane 1 clock lane物理信号加起来也就10根左右非常适合空间受限的小型显示模组。2.2 DSI的协议层次DSI规范可以分为三层层次作用D-PHY物理层负责高速差分信号传输定义lane的数量、电压、时序DSI协议层负责打包像素数据、命令数据定义包类型应用层屏幕模组或SoC的显示控制器通过DSI接口发送命令和帧数据在驱动开发中我们更关心的是协议层的数据内容比如发送多少命令去初始化屏幕、当前工作在Video Mode还是Command Mode。2.3 两种工作模式MIPI DSI屏幕按数据刷新方式分为两类Video Mode视频模式SoC持续不断地把画面数据流发送给屏幕屏幕自身没有帧缓存依赖主机端持续刷新。这类屏的驱动配置重点在时序。Command Mode命令模式屏幕内部带显存SoC先把数据写入屏幕的GRAM之后屏幕自己刷新显示。这类屏通常需要额外的TE信号做同步驱动时要关注命令通道和刷新控制。0.23寸OLED这类微型屏既有视频模式方案也有命令模式方案具体取决于模组驱动IC的设计。驱动前必须先从屏厂规格书中确认。3. 认识0.23寸OLED屏的特点与驱动难点3.1 0.23寸OLED是什么样的屏“0.23寸”通常指屏幕对角线长度为0.23英寸。这个尺寸下的OLED屏有一个显著特征像素密度非常高。和常用的0.96寸I2C OLED不同那种屏尺寸单位接近1英寸、分辨率只有128x64接口是I2C/SPI驱动芯片是SSD1306属于字符/图形点阵屏。而0.23寸OLED通常是硅基OLED或者高PPI微显示方案分辨率可以达到640x400、1920x1080等单位面积像素密度远超普通屏。接口一般不会使用I2C——因为I2C频率有限根本传不了高清画面所以会采用MIPI DSI或并行RGB接口。3.2 是否需要驱动IC初始化序列这是很多新手最容易忽略的一点。普通的RGB屏通过简单的DE、HSYNC、VSYNC信号就能出图但MIPI OLED模组通常在屏内部有一颗驱动IC它需要通过MIPI命令来配置工作模式、Gamma曲线、亮度、扫描方向等参数。屏厂一般会提供一份“初始化序列”多是以十六进制命令序列的形式给出。驱动开发的核心工作之一就是把这份初始化序列在恰当的时机通过DSI接口发送给屏。如果初始化序列缺失或者时序不对屏幕就会出现白屏、花屏甚至不亮。3.3 0.23寸OLED驱动常见难点像素格式适配常见有RGB565、RGB666、RGB888驱动若配置错会造成颜色错乱。lane数量不一致有的屏只支持2 lane有的支持4 laneSoC端的DSI控制器需与屏端匹配。初始化序列长度部分屏的初始化序列很长甚至有几百条命令任何一个字节出错都可能导致点不亮。电压与电源时序微显示模组对供电时序比较敏感必须先供电、再拉复位、最后发初始化命令。4. 泰山派软件环境与准备工作泰山派的核心SoC是RK3566它内部集成了MIPI DSI控制器支持MIPI DSI输出可配置为单通道或多通道。在软件层面我们主要通过Linux内核的DRM/KMS框架去驱动MIPI屏。4.1 开发环境建议准备一台Ubuntu主机18.04或20.04 64位均可新版SDK通常要求在64位系统下编译用于编译内核和SDK。常见开发环境说明项目建议操作系统Ubuntu 18.04 / 20.04 x64交叉编译工具链aarch64-linux-gnu- 或Rockchip SDK自带工具链泰山派SDK根据官方发布版本下载内核版本以SDK自带版本为准常见为Linux 5.10/5.15系列烧录工具RKDevTool / upgrade_tool / 官方烧录工具需要特别说明的是不同批次泰山派板卡、不同SDK版本设备树路径和内核配置可能会有差异。本文的重点是梳理配置思路具体路径请按你手里的SDK做对应调整。4.2 内核需要开启的配置在Linux内核下驱动MIPI DSI屏通常依赖DRM子系统。如果SDK预编译内核已经支持MIPI DSI可以省略这一步如果是从零配置内核需要打开如下相关选项CONFIG_DRMy CONFIG_DRM_ROCKCHIPy CONFIG_DRM_ROCKCHIP_DW_MIPI_DSIy CONFIG_DRM_PANELy CONFIG_DRM_PANEL_SIMPLEy CONFIG_DRM_PANEL_ROCKCHIPy CONFIG_BACKLIGHT_CLASS_DEVICEy不同内核版本的配置名称会有差异例如有些版本使用CONFIG_DRM_ROCKCHIP_MIPI_DSI。在配置菜单中检索DRM、MIPI、ROCKCHIP就可以快速定位。4.3 先确认系统能正常启动在动手写屏驱动前最好先确认泰山派能正常启动到Linux并且串口/网络登录都正常。驱动屏幕时我们通常需要一边改设备树一边看内核日志。通常通过以下方式确认# 查看串口信息确认内核启动 dmesg | grep mipi # 查看DRM是否注册成功 ls /sys/class/drm/如果能看到card0-DSI-1之类的节点说明MIPI DSI链路已经被内核识别只是屏可能还没有正式点亮。5. RK3566的MIPI DSI接口与设备树配置思路5.1 在设备树中找到MIPI DSI节点RK3566的DSI控制器在设备树中的节点名称一般形如dsife060000通常挂在与display-subsystem相关的链路上。当我们内核对某个屏幕适配良好时常见的做法是使用Rockchip提供的panel-simple或panel-rockchip驱动在设备树里新增一个屏幕节点并在DSI节点中引用。5.2 设备树添加MIPI OLED屏节点下面是一个简化后的设备树配置示例展示如何定义一块MIPI OLED panel节点/ { compatible rockchip,rk3566; backlight: backlight { compatible pwm-backlight; pwms pwm0 0 50000 0; brightness-levels 0 1 2 3 4 5 6 7 8 9 10; default-brightness-level 8; status okay; }; panel_oled: panel-oled { compatible example,oled-023; status okay; power-supply vcc3v3_lcd; backlight backlight; reset-gpios gpio3 RK_PA5 GPIO_ACTIVE_LOW; ports { #address-cells 1; #size-cells 0; port0 { reg 0; panel_in_dsi: endpoint { remote-endpoint dsi_out_panel; }; }; }; }; };然后在DSI控制器节点内增加端口引用dsi { status okay; rockchip,lane-rate 480; ports { #address-cells 1; #size-cells 0; port1 { reg 1; dsi_out_panel: endpoint { remote-endpoint panel_in_dsi; }; }; }; };注意reset-gpios的GPIO编号必须根据你的板卡实际原理图来填写。power-supply需要指向板卡上OLED屏对应的电源节点。compatible需要与panel驱动中匹配的字符串一致。5.3 lane相关配置RK3566的DSI控制器和屏幕的lane数必须匹配。如果屏是4 lane在驱动里会读取设备树或固定匹配参数如果屏是2 lane则需要在驱动或平台配置中把lane数调整为2。这里的常见错误是硬件设计时DSI lane数是固定的但当SoC与屏的lane数不一致时往往表现为屏幕无信号或者显示异常。遇到这种情况优先检查屏规格书确定lane数量再到DSI驱动确认实际配置。6. 驱动适配从panel-simple到专用驱动6.1 复用内核现有panel驱动如果0.23寸OLED屏的驱动IC比较通用并且厂家没有额外初始化序列可以直接使用Linux内核的panel-simple驱动只需要在设备树中定义一个带时序信息的节点。例如drivers/gpu/drm/panel/panel-simple.c中新增一个timing结构需要重新编译内核。对于终端用户我们可以选择在设备树中直接使用已经支持的panel型号或者给kernel提交patch新增panel描述。但实际情况中很多国产OLED微显示模组都需要厂家初始化序列单纯靠panel-simple可能无法点亮此时需要为它编写一个简单的平台驱动。6.2 构造一个初始化序列发送框架Linux内核DRM子系统提供了mipi_dsi_dcs_write_buffer接口用于向屏幕发送命令。我们设计的panel驱动核心就是做三件事解析设备树中定义的电压、复位GPIO、背光。上电并复位。在prepare阶段发送初始化命令列表在unprepare阶段关闭屏幕。下面是一个框架示例注意这段代码是“示意思路”实际寄存器命令必须由你手里的屏厂规格书提供// 文件路径drivers/gpu/drm/panel/panel-oled-023.c #include linux/module.h #include linux/of.h #include linux/gpio/consumer.h #include linux/regulator/consumer.h #include video/mipi_display.h #include drm/drm_panel.h #include drm/drm_mipi_dsi.h struct oled023 { struct drm_panel base; struct mipi_dsi_device *dsi; struct regulator *supply; struct gpio_desc *reset_gpio; struct gpio_desc *enable_gpio; }; static inline struct oled023 *to_oled023(struct drm_panel *panel) { return container_of(panel, struct oled023, base); } static int oled023_prepare(struct drm_panel *panel) { struct oled023 *oled to_oled023(panel); int ret 0; /* 1. 给屏幕供电 */ if (oled-supply) { ret regulator_enable(oled-supply); if (ret) return ret; } /* 2. 复位延时 */ gpiod_set_value_cansleep(oled-reset_gpio, 1); msleep(20); gpiod_set_value_cansleep(oled-reset_gpio, 0); msleep(20); /* 3. 发送初始化序列按屏厂提供的命令表填写 */ /* mipi_dsi_dcs_write_buffer(oled-dsi, init_cmd, sizeof(init_cmd)); */ return ret; } static int oled023_unprepare(struct drm_panel *panel) { struct oled023 *oled to_oled023(panel); gpiod_set_value_cansleep(oled-reset_gpio, 1); if (oled-supply) regulator_disable(oled-supply); return 0; } static const struct drm_panel_funcs oled023_funcs { .prepare oled023_prepare, .unprepare oled023_unprepare, .get_modes oled023_get_modes, }; static int oled023_probe(struct mipi_dsi_device *dsi) { ... } static const struct of_device_id oled023_of_match[] { { .compatible example,oled-023 }, { } }; MODULE_DEVICE_TABLE(of, oled023_of_match); static struct mipi_dsi_driver oled023_driver { .probe oled023_probe, .remove oled023_remove, .driver { .name panel-oled-023, .of_match_table oled023_of_match, }, }; module_mipi_dsi_driver(oled023_driver); MODULE_LICENSE(GPL);上面的代码只写了prepare和unprepare的核心流程实际还需要补全get_modes、enable、disable、probe/remove中的检查项。真正编写时还需要为dsi设备设置dsi-mode_flagsdsi-formatdsi-lanes6.3 常见的作用函数解释get_modes是panel驱动中最重要的一部分它决定内核向DRM子系统上报哪些显示分辨率与刷新率。通常做法是定义drm_display_mode结构体并在get_modes中转换为drm_mode。static const struct drm_display_mode oled023_mode { .clock 15000, .hdisplay 640, .hsync_start 640 16, .hsync_end 640 16 48, .htotal 640 16 48 96, .vdisplay 400, .vsync_start 400 1, .vsync_end 400 1 1, .vtotal 400 1 1 1, .flags DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, };时序参数porch、sync等完全取决于屏规格书如果拿不到具体数值宁可不写也不能随便填否则屏幕显示可能偏移或闪烁。7. 编译、烧录与验证流程7.1 编译内核与设备树泰山派SDK通常提供一键编译脚本。以手动编译为例假设我们已经进入内核目录export ARCHarm64 export CROSS_COMPILEaarch64-linux-gnu- make rockchip_linux_defconfig # 如果需要确认配置项 make menuconfig # 编译内核 make -j$(nproc) Image dtbs编译完成后会生成内核镜像和设备树文件。设备树一般位于arch/arm64/boot/dts/rockchip/目录下文件类似rk3566-taishanpai.dts。我们需要把我们新增的panel节点和dsi配置合入对应的dts文件再重新编译。7.2 烧录验证烧录步骤因SDK发布方式不同而不同常见路径是把boot.img或单独的内核与dtb烧到板卡。烧录完成后启动系统接着检查# 查看mipi dsi是否触发 dmesg | grep -i mipi # 查看drm驱动注册状态 dmesg | grep -i drm # 检查panel是否匹配 dmesg | grep -i panel如果驱动探测成功一般会在dmesg中看到类似信息panel-oled-023 0-0000: Linked as a consumer to regulator.0 rockchip-drm display-subsystem: bound 0:0.0 (ops rockchip_dsi_drm_ops)之后我们用modetest来查看系统识别到的显示模式modetest -M rockchip -p如果屏幕已经点亮可以尝试往framebuffer上写颜色测试cat /dev/urandom /dev/fb0如果你使用的是Linux DRM应用也可以用modetest刷单色画面。正常情况屏幕会显示对应颜色。8. 常见问题与排查思路8.1 插上屏幕后完全没有显示现象常见原因解决思路屏幕全黑背光不亮电源未正确开启检查power-supply节点与GPIO控制确保供电正常屏幕全黑背光亮初始化序列未执行或复位未释放查看probe是否成功复位IO极性是否正确DRM设备里没有DSI节点设备树dsi节点status不是okay检查设备树覆盖配置屏幕白屏初始化序列错误逐帧核对屏厂初始化序列数据注意时序延时8.2 开机显示花屏或颜色不对花屏和颜色错乱是MIPI屏调试中非常常见的现象。最常见原因是Pixel Format不匹配。如果屏是RGB666而驱动设置成RGB888颜色的低位会错乱尤其在渐变图形上表现明显。如果屏是RGB565而驱动设置为RGB888则会出现明显的色斑、彩色干扰。检查时可以读屏规格书和代码中的dsi-format做对照MIPI_DSI_FMT_RGB888 MIPI_DSI_FMT_RGB666 MIPI_DSI_FMT_RGB5658.3 屏幕能亮画面但会闪烁闪烁一般原因如下背光PWM频率过低。屏处于Command Mode但TE信号同步不正确。刷新率和帧缓冲不匹配。优先检查PWM背光频率再检查是否在Video Mode下设置了稳定的刷新率。8.4 泰山派识别到RK3566但系统进入ADB设备模式这是一个比较典型的调试环境问题。很多泰山派板卡默认烧录的是Android或包含ADB的镜像接入电脑后电脑识别设备为ADB设备导致一部分开发者误以为没有正常运行Linux。此时我们首先要区分两点如果板卡作为ADB设备被识别说明系统已经在Android或带ADB的Linux中运行这并不影响调试你可以通过ADB登录。如果我们要做MIPI显示调试建议优先使用串口登录系统因为ADB在某些定制的Linux镜像中并没有完全启用且串口能看完整的内核日志。一句话电脑识别成ADB设备不代表驱动失败不要被设备名称误导重点是检查内核日志中DSI链路是否起来。9. 工程实践建议9.1 拿到屏先做“最小验证”很多开发者在拿到新屏幕后第一件事就是对照驱动框架写一大堆代码结果出问题后完全不知道是硬件接错还是软件配置错。更稳妥的做法是先用简单的点屏工具例如RK平台的dsi_test或读写寄存器工具验证能否通过MIPI命令和屏幕通信。确认通信OK后再尝试发初始化序列。如果能点亮再进入DRM框架做完整的显示链路适配。9.2 保存原始命令表不要随意“优化”屏厂提供的初始化序列往往是经过大量实验得到的里面可能包含时序修复命令、电压配置命令、gamma命令。不要因为某条命令看不出作用就删掉。建议做法是把原始命令表完整保存为.h或.c文件。在每条命令上方添加注释。如果有修改单独维护一个差异记录。9.3 电源时序要谨慎处理MIPI屏对电源时序要求往往比RGB屏严格。常见的需求包括VDDI 先上电。主电源后上电。复位信号在电源稳定后解除。初始化序列必须在复位释放后等待一段延时再发送。驱动代码中尽量使用regulator框架和gpio_desc来控制电源和复位不要用杂散的GPIO操作绕过框架否则后续做休眠唤醒时非常容易出现屏幕无法恢复问题。9.4 背光控制与显示状态分开在业务开发中很容易把背光和显示当成一个东西。实际上屏幕的亮灭和背光的亮灭应该分层控制DRM的prepare/unprepare控制屏幕电源与初始化。DRM的enable/disable控制视频流启停。背光由独立的backlight驱动控制。如果业务需要“息屏但保持Android系统运行”关闭背光即可不要直接拔屏幕电源。9.5 调试时要留足日志打印在实际调屏开发中最忌讳闷头改代码。比较推荐的做法是在probe、prepare、unprepare、enable、disable函数中都加一条dev_info或dev_dbg日志这样可以快速定位是驱动没有加载还是加载了但状态切换异常。调试完成后再把冗余日志改成dev_dbg保留在代码中即可。10. 总结与后续学习方向泰山派驱动0.23寸OLED屏的核心链路是RK3566 DSI控制器 → MIPI DSI信号线 → OLED模组驱动IC → OLED像素阵列在Linux软件栈上我们需要打通链路是设备树DSI节点panel节点 → panel驱动报告模式、配置电源时序 → DRM/KMS框架 → 用户空间显示程序。如果只是点亮屏幕上面任何一环都不能出错如果要做业务产出还需要进一步掌握DRM framebuffer、图层合成、PWM背光调节、休眠唤醒等知识点。但在做实际项目时还有几个问题值得重点关注屏幕规格书上的时序参数必须亲自核对网络上别人的屏幕参数只能用来理解不能直接借用。厂家给的初始化序列在驱动中如何组织、如何延时需要结合RK3566的MIPI DSI控制器状态机来调试。国产屏的兼容性验证需要做足尤其是不同批次模组的初始化差异。如果你正准备在泰山派上调试MIPI OLED建议先把自己手头的模组规格书完整过一遍确认好lanes、format、mode_flags这三项再开始动设备树。祝点屏顺利。
返回列表