尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

RK3568平台SPI LCD的FrameBuffer模式驱动开发全解析

RK3568平台SPI LCD的FrameBuffer模式驱动开发全解析 1. 为什么到了RK3568还会有人用FrameBuffer模式驱动SPI LCD先把这个选择摆到桌面上说清楚。RK3568是瑞芯微旗下那颗四核Cortex-A55的SoC带G52 GPU支持4K解码显示链路本身有VOPVideo Output Processor和丰富的显示接口。按常理说这板子要么走RGB并口要么走MIPI DSI再要么HDMI和eDP怎么也不该轮到SPI接口的屏幕。但实际项目里SPI LCD在RK3568平台上出现的频率比想象中高得多。我接触过的场景大致有这么几类一是低成本HMI小面板比如那种2.0寸到4.0寸的IPS屏分辨率通常是240x320或者480x800接口就是4线的SPI加DC脚二是做为调试辅助屏不参与主显示流程只用来打印状态信息、显示IP地址和运行时长三是一些工业设备上需要紧凑型显示模块不想为了一个显示功能去重新设计整条RGB信号线。这三个场景里FrameBuffer模式恰好够用。FrameBuffer模式和DRM/KMS的区别简单说就是DRM是内核现在主推的显示框架把CRTC、Encoder、Connector、Plane这些概念都抽象出来了RK3568官方BSP里主要支持的都是DRM通路而FrameBuffer是老的fbdev框架直接维护一块内核内存作为显存用户态应用程序打开/dev/fb0用mmap映射内存往里面写像素数据驱动再把这块内存里的数据通过SPI刷到屏幕上去。为什么还有人坚持用FrameBuffer原因很实际SPI接口本身带宽就低不管用什么框架它的上限就在那里。如果只是显示静态画面、文字、简单图形FrameBuffer模式的内核配置简洁、调试容易、依赖少而且不需要在用户态引入复杂的显示合成逻辑。另外一点网上关于fbdev的参考代码多quick-and-dirty的时候真的比DRM省事。但要说清楚这不是否定DRM。如果你想跑Weston、跑流畅的动画、做双图层叠加SPI屏幕用DRM同样可以做就是工作量明显大。本文讨论的是FrameBuffer模式所以后面的设备树、驱动代码和调试路径都以fbdev为基础这一点先明确下来。2. RK3568的SPI控制器与SPI LCD面板的硬件匹配分析2.1 RK3568上有哪些SPI控制器可以用RK3568一共提供了6组SPI控制器标号从SPI0到SPI5。每组控制器都支持Master模式和Slave模式有独立的时钟、FIFO深度和中断。从SoC的引脚复用来看每组SPI的引脚都映射到了不同的GPIO bank上而且大部分都有m0和m1两个映射选项这就给PCB布局留了不少弹性的空间。具体的地址和中断号在设备树里已经有了默认定义比如SPI1的节点地址是0xfe610000SPI2在0xfe620000SPI3在0xfe630000。这里有一个容易忽略的点是RK3568的SPI控制器时钟源来自CRU模块实际bitrate可以配置的范围比较宽但如果你想跑到50MHz以上需要留意时钟树里SPI的父时钟选择。在默认配置下很多板子跑40MHz是稳定的再往上就需要逐板调试。对于SPI LCD这种设备通常不需要很高的时钟。240x320的分辨率、RGB565格式、60fps的刷新率理论上需要的像素带宽是240x320x2x60大约是9.2MB/s。如果按SPI 8bit模式传输每个像素要传2个字节也就是18.4Mbps的速率。再加上帧与帧之间的消隐和命令开销30MHz左右的SCLK其实已经能跑得比较舒服了。所以绝大多数情况下SPI LCD节点把spi-max-frequency配成30MHz到40MHz之间就够。2.2 SPI LCD的常见驱动IC和接口定义市面上常见的SPI LCD从驱动IC来分主要有ST7789V、ILI9341、GC9307、NT35510等。其中ST7789V和ILI9341占了240x320这个分辨率的绝大多数。两者接口都是标准的4线SPISCLK、MOSI、CS再加一根DC数据/命令选择引脚部分模块还把RESET和背光控制也引出来了。这里说的4线SPI其实是三个SPI信号加一个DC脚注意不要和全双工四线SPI搞混。SPI LCD的MOSI同时承担命令和数据的发送SCLK提供时钟CS是片选DC脚决定当前字节是命令还是数据。有些模块的DC可以直接复用SPI控制器的某个GPIO也可以自己指定任意空闲GPIO驱动里控制起来都方便。从面板供电来看大部分小尺寸SPI LCD模块的面板逻辑电压是3.3V背光LED串的电压可能是3.3V也可能是更高具体由模块的背光电路决定。RK3568的GPIO bank电压可以通过SDIO/GPIO的电压域配置来调整但一般的开发板GPIO都是3.3V电平直接连STM32、ESP32这类MCU的模块可以直接对接。需要注意的是如果模块的IO逻辑电平是1.8V那就要检查RK3568对应bank的VCCIO是否拉到了1.8V否则画面可能异常。2.3 引脚规划和设备树pinmux准备在开始写设备树之前先把引脚规划做完整。以下是一个我实际用过的引脚分配表板子不同引脚可以替换但思路是一致的功能引脚RK3568 Pinmux说明SCLKGPIO3_B1SPI1_M0_CLKSPI时钟MOSIGPIO3_B2SPI1_M0_MOSI主出从入CSGPIO3_B0SPI1_M0_CS0硬件片选DCGPIO3_C0GPIO功能命令/数据切换RESETGPIO3_C1GPIO功能复位信号BACKLIGHTGPIO3_C2GPIO功能或用PWM背光开关/亮度需要注意CS这个脚如果你用SPI控制器的硬件片选pinmux里要选成SPI1_M0_CS0如果你想省一个控制器引脚、用软件模拟片选那CS脚设成GPIO功能驱动里自己拉低拉高。实际调试中我发现用小尺寸LCD模块时硬件片选比软件片选更省心因为软件片选的时序抖动可能导致首字节误触发而且硬件片选在内核SPI框架里已经有成熟的cs控制逻辑。RESET脚虽然很多模块内部都自带上电复位电路但强烈建议还是用GPIO来控一下因为上电时序不满足时屏可能进入异常状态。我在调试过程中遇到过一次上电后花屏后来发现是复位脚悬空模块内部复位电路没有正确触发用GPIO拉低再拉高一次就好了。3. 设备树里SPI LCD节点的配置方法3.1 在SPI控制器节点下挂载panel设备设备树是RK3568 Linux驱动开发绕不开的一层。SPI LCD的驱动本质上是SPI从设备驱动所以在设备树里要把它挂在某个SPI控制器节点下面。以下是SPI1控制器节点下挂载ST7789V设备的典型写法spi1 { status okay; pinctrl-names default; pinctrl-0 spi1m0_cs0 spi1m0_pins; assigned-clocks cru SCLK_SPI1; assigned-clock-rates 200000000; max-freq 40000000; st7789v: st7789v0 { compatible powertip,st7789v; reg 0; spi-max-frequency 30000000; rotate 0; bgr 0; fps 30; buswidth 8; reset-gpios gpio3 RK_PC1 GPIO_ACTIVE_LOW; dc-gpios gpio3 RK_PC0 GPIO_ACTIVE_HIGH; backlight-gpios gpio3 RK_PC2 GPIO_ACTIVE_HIGH; status okay; }; };这里有几个细节值得展开assigned-clocks和assigned-clock-rates是用来设置SPI1控制器的工作时钟的我经常看到有人省略这两个字段结果SPI时钟跑在上电默认值要么低得离谱要么高得发飘。设置成200MHz的父时钟再通过SPI控制器的时钟分频得到实际SCLK。reg 0对应片选地址0也就是CS0。如果你的控制器接了多个SPI设备这个值要相应调整。compatible字段是你驱动里of_match_table匹配时用的名字我用的powertip,st7789v只是举例到底写什么完全由你自己的驱动决定只要设备树和驱动对得上就行。reset-gpios、dc-gpios、backlight-gpios都是驱动里要通过devm_gpiod_get_optional之类的接口去解析的如果你驱动没用GPIO写了也白写反过来驱动里要用的GPIO设备树里忘了配probe阶段就会报错。GPIO_ACTIVE_LOW/HIGH的定义要跟实际电路一致这是新手最容易搞反的地方。3.2 背光节点的独立配置思路背光最好单独建一个节点不直接塞在LCD节点里。原因有两个一是背光很可能会用到PWM调光PWM在设备树里通常是独立的节点让LCD驱动直接管PWM属于越权二是如果把背光做成platform_device用户态可以通过sysfs去调亮度做产品时交互体验好很多。backlight: backlight { compatible pwm-backlight; pwms pwm3 0 20000 0; brightness-levels 0 20 40 60 80 100 120 140 160 180 200 220 240 255; default-brightness-level 10; status okay; };如果你的屏幕背光只有开关功能没有亮度调节需求那用一个普通的GPIO-led节点或者直接在LCD驱动里操作GPIO就够了不必为此引入PWM。3.3 设备树配置后的验证手段设备树写好后内核编译时建议把SPI和SPI LCD相关的驱动都编成模块方便调试时动态加载卸载。启动后先看dmesg里SPI控制器是否注册成功dmesg | grep -i spi看到类似spi1 spi1.0: setup mode 0, 8 bits/w, 30000000 Hz max这样的日志说明设备树解析和SPI框架已经工作了。如果没有这条日志先查pinmux是否冲突再看status okay有没有写对。还可以用ls /dev/fb*确认fbdev设备节点是否生成。如果生成了/dev/fb0那驱动probe基本已经走到最后一步了。4. 从spi_device到fb_info驱动注册链路拆解4.1 驱动框架选择fbtft还是自己写Linux内核里有一套SPI LCD的通用驱动框架叫fbtftFrameBuffer TFT它把市面上主流的小尺寸LCD控制器都封装了一遍ST7789V、ILI9341这些都有现成驱动。按说直接用fbtft是最省事的为什么还要自己写fbtft的优势是代码成熟、配置灵活对大多数场景开箱即用加上设备树里写compatible sitronix,st7789v就能跑起来。缺点也很明显第一fbtft里面的初始化序列是固定的但市面上很多模组虽然用的同一颗驱动IC厂商却会修改Gamma曲线、偏压设置、扫描方向等寄存器直接套用可能出现色彩偏差或者显示方向不对第二fbtft的资源管理方式和RK3568的内核版本之间偶尔有小摩擦调试起来要多绕几个弯第三如果是做产品你可能需要对初始化序列做差异化配置这时候自己写驱动反而更可控。我个人的倾向是如果你只是想在RK3568上快速验证屏幕能不能亮用fbtft如果你准备把这个屏幕真正用进量产产品自己维护一个精简驱动把上电时序、初始化序列、刷新路径都握在自己手里。下面我讲的是自己写的方式因为自己写一遍之后对fbtft的内在逻辑也会有更深的体感。4.2 驱动的数据结构与匹配关系一个SPI从设备驱动核心要处理的是两个结构体struct spi_driver和struct fb_info。struct spi_driver负责把驱动的id_table和设备树里的compatible匹配起来Probe函数在设备树节点被正确解析后触发。static const struct of_device_id st7789v_of_match[] { { .compatible powertip,st7789v, }, {}, }; MODULE_DEVICE_TABLE(of, st7789v_of_match); static struct spi_driver st7789v_driver { .driver { .name st7789v, .of_match_table st7789v_of_match, }, .probe st7789v_probe, .remove st7789v_remove, }; module_spi_driver(st7789v_driver);struct fb_info则是由framebuffer_alloc分配配置好fb_var_screeninfo和fb_fix_screeninfo后用register_framebuffer注册到内核。4.3 probe函数里要做的事probe函数是整个驱动的重头戏按顺序做这几件事第一拿到struct spi_device设置SPI模式。SPI LCD控制器通常工作在SPI Mode 0CPOL0CPHA0也有一部分模块要求Mode 3这个要查模组手册。设置方式是spi-mode SPI_MODE_0; spi-bits_per_word 8; spi-max_speed_hz 30000000; spi_setup(spi);第二解析GPIO。DC、RESET、背光这几根线都要在这里解析并申请。dc_gpio devm_gpiod_get(dev, dc, GPIOD_OUT_LOW); reset_gpio devm_gpiod_get(dev, reset, GPIOD_OUT_HIGH); backlight_gpio devm_gpiod_get_optional(dev, backlight, GPIOD_OUT_LOW);第三执行LCD控制器的上电时序。一般是拉低RESET - 延时10ms - 拉高RESET - 延时120ms以上有些IC要求最长120ms。这个时序流程如果不对后面初始化序列发了也白发。第四发送初始化序列。这是体力活就是把几十个寄存器的配置值一个个通过SPI写进去。ST7789V的常见初始化序列大致包括static const u16 st7789v_init_sequence[] { 0x01, 0x00, // SWRESET 软件复位 0x11, 0x00, // SLPOUT 退出睡眠模式 0x3A, 0x05, // COLMOD 设置为16bit/pixelRGB565 0x36, 0x00, // MADCTL 设置扫描方向 0x21, 0x00, // INVON 反色开启 0x13, 0x00, // NORON 正常显示模式 ... 0x29, 0x00, // DISPON 开启显示 };具体寄存器值必须查芯片手册不同批次甚至不同模组厂商给出的推荐值会有差异。初始化完成之后屏幕理论上应该已经能显示内容了只是还没有显存内容可以刷。第五分配fb_info显存。这里有一个重点SPI LCD的像素格式一般用RGB565屏幕上每个像素占2个字节240x320的屏需要240x320x2 153600字节。如果只用这块内存作为虚拟显存不涉及DMA因为SPI传输是用CPU发送的那么用dma_alloc_coherent和vkzalloc都可以。我习惯用devm_kzalloc分配够用就行。第六填充fb_fix_screeninfo和fb_var_screeninfo。fix-smem_start virt_to_phys(fb_buffer); fix-smem_len 240 * 320 * 2; fix-type FB_TYPE_PACKED_PIXELS; fix-visual FB_VISUAL_TRUECOLOR; fix-line_length 240 * 2; var-xres 240; var-yres 320; var-bits_per_pixel 16; var-red.offset 11; var-red.length 5; var-green.offset 5; var-green.length 6; var-blue.offset 0; var-blue.length 5;第七注册fb_ops。这里的核心是fb_fillrect、fb_copyarea、fb_imageblit这三个函数你可以用内核通用的cfb_fillrect、cfb_copyarea、cfb_imageblit它们负责把用户的绘图操作转换成对显存的修改。之后还需要一个刷新函数把显存里的数据通过SPI发送到屏幕这个函数在fb_ops的fb_ioctl或者自定义的定时器/工作队列里调用。4.4 刷屏路径的设计刷屏是SPI LCD驱动里最关键的路径。Linux的fbdev机制本身并不知道你是一个慢速SPI屏幕用户进程往/dev/fb0里写数据之后框架不会自动通知驱动去刷新屏幕。所以需要驱动主动做这件事常见做法有两种做法一是轮询式刷新内核里开一个定时器或者delayed_work比如30fps就是每33ms把整帧数据刷一次。这种做法简单粗暴但缺点是即使画面没变化也在浪费带宽。做法二是脏矩形刷新在fb_ops的fb_write或者fb_imageblit被调用时记录显存中被修改的区域然后通过工作队列在一个小的延时窗口比如16ms内统一发送。这种方式能大幅减少SPI传输量但因为fbdev框架不直接提供脏矩形回调实现起来要自己在fb_write的路径上加钩子。对于大多数显示静态内容的应用场景轮询式刷新已经够了。实测下来240x320 RGB565屏幕30MHz SPI时钟下整帧传输大约需要240x320x2x8/30000000大概是41ms也就是说理论上限也就24fps左右。如果开了脏矩形刷新显示时钟、文字这种场景的SPI负载能下来一大截。5. 点亮过程中的实际问题与排查链路5.1 屏幕完全没反应的整体排查顺序这是调试中遇到最多的一类问题注册信息一切正常/dev/fb0也生成了程序往里面画了颜色但屏幕就是不亮。按下面的顺序去排查基本能覆盖90%的情况。第一步查屏供电。模块的VCC有没有3.3V或者5V看规格背光LED有没有供电。拿万用表量一下模块的电源引脚这步最基础但也最容易翻车我遇到过模块供电线接触不良导致屏幕完全不亮的。第二步查RESET时序。用示波器或者逻辑分析仪看一下RESET引脚上电之后是不是有一个低脉冲。很多模组虽然内部有上电复位电路但如果电源爬坡太慢内部复位可能失效。驱动里手动控制RESET是最可靠的做法。第三步查DC和CS的电平。初始化序列阶段DC脚应该在命令字节时保持低电平、数据字节时保持高电平CS则在每个SPI事务期间保持低电平。如果CS没有正常拉低控制器根本不会理会SPI总线上的数据。第四步查背光。很多时候屏其实已经显示了只是背光没亮肉眼看不出来。用强光手电贴着屏幕照如果能看到淡淡的图像轮廓说明显示通路已经通了问题就出在背光控制上。5.2 白屏问题初始化序列是否真正发出去了白屏意味着屏幕背光亮了但液晶分子没有偏转所有像素都呈现透光状态。这通常是初始化序列没有成功执行或者执行了但被后续的SPI事务打断了。排查方法是在驱动代码里每发送一条初始化命令之后加一个短延时并检查SPI的spi_write返回值。另外需要关注的一点是ST7789V这类IC在收到软件复位0x01之后需要等待150ms左右才能发送后续命令如果这个延时不够后续命令会被IC忽略表现出来就是白屏或者花屏。提示初始化序列发送完毕后不要急着返回至少延时20ms再开启显示0x29很多屏的ST7789V数据手册里对命令间隔都有明确要求。时序宽松的模块可能没感觉时序敏感的模块就会随机白屏。5.3 画面颜色不对RGB和BGR的顺序问题当屏幕能显示但颜色不对比如红色显示成蓝色绿色显示成品红很多情况下是RGB颜色顺序不对。ST7789V通过MADCTL寄存器0x36的bit3来控制RGB/BGR顺序默认值可能因模组而异。设备树里我预留了一个bgr字段驱动里根据这个字段去设置MADCTL的bit3。调试时如果颜色不对直接把该字段翻转即可不用重新编译驱动。另外还需要检查fb_var_screeninfo里定义的RGB位域偏移是否跟控制器的实际行为一致有些驱动IC实际是BGR565内核层的位域定义就要跟着反过来。5.4 花屏和横条纹时钟太快或信号质量差花屏一般不是初始化序列的问题而是数据在传输过程中发生了错误。优先级最高的怀疑对象是SPI时钟频率太高。如果模块的PCB走线比较长、又没有做好阻抗匹配三四十MHz的SCLK在线上会有明显的过冲和振铃导致接收端采样出错。遇到花屏先把spi-max-frequency降到10MHz试一下。如果降低频率后画面稳定基本可以确认是信号完整性问题。接下来可以考虑优化走线长度、串联端接电阻或者退回到20MHz附近的稳定频率。我曾经在一块核心板上测试40MHz的花屏降到25MHz就一切正常差距很微妙。另一个花屏来源是供电纹波。屏幕做整帧刷新时电流会有周期性的波动如果供电网络偏弱可能在工作频率上产生可观的纹波进而影响SPI信号的电平判断。这种情况下用RC滤波、加大电容都能缓解。5.5 刷新闪烁和撕裂帧率与传输时间不匹配刷新闪烁多数不是因为屏幕本身质量差而是刷屏路径和内容更新路径没有同步。最典型的情况是用户程序一边往显存里写新帧驱动的工作队列一边在SPI上刷旧帧和半新帧用户肉眼就会看到画面的闪烁或者撕裂。解决思路是引入简单的双缓冲概念但fbdev机制里显存只有一块做起来不如DRM的plane那么干净。实用做法是把刷新动作放在一个mutex保护的工作队列里用户程序写入显存时也尝试拿到同一个锁在fb_write里做这样能显著减少撕裂的概率。对静态显示场景来说效果已经足够好。6. 性能优化与面向产品的细节打磨6.1 SPI时钟频率和DMA的取舍SPI LCD的刷新性能主要被两个因素卡住一是SCLK频率二是SPI传输时的数据搬运方式。RK3568的SPI控制器支持DMA模式数据发送的时候可以不经过CPU逐字节搬运而是让DMA把内存里的像素数据直接搬到SPI的FIFO。这在显示大量静态内容时能明显降低CPU占用。但要注意SPI LCD的DMA跑起来有个隐含前提你要刷的数据在物理内存上是连续的。vkzalloc分配的内存是虚拟地址连续的物理页可能是离散的所以如果要走DMA路径最好用dma_alloc_coherent分配显存确保物理连续。我实测过同一个驱动的两种路径CPU发送模式下30MHz SPI时钟占用了一个CPU核心大约30%的负载切到DMA模式后负载降到接近10%。对于跑业务逻辑的嵌入式系统来说这个差异很关键。6.2 局部刷新真正让SPI LCD流畅起来的技巧上面提过的脏矩形刷新在产品落地时几乎是必须做的优化。具体实现不复杂在fb_write或者fb_imageblit的hook里比较新写入的坐标范围和上次刷新的范围合并出一个更新矩形然后把这个矩形区域内的像素数据发送到屏幕。ST7789V支持通过设置列地址0x2A和行地址0x2B来限定后续写入的GRAM区域所以局部刷新在指令层面是完全可行的。以显示一段滚动文本为例如果全屏240x320刷新一帧41ms如果用局部刷新只更新有文字变动的区域比如80x20像素一帧只需要80x20x2x8/30000000大约0.85ms差了一个数量级。这就是为什么同样的SPI屏幕有人做出来的效果顺滑有人做出来卡成PPT关键都在局部刷新上。6.3 开机logo显示与console输出FrameBuffer模式有一个额外的好处通过内核的fbcon模块可以让内核日志直接输出到SPI LCD上。这对调试和产品现场运维都很有帮助。要启用这个功能内核配置需要打开CONFIG_FRAMEBUFFER_CONSOLE然后在内核启动参数里加fbconmap:1或者直接consoletty1。这样内核的printk输出就会显示在屏幕上。第一次把内核日志打到SPI屏幕上的体验还是很奇妙的虽然刷新速度跟真正的终端没法比但嵌入式场景里设备没有网口、没有串口的时候这块屏就是唯一的眼睛。开机logo也可以放在这个链路里。最简单的方式是做一个用户态的小程序在系统启动早期通过/dev/fb0把logo图片显示出来然后用systemd启动单元或者rcS脚本拉起。6.4 休眠唤醒的电源管理处理产品化之后省电是一个绕不开的需求。SPI LCD在系统休眠时需要做两件事一是把屏幕内容停在一个安全的低功耗状态通常是进入睡眠模式ST7789V的0x10命令二是把背光关掉。驱动里实现spi_driver的shutdown回调或者pm_ops在休眠前发送SLPOUT的逆操作——SLEEPIN命令并把背光GPIO拉低。唤醒时重新执行上电时序和初始化序列。这里有个经验很多屏在休眠后唤醒重新初始化序列不能偷懒只发DISPON因为GRAM的内容可能已经丢了需要做完整的复位和初始化否则唤醒后可能出现花屏。6.5 内核配置的裁剪建议如果你做的是量产固件内核配置里不一定需要保留所有SPI LCD相关的debug选项。但以下选项建议保留CONFIG_FB: fbdev框架本体CONFIG_FB_CFB_FILLRECT/CONFIG_FB_CFB_COPYAREA/CONFIG_FB_CFB_IMAGEBLIT: 通用的显存操作函数CONFIG_FRAMEBUFFER_CONSOLE: fbcon支持CONFIG_LOGO: 开机logo支持CONFIG_SPI_ROCKCHIP: RK3568的SPI控制器驱动如果不再需要eMMC引导时的其他显示输出可以把DRM相关的显示驱动裁剪掉一部分这样能省下可观的内存占用和启动时间。但需要小心RK3568的VOP和DRM链路跟系统其它部分的耦合度不低裁剪前要确认没有别的模块依赖它。7. 从FrameBuffer到DRM的后续演进路径最后聊一下这套方案的后续演进。如果你已经把SPI LCD在FrameBuffer模式下跑通了并且开始嫌弃它不够现代想往DRM方向迁移有一些工作是可以平滑过渡的。DRM框架下SPI LCD通常会被实现成一个drm_panel驱动配合一个简单的drm_connector和drm_encoder。相比fbdevDRM的优势是对用户态的接口更标准Wayland合成器、X11、Android的HWC都能直接识别这块屏。代价是你需要自己实现drm_simple_display_pipe的atomic_flush回调里面做的事情和fbdev模式下的刷屏路径本质上是一样的只是换了一层壳。迁移时你在FrameBuffer模式下积累的调试经验——上电时序、初始化序列、刷屏路径、局部刷新逻辑——全部可以复用。所以不用觉得现在写fbdev驱动是在走弯路它反而是理解DRM那条链路底层逻辑的捷径。我见过很多先写fbdev、后迁移DRM的工程师对屏幕为什么亮、为什么花、为什么慢的理解深度比那些一上来就套DRM框架的人扎实得多。这块SPI LCD驱动做完之后可以继续做的事情还挺多的比如加一个简单的Framebuffer缩放算法让更高分辨率的framebuffer内容缩放到240x320显示或者做一个用户态的绘图库在/dev/fb0上直接渲染简单的仪表盘控件。每次做这类扩展你都会发现SPI LCD虽然慢但正因为慢反而逼着你把每一帧的代价都想清楚这种对传输带宽和计算开销的敏感度在嵌入式开发里是通用的底层能力。
返回列表