简介:Linux驱动开发工程师与嵌入式学习者可借助这份8080并行接口小尺寸LCD驱动实现资源,系统掌握从硬件接口分析、设备模型注册到数据传输与命令发送的完整开发流程。资源基于常见的lcd8080-master项目,适合需要在内核空间编写字符设备驱动的初中级开发者。压缩包共9个文件,约15KB,以C源码为主,包含3个C源文件与1个头文件,另有Makefile构建脚本和2个Markdown说明文档,其中lcd8080-core.c、lcd8080-io.c、lcd8080-ili9341.c分别承担驱动核心框架、I/O访问与液晶控制器适配,层次清晰。目前已吸引350人学习下载,包体虽小却覆盖设备注册、I/O操作、设备树配置、模块加载与卸载等关键知识点。通过阅读源码与配套文档,可快速掌握8080接口LCD的Linux驱动工程实现方法,并迁移至其他并行接口外设驱动开发中。
1. 小尺寸8080并行接口屏:Linux驱动选型与实现路径
去年在给一台老式仪器换显示屏时,遇到一个典型的尴尬:原来板子上的 2.4 寸 SPI 屏刷新一屏要 90 毫秒,用户拿手指一点,屏幕上的曲线要等半天才跟上。客户给的替代屏是 3.5 寸、16 位色、8080 并行接口的 TFT 液晶屏。数据手册写得很简单,但要在 Linux 底下把这个屏点亮,涉及的却是一整套字符设备驱动框架、时序模拟和帧缓冲对接。很多人一看“8080”这个名字就以为是什么老古董协议,实际上它到今天仍然是小尺寸工控屏最常见的接口之一。它的驱动难度不在于协议本身,而在于 Linux 下没有一套标准的“平板模组接口”抽象,需要自己把这套并行时序挂到字符设备、平台设备或帧缓冲框架里。
这篇文章想把这件事讲透:从 8080 接口的电气与时序本质,到用 GPIO 模拟并行读写,再到把屏幕暴露成/dev/fb0交给应用层直接mmap,最后是实际调屏中会遇到的参数陷阱和刷新优化。看完之后,你应该能独立写完一个针对 2.4 寸到 4.3 寸、8 位或 16 位数据总线、8080 接口小屏的 Linux 驱动内核模块。代码以 5.x 内核为准,但我会把与旧内核的差异也标出来。
2. 用 platform 总线与设备树把 8080 屏挂进驱动模型
2.1 为什么是 platform 总线而不是 I2C 或者 SPI
8080 接口的液晶屏在数据手册里被叫作“MCU 接口”,本质上是一组片选、读写、复位和并行数据线。它不像 I2C 有标准内核子系统,也不像 SPI 有统一的 SPI 控制器可以对接,在嵌入式 Linux 环境里,最干净的做法是把它当作一个 memory-mapped 设备挂在 platform 总线上。这里的关键点是:控制器本身可能挂在 SoC 的并行总线上,也可能只是若干 GPIO 的简单组合。如果你用的是 GPIO 模拟,更常见的手法是通过设备树把相关引脚传给驱动,让驱动在 probe 阶段完成gpio_request和gpiod_get。
我一般会先在设备树里定义一个 platform 设备,把数据线 DC、WR、RD、RESET 这些引脚编排成 GPIO specifier。注意一个容易被忽略的问题:8080 接口的数据线如果是 16 根,不要每根都写进设备树的gpios属性里,否则设备树会变得极其臃肿,而且中断号之类的关联也会失效。更合理的组织方式是使用gpio-array这样的自定义属性,或者干脆让驱动在 init 时通过of_get_named_gpio_flags逐个解析。如果你的板子把并口接在了 SoC 的 LCD 控制器引脚上,那就不是 GPIO 模拟的范畴了,需要走 LCDC 驱动,那篇文章暂时不展开。
2.2 设备树节点与 platform_driver 的绑定逻辑
在arch/arm/boot/dts里增加类似下面的节点:
&gpio { lcd8080_pins: lcd8080_pins { pins = "GPIO0_4", "GPIO0_5", "GPIO1_0", "GPIO1_1"; function = "gpio"; }; }; lcd8080: lcd-display@0 { compatible = "vendor,8080-lcd"; reg = <0>; pinctrl-names = "default"; pinctrl-0 = <&lcd8080_pins>; db-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>, <&gpio0 7 GPIO_ACTIVE_HIGH>, <&gpio0 8 GPIO_ACTIVE_HIGH>; dc-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; wr-gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>; rd-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>; reset-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; status = "okay"; };这段设备树的核心意图是把“驱动需要操作的引脚”以及“引脚的有效电平”一次性描述清楚。db-gpios里三根线只是示意,实际工作中 8080 屏的数据线可多可少,8 位屏用 8 根,16 位屏用 16 根,编写时不要漏掉,否则屏幕上会出现颜色错位或花屏。dc-gpios对应 RS 信号,它决定当前传输的是命令还是数据;wr是写使能,rd是读使能,reset是硬件复位,通常低电平有效。
Platform 驱动这边,通过of_device_id匹配 compatible,再在 probe 函数里用devm_gpiod_get拿引脚。常见的错误是在这里直接拿 GPIOLIB 的旧接口gpio_request,然后混用gpio_direction_output。新内核建议直接用devm_gpiod_get_optional,它在老旧 DT 节点缺属性时不会让 probe 失败,排错时也更友好。另外注意:8080 接口既然叫“并行”,它的数据引脚不能简单按普通 GPIO 的 push-pull 输出去看,很多 8080 屏要求数据线可以双向切换,驱动在初始化和绘图阶段往往需要把数据线方向改来改去。
2.3 probe 函数里的资源申请与初始化顺序
static int lcd8080_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct lcd8080_priv *priv; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW); priv->wr = devm_gpiod_get(dev, "wr", GPIOD_OUT_HIGH); priv->rd = devm_gpiod_get(dev, "rd", GPIOD_OUT_HIGH); priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(priv->dc) || IS_ERR(priv->wr) || IS_ERR(priv->rd) || IS_ERR(priv->reset)) return -ENODEV; /* 先将 RESET 拉低一段时间再拉高,让屏内部逻辑复位 */ gpiod_set_value(priv->reset, 0); msleep(20); gpiod_set_value(priv->reset, 1); msleep(120); platform_set_drvdata(pdev, priv); return lcd8080_hw_init(priv); }这里必须注意一个细节:devm_gpiod_get的GPIOD_OUT_HIGH参数指的是驱动获取引脚后初始输出的电平,而不是设备树里GPIO_ACTIVE_HIGH这个标志。GPIOD_OUT_HIGH会让实际物理引脚输出高电平,而设备树里的 active 标志只影响gpiod_set_value的语义。比如 RESET 在设备树里被标成GPIO_ACTIVE_LOW,那么调用gpiod_set_value(priv->reset, 0)时,GPIOLIB 会自动把物理电平拉到高。很多初接触者在这一点上绕晕,结果复位时序正好反了,屏幕要么彻底不亮,要么初始化写进去的命令全部无效。
3. GPIO 模拟并口时序:8080 屏点亮的初始化序列与数据手册对照
3.1 8080 接口的读写时序模型
8080 接口的时序本质上是一组非常规整的电平翻转。写一个命令或数据时,先把 DC 线拉到对应电平(命令为低、数据为高),然后在 WR 引脚的上升沿,CPU 把数据总线上已经稳定的值锁存进屏幕控制器的寄存器。整个过程中 RD 要保持在高电平,避免数据总线方向冲突。读操作则相反,把 RD 拉低后,屏幕控制器会把当前寄存器或 GRAM 的值驱动到数据线上,CPU 在 RD 上升沿之前取走数据。这里有个绝大多数新手会犯的错:读操作之前,必须先把数据线切到输入模式。如果你的数据线是用 GPIO 模拟的,就意味着要逐个引脚切换方向。如果数据线接在 SoC 的并行总线引脚上,这个切换由总线控制器自动完成,反而省心。
真实工业屏的数据手册里会给出Write Cycle Time、WR Low Level Width、WR High Level Width等参数。常见的小尺寸 8080 屏写周期通常在 60 纳秒到 200 纳秒之间。用 GPIO 模拟时,一次gpiod_set_value的开销可能就会达到几十纳秒,尤其是经过 GPIO 子系统层层调用之后,实际速度根本无法达到极限时序要求。因此在驱动代码里,我一般不会严格按数据手册的最小周期去算,而是会把一次写操作的 GPIO 翻转序列保持在几百纳秒到 1 微秒量级,确保在任何主频下都能稳定工作。
3.2 最小化读写的底层函数怎么写
static void lcd8080_wr_data(struct lcd8080_priv *priv, u16 data) { int i; gpiod_set_value(priv->dc, 1); /* DC=1 表示数据 */ gpiod_set_value(priv->rd, 1); /* 禁止读操作 */ for (i = 0; i < 16; i++) { gpiod_set_value(priv->db[i], (data >> i) & 0x1); } gpiod_set_value(priv->wr, 0); ndelay(50); gpiod_set_value(priv->wr, 1); ndelay(50); }这段代码故意没有做任何总线方向切换,是因为 8 位屏和 16 位屏在引脚数量上不一样。如果你的屏是 8 位数据线,就把for循环改成 8 次,但是要注意 8 位接口模式下,数据手册通常要求把高 8 位数据线接地,而不是悬空。悬空会导致读 ID 的时候拿到随机值,初始化流程异常。ndelay(50)是保守值,如果后续发现 GPIO 翻转速度本身已经超过 20 纳秒,可以把这个延迟完全去掉,只保留空循环。我从实际项目里的经验是:延迟写 50 纳秒左右反而能躲开一些 GPIO 芯片在上升沿产生的毛刺。
命令写函数与数据写函数的唯一区别在于 DC 电平,其他的循环逻辑完全一致。这里有个非常有用的技巧:把dc、wr、rd、rest这些控制引脚和db数据引脚放在同一个 gpiochip 上时,驱动里可以提前把所有引脚的方向一次性设置好,然后在写数据时只翻转数据引脚,不反复改变方向。在中断上下文中,这种优化能明显改善屏幕刷新的流畅感。
3.3 初始化序列与数据手册的对照方法
大多数 8080 接口小屏控制器的初始化序列都极其相似,以最常见的 ILI9341 控制器为例,初始化流程通常包含软复位、关闭显示、设置像素格式、设置内存访问控制、设置帧率、打开显示这几步。具体命令码会因为控制器的不同而不同,有的屏用 ST7789,有的用 NT35310,命令码差异很大。所以驱动里最好不要硬编码一套“万能初始化序列”,而是把序列拆成一个static const u8 init_cmd[]数组,驱动在初始化时一行行解释执行。
下面是一个简化的初始化序列示例:
static const struct lcd8080_init_cmd { u8 cmd; u8 len; const u8 *data; } lcd8080_init_seq[] = { { 0x01, 0, NULL }, /* Soft Reset */ { 0x11, 0, NULL }, /* Sleep Out */ { 0x3A, 1, (const u8[]){ 0x66 } }, /* 18-bit color */ { 0x36, 1, (const u8[]){ 0x48 } }, /* Memory Access Control */ { 0x29, 0, NULL }, /* Display ON */ };执行时每一条命令都要按照 8080 接口写命令、写数据的顺序发送。加msleep的位置通常出现在 Soft Reset 之后和 Sleep Out 之后,因为这两个命令会改变屏内部的电源状态,等待时间不够,后面的寄存器写入会被丢弃。这里我提一个与数据手册常被忽略的地方:很多屏在0x3A里能设置 16 位色或 18 位色,但 8080 并口的数据线若只有 16 根,强行设成 18 位色会导致低 2 位被截断,屏幕出现细密噪点。错误表现和接触不良很像,排查起来非常折磨人。
4. 对接帧缓冲框架:把 8080 屏变成/dev/fb0并支持用户态直写
4.1 字符设备、帧缓冲与内核中各框架的边界
Linux 内核里面与显示屏直接相关的框架有两个:一个是 DRM/KMS,另一个是传统的 fbdev。对小尺寸 8080 并行接口屏来说,fbdev 仍然是最快能跑通的方式。fbdev 框架的核心是register_framebuffer(),它会在/dev下创建fb0节点,用户态通过open、mmap、ioctl三个系统调用就能完成大部分工作,不需要额外写字符设备驱动。头部文件是linux/fb.h,里面定义了struct fb_info、struct fb_ops和struct fb_var_screeninfo等关键结构。
很多新手会直接想从零写一个miscdevice字符设备驱动,自己管理file_operations。这样做并不是不行,但对 8080 屏来说,等于放弃了内核已经帮你封装好的mmap映射、虚拟分辨率切换、backlight 控制等能力。我的建议是:在真正需要实现快速滚动、多缓冲同步之类的特殊功能之前,优先选择 fbdev,这是字符设备驱动框架里最省力的路径。
4.2 填充 fb_info 与 fb_ops 的关键字段
static int lcd8080_fb_probe(struct platform_device *pdev) { struct fb_info *fbi; struct lcd8080_priv *priv; fbi = framebuffer_alloc(sizeof(*priv), &pdev->dev); if (!fbi) return -ENOMEM; priv = fbi->par; platform_set_drvdata(pdev, fbi); strcpy(fbi->fix.id, "lcd8080"); fbi->fix.smem_start = 0; /* 无物理地址,零拷贝映射 */ fbi->fix.smem_len = 320 * 240 * 2; /* 320x240 RGB565 缓冲 */ fbi->fix.type = FB_TYPE_PACKED_PIXELS; fbi->fix.visual = FB_VISUAL_TRUECOLOR; fbi->var.xres = 320; fbi->var.yres = 240; fbi->var.bits_per_pixel = 16; fbi->var.red.offset = 11; fbi->var.red.length = 5; fbi->var.green.offset = 5; fbi->var.green.length = 6; fbi->var.blue.offset = 0; fbi->var.blue.length = 5; fbi->fbops = &lcd8080_fb_ops; fbi->screen_base = (char __iomem *)priv->vram; if (register_framebuffer(fbi) < 0) { framebuffer_release(fbi); return -EINVAL; } return 0; }这段代码里,smem_start = 0的含义是告诉 fbdev 子系统这块显存不是物理连续内存。如果你有一块 DMA 内存,就应该把它的物理地址填进去,这样用户态mmap时可以直接映射物理内存,避免复制。但很多 GPIO 模拟方案里,显存只是内核空间kzalloc出的一段缓冲区,因此在fb_mmap回调里你需要用remap_pfn_range或者是dma_alloc_coherent预先分配。用dma_alloc_coherent分配显存是更稳妥的做法,它保证了 cache coherency,否则 CPU 写入显存后,DMA 控制器或者用户态映射可能读到旧数据。
4.3 fb_ops 里必须实现的三个回调
static int lcd8080_fb_blank(int blank, struct fb_info *fbi) { return 0; /* 实际效果依赖控制器 BLANK 命令 */ } static int lcd8080_fb_set_par(struct fb_info *fbi) { /* 在分辨率或色深变化时重新计算时序 */ return 0; } static ssize_t lcd8080_fb_write(struct fb_info *fbi, const char __user *buf, size_t count, loff_t *ppos) { /* 默认 fb_write 已经隐式处理了 ppos 和范围保护 */ return fb_sys_write(fbi, buf, count, ppos); }如果你不实现fb_write,用户态仍然可以通过mmap直接写显存。但在某些库里,比如 Qt 的 LinuxFB 插件,它内部会对/dev/fb0执行write系统调用。所以最省事的做法是调用内核提供的fb_sys_write和fb_sys_read,它们会把用户态数据拷贝到screen_base指向的缓冲区。注意这些fb_sys_*系列函数要求screen_base是内核虚拟地址,不能是ioremap出的地址,否则会触发内核异常。这是 fbdev 驱动里最容易踩的坑:screen_base到底是普通内核地址、vmalloc地址还是ioremap地址,直接决定了读写路径怎么选。
4.4 刷新任务与回写屏幕
当用户态把像素写入screen_base后,你的驱动程序如何知道要刷新?8080 接口屏没有 VSYNC 中断,所以绝大多数小屏驱动采用后台刷新方式,比如在set_par里开启一个delayed_work,定时把整块显存扫到屏幕上。常见做法是每 30 到 60 毫秒扫描一次,主要开销在于 GPIO 模拟的 16 位数据写入。320x240 分辨率下,一帧 76 万次 GPIO 翻转,即便每次翻转只要 100 纳秒,整帧也要 76 毫秒,刷新率只能到 13fps 左右。这意味着用 GPIO 模拟的情况下,不要指望流畅动画,更适合静态界面或低速波形显示。
static void lcd8080_refresh_work(struct work_struct *work) { struct lcd8080_priv *priv = container_of(work, struct lcd8080_priv, refresh_work.work); u16 x, y; u16 *vram = (u16 *)priv->vram; for (y = 0; y < priv->height; y++) { for (x = 0; x < priv->width; x++) { lcd8080_set_window(priv, x, y, x, y); lcd8080_wr_data(priv, vram[y * priv->width + x]); } } schedule_delayed_work(&priv->refresh_work, msecs_to_jiffies(50)); }这段代码里频繁调用lcd8080_set_window会把刷新效率拉到极低,因为左边界和右边界没有变化时,完全可以只在第一行设置一次 window,后面的行坐标递增即可。很多控制器的Set Column和Set Page命令代价很高,建议改成只在 x 坐标跨越边界时重新调用,或者干脆用控制器的2-byte连续写模式,通过连续的写数据操作驱动内部列地址自增,这样能省掉大部分 window 命令开销。
5. 驱动实战中的参数表:时序、像素格式与常见故障排查
5.1 一页看懂主要控制器参数差异
对于 8080 接口小屏,市面上常见的控制器有五六个型号,它们的命令集并非完全兼容。下面的表格列出了我最常接触的几个控制器在几个关键初始化点的典型值,适合作为调试时的快速对照。
| 控制器型号 | 常见分辨率 | 像素格式命令 | RGB565 值 | 内存访问控制命令 |
|---|---|---|---|---|
| ILI9341 | 320x240 | 0x3A | 0x55 | 0x36 |
| ST7789 | 240x320 | 0x3A | 0x55 | 0x36 |
| NT35310 | 480x272 | 0x3A | 0x55 | 0x36 |
| SSD1963 | 800x480 | 0x3A | 0x55 | 0x36 |
这四款控制器的命令编号高度相似,但0x36的旋转控制位定义有区别。ILI9341 的MY、MX、MV三位分别控制行镜像、列镜像和行列交换,而 NT35310 的记忆访问控制里还有额外的位会影响 BGR 颜色顺序。具体表现就是同样的初始化代码,换一块屏后,颜色偏红或者偏蓝。这种问题不是像素格式设置错误,而是0x36寄存器里的 BGR 位没设置对。排查方式是用一个纯白界面看 R、G、B 分量是否正常,而不是用彩色照片。
5.2 GPIO 模拟速度不够怎么办
最直接的方案是降低屏幕分辨率,或者把 16 位 RGB565 的传输放在 8 位模式下分两次送。很多控制器支持两种并口宽度,驱动初始化时通过特定寄存器选择。用 8 位模式牺牲了一半的数据吞吐,但 GPIO 数量减少,也让platform_driver的管脚资源申请更简单。如果想要更高的刷新率,我建议用 SoC 内置的并行总线或 SPI 控制器。有些 SoC 的 SPI 控制器支持最高 40MHz 时钟,用 SPI 模式四线或三线驱动小屏反而比 GPIO 模拟 8080 更快,只不过命令和数据都变成了 9 bit 一帧的串行协议。这里不展开 SPI 屏的编写细节,但思路是相通的。
5.3 花屏、闪烁、开机无显示的排查路径
曾在调试一块 2.8 寸屏时,遇到的现象是背光亮但画面出现规律性条纹,每隔固定行数水平偏移一点点。最后定位到是初始化序列里0x36的值设成了0x48,导致SS扫描方向反转,RAM 行地址映射和显存坐标不一致。这种花屏不是同步问题,而是坐标系问题。处理方式是先用纯色测试图,把屏幕分成四个象限分别填充不同颜色,通过观察哪个颜色跑到了哪个位置,确定行列方向是否需要翻转。另一类常见的闪烁问题是电源纹波。8080 屏的背光驱动如果和 LCD 逻辑供电在同一路 LDO 上,当 GPIO 大量翻转导致负载突变时,电压跌落会让 VCOM 变化,屏幕就出现横向暗线。解决办法不是调软件时序,而是在 LCD 逻辑电源上加 10 微法陶瓷电容,并把背光 PWM 频率从 1kHz 提高到 20kHz。
还有一类非常隐蔽的错误:framebuffer里已经写入了正确的像素,但屏幕一直显示上一次的内容。这多半是mmap的内存与刷新时读取的内存不一致。例如使用vmalloc分配显存,mmap后用户态写入的缓存没有 flush,而刷新 worker 在不同的 CPU 核上运行,cache 一致性问题会导致脏数据无法被看到。解决方法是在刷新前调用dma_map_single做一次 clean 操作,或者直接换成dma_alloc_coherent内存,两个方法各有取舍,后者对系统内存分配压力更大,但调式更省心。
5.4 用 dmesg 和 devmem 做快速验证
# 查看 fb 内存映射信息 cat /sys/class/graphics/fb0/virtual_size cat /sys/class/graphics/fb0/bits_per_pixel # 用 devmem 读取数据手册里的 ID 寄存器,确认数据线 wiring 是否正确 devmem 0x01C00000 32devmem的地址在这里只是示意。实际操作中,你可以通过/proc/iomem找到 LCD 控制器或并口的寄存器基地址,然后读取控制器的 ID 寄存器。如果读出来的值和数据手册不一致,先怀疑数据线的顺序错了,尤其是把DB0和DB1接反时,屏幕上会产生规律性“雪花”图案。另有一个常用技巧:初始化屏后,通过dmesg查看驱动是否有Failed to read LCD ID之类的打印,很多控制器支持读 ID,驱动可以在 init 阶段先读一次 ID 判断当前接线是否正确。这个步骤成本很低,强烈建议加进去。
6. 刷新性能优化技巧:零拷贝映射与批量写命令收尾
拨动刷新率最见效的手段是把“一行一个 window”改成“整帧一个 window”。320x240 的屏在 GPIO 模拟下,一次 window 设置要发送 4 条命令加 4 个数据,大约需要 20 微秒。如果每一行都设置,整帧就是 240 次,约 4.8 毫秒的开销,看似不多,但加上 16 条数据线的 GPIO 翻转,总时间就会冲到 100 毫秒。改为整帧一个 window 之后,意义不仅是省了那 239 次设置,更重要的是驱动写数据的循环可以退化成快速的 I/O 序列,不在中间插入任何控制逻辑。实践中用整帧 window 加连续写,通常能让刷新时间下降 20%。
另一个可以立竿见影的优化是用gpiod_set_array_value一次性写 16 条数据线。它要求所有 GPIO 属于同一个 gpiochip,并且引脚号连续或接近连续。在多数 SoC 上,这会把 16 次set_value调用压缩成一次内部寄存器写入,省下来的时间很可观。前提是设备树里申请引脚时要避免 GPIO 号映射到不同 bank。我在 RK 和全志平台上都用这个方法,数据线接入同一个 bank 时,刷屏速度能快接近一倍。你的板子如果数据线被 PCB 布到不同 GPIO 组,那这个优化就没法用,只能通过查看 SoC 的 GPIO 寄存器,手写 memory-mapped 的赋值代码。
关于显存拷贝问题,尽量让用户态进程直接mmap显存,而不是通过write系统调用。Qt 的 LinuxFB 支持mmap方式,但如果你自己写绘图程序,不要每帧都memcpy一份中间缓冲到screen_base。合理做法是让应用直接在这种显存上绘制,绘图结束后调用ioctl(fd, FBIOPAN_DISPLAY, ...)做一次同步。FBIOPAN_DISPLAY在多数 fbdev 驱动里只是复制var参数,真正提醒驱动刷新还是要靠我们自定义的fb_ops里的fb_pan_display回调来实现。
最后一个值得养成的习惯是给驱动加一个debugfs节点,用来强制触发一次整屏刷新和调节刷新周期。I2C 的 0.96 寸小屏通常不需要这种机制,因为分辨率低、刷得快,但 8080 的 4.3 寸屏进入低功耗模式后再唤醒,常常需要重新执行初始化序列。如果在驱动里实现了唤醒后全屏刷新的路径,该节点还能帮你快速验证时序是否需要重新训练。/sys/kernel/debug/lcd8080/refresh这个接口用起来比反复卸载加载模块高效得多,调试时能省掉大量白屏等待时间。
本文还有配套的精品资源,点击获取