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

资讯详情

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

RK3568 SPI LCD驱动开发实战:基于FrameBuffer的ST7789V移植与优化

RK3568 SPI LCD驱动开发实战:基于FrameBuffer的ST7789V移植与优化 做嵌入式Linux开发这些年屏幕驱动这块永远是最能让人“又爱又恨”的部分。前阵子刚完成一块240x320分辨率、SPI接口的ST7789V小屏在瑞芯微RK3568平台上的驱动适配用的是Linux标准的FrameBuffer框架。这个项目本身不算复杂但一路捋下来涉及设备树配置、SPI时序、内核驱动注册、用户态显存操作这些环节每个地方都可能藏着几个暗坑。写这篇东西就是想把RK3568上SPI LCD驱动的完整实现路径、关键参数的计算方式、调试中的排错思路都摊开来讲清楚给后面要做类似移植的朋友一个可以直接参考的版本也帮刚接触FrameBuffer驱动开发的同学省点走弯路的时间。1. 项目全景与核心思路拆解1.1 为什么要在RK3568这类MPU上接一颗SPI小屏RK3568本身是带RGB、LVDS、MIPI DSI这些显示接口的理论上接大屏才是它的常规用法。那为什么还会有人拿它去驱动一颗SPI接口的小尺寸TFT屏这个问题的答案基本决定了整个项目的技术选型方向。实际项目里遇到这种需求通常是下面几种场景叠加。第一是成本敏感的设备不需要大屏交互只需要一个能显示状态信息、二维码、简单图标的迷你屏幕RGB565格式的SPI屏单价够低。第二是硬件改动最小化主控板已经设计好了核心板引出的显示接口没做预留只剩SPI总线能复用出来接屏。第三是功能定位限制设备主要跑业务逻辑屏幕只是辅助显示不需要高刷新率更不需要GPU合成用FrameBuffer模式就够了。我当时这个项目就是典型的第二、三种情况结合。设备是一台工业数据采集终端主界面需要实时显示运行状态和几组传感器数值屏幕只需要刷新数字和图标对帧率要求不高但对启动速度、功耗、稳定性有要求。综合来看一颗240x320的ST7789V SPI屏加FrameBuffer驱动是性价比最高的方案。这里要纠正一个常见的认知误区很多人觉得RK3568跑Linux显示这块就应该上DRM/KMS那一套FrameBuffer是过时技术。但其实FrameBuffer作为内核中最基础的显示框架至今仍在无数嵌入式设备上服役。对于小尺寸低刷新率的SPI屏FrameBuffer无论是内存占用、CPU开销还是开发维护成本都比引入完整DRM链路要轻量得多而且更容易控制时序。1.2 FrameBuffer在Linux显示链路里的位置要理解FrameBuffer模式驱动SPI LCD得先把Linux显示链路的几个层次弄清楚。从上到下大概是应用层用户程序、fbdev接口/dev/fb0、内核FrameBuffer核心层、具体的显示驱动、硬件屏幕。大部分人不理解的一点是FrameBuffer其实不直接负责把数据推送到屏幕上它管理的是一块内核分配的内存区域也就是显存。应用层通过mmap把这个内核缓冲区映射到用户空间然后往里面写入像素数据。内核中的驱动负责把这块内存里的数据搬运到实际的显示硬件上。举个例子帮助理解可以把FrameBuffer想象成一块黑板应用层拿着粉笔在黑板上写字写完之后负责展示的人驱动再把黑板上的内容搬到LED屏幕上给大家看。对于RGB并口屏或MIPI屏这个搬运过程由硬件控制器自动完成而对于SPI屏因为屏幕本身不带RGB控制器搬运动作就得靠CPU通过SPI总线把数据一笔一画地写到屏幕的GRAM显存里。所以这次项目的核心任务就很清晰了在RK3568上注册一个FrameBuffer设备同时写一个通过SPI接口初始化并刷新屏幕的驱动。上层应用不用关心屏幕是RGB屏还是SPI屏只要往/dev/fb0写入数据就行。1.3 驱动方案选型FBTFT、自研、还是用户态直接操作明确了要做什么接下来是选择实现路径。目前做SPI LCD在Linux下有三种主流方案各有取舍。第一是使用内核自带的FBTFT框架。FBTFT是内核里专门为SPI小屏设计的驱动框架已经支持ST7789V、ILI9341、ILI9488等众多常见控制芯片。如果屏的型号正好在支持列表里且使用的是GPIO模拟的SPI或片选时序那这种方式几乎零开发量设备树配置一下就能点亮。但它有一个问题FBTFT在内核主线中事实上已经被标记为staging状态有些内核版本编译时可能会出兼容问题而且它对DMA传输、部分厂商LCD初始化自定义命令的支持不够灵活。第二是自己写独立的FrameBuffer驱动这也是我这次选择的方式。自主可控性最强可以针对特定屏控制器的初始化命令做深度的定制背光、伽马、扫描方向、偏压设置都能精确把控调试和排查问题的空间也最大。代价是需要自己对FrameBuffer框架、SPI子系统、设备树都有比较全面的理解。第三是绕开内核驱动直接在用户态操作/dev/spidev设备。这是最省事的方案写一个C程序或Python脚本调spidev接口就可以给屏幕发数据。但在这个项目中我直接否掉了这个方案原因有两个一是FrameBuffer设备没了上层应用如果原本是走fbdev接口的GUI库就完全无法工作二是用户态做刷屏会频繁地在用户态和内核态之间切换刷新率高一点CPU占用率就很难看。选择自研驱动本质上是用一定的开发工作量换取最大的灵活性和可控性。这也是我一贯的想法如果这个屏幕在你的产品里是长期存在的那自研驱动一次投入后续维护和扩展都是自己的节奏。2. 硬件连接与设备树配置要点2.1 SPI控制器、引脚复用与片选的选择RK3568一共集成了6个SPI控制器SPI0到SPI5每个控制器既可以做master也可以做slave。我们这里用master模式从CPU控制器发数据到屏控制芯片。在选择具体用哪个SPI控制器时要看两个东西一个是引脚复用RK3568大部分外设引脚都有多组mux比如SPI0有m0和m1两组引脚可选选择时需要注意这几个引脚有没有被其他外设比如UART、I2C、PWM占用另一个是能不能跑到目标频率不同引脚组的信号完整性略有差异差分走线和PCB长度这些因素虽然对低速SPI影响不算大但对20MHz以上频率也会有影响。我在项目中用的是SPI0的m0组引脚分别是SCLK时钟、MOSI主出从入、CS0片选0。还有两个额外信号需要单独分配GPIODC数据/命令选择和RST复位这两个脚在标准SPI控制器里没有专用通道必须用普通GPIO来模拟时序。硬件连接上有一个细节值得注意SPI屏的MISO引脚一般是不用的屏幕数据是单向从主控流向屏幕这种模式下省一条线也避免占用另一路SPI引脚但对驱动来说需要确保SPI控制器在单工mode下工作正常。引脚确定后在设备树里要进行两件事一是把SPI0的pinctrl配置成m0组引脚二是把SPI0节点的status改为okay。具体引脚组编号以SDK里的pinctrl设置文件为准不同内核版本命名可能稍微有差异。2.2 设备树节点拆解从SPI总线到fb_panel设备树是驱动和设备之间的“连接桥梁”。对于SPI LCD需要在SPI控制器节点下面创建一个子节点描述屏幕这个从设备。这里给出一个完整的参考配置spi0 { status okay; pinctrl-names default; pinctrl-0 spi0m0_pins; max-freq 20000000; st7789v: st7789v0 { compatible myvendor,st7789v; reg 0; spi-max-frequency 20000000; reset-gpios gpio4 RK_PA5 GPIO_ACTIVE_LOW; dc-gpios gpio4 RK_PA6 GPIO_ACTIVE_HIGH; backlight-gpios gpio4 RK_PA7 GPIO_ACTIVE_HIGH; width 240; height 320; rotate 0; bpp 16; fps 30; buswidth 8; }; };简单拆解一下这些属性的含义。compatible字符串是驱动与设备节点匹配的关键驱动里的of_match_table必须包含这个字符串。reg 0代表这个从设备挂在SPI控制器的CS0上如果接CS1就改成reg 1。spi-max-frequency告诉内核这个从设备最高可以跑到多高的SPI时钟驱动在初始化SPI控制器时会按这个频率去配置。reset-gpios、dc-gpios、backlight-gpios三个属性是在驱动里通过devm_gpiod_get获取背光、复位和数据/命令控制引脚的依据。width、height、rotate、bpp、fps这些参数则对应屏的物理规格驱动会读取它们来初始化FrameBuffer的固定信息和可变信息。有一点务必注意上述属性名如果走的是自研方式完全由我们自己定义只要驱动和设备树对应上就行如果走的是FBTFT方式属性名就必须遵循FBTFT的约定比如fps、rotate、buswidth这些在FBTFT里都有固定的语义。用自定义compatible时这些字段的具体含义需要在驱动代码里明确定义不要引用了没实现那样就是无效字段。2.3 背光与复位引脚的GPIO设计背光控制这块往往是新手容易漏掉的地方。SPI屏不像大屏有独立的背光驱动IC通常只是几颗LED直接用GPIO拉高或拉低就能点亮。用GPIO控制背光的好处是省成本但缺点是亮度只能开关不能调。如果产品需要亮度调节就得换成PWM背光RK3568的PWM控制器很丰富在设备树里配一个pwm-backlight节点也不是难事。复位引脚的时序也有讲究。绝大多数TFT屏控制芯片要求上电后复位脚保持低电平至少10ms然后再拉高驱动内部再延时等待电源稳定。如果这一步做得太粗糙很容易出现上电白屏但驱动初始化看起来又正常的情况。驱动里处理复位时建议这样拿GPIO后先拉低msleep(50)拉高再msleep(120)。这个时序是ST7789V手册里明确要求的其他控制芯片大同小异。另外DC数据/命令选择引脚的极性设计会影响驱动写屏的效率。常规做法是DC为低时SPI总线上传的是命令字节DC为高时传的是数据字节。因此驱动里每次写命令、写数据都要切换DC的电平状态这就是为什么DC引脚必须用GPIO不能复用给其他外设。3. 驱动实现与FrameBuffer注册全流程3.1 驱动入口、probe流程与资源获取自研驱动的骨架其实非常固定向内核注册一个platform_driver在driver匹配到设备树节点后进入probe函数在probe里完成硬件初始化、FrameBuffer内存分配、fb_info注册最后在remove函数里做逆操作。驱动里最核心的数据结构是fb_info它承载了整个FrameBuffer的所有管理数据和操作函数指针。一个最小可用且工程上能跑的probe流程大致是这样的解析设备树节点获取屏的宽、高、色深等参数。获取并申请SPI控制器资源配置SPI模式一般用SPI_MODE_0或SPI_MODE_3具体看屏的时序图ST7789V两个都支持但手册推荐的模式要确认。获取DC、RST、背光GPIO。执行复位和初始化序列。分配FB显存空间size width * height * bpp / 8。填充fb_fix_screeninfo和fb_var_screeninfo信息。调用register_framebuffer注册设备。这个流程看起来不长但每步的细节都藏着讲究。比如spi_mode的配置最安全的做法是先用SPI_MODE_0因为大部分SPI从设备默认支持这个模式。如果显示异常再对比屏的读写时序图逐一尝试SPI_MODE_1/2/3问题往往就出在时钟极性和相位的匹配上。GPIO资源的申请一定要使用devm_gpiod_get这类设备资源管理接口它的好处是驱动卸载或binding失败时内核会自动帮你释放资源避免忘了释放GPIO导致后续加载失败。这点在反复insmod/rmmod调试时尤其重要。3.2 初始化序列写命令与写数据的时序LCD驱动开发中初始化序列是整个项目里最“硬核”的部分。所谓初始化序列就是按照屏控制芯片手册上电后往芯片写入一串寄存器配置命令完成屏幕扫描方向、像素格式、RGB顺序、伽马、电源电压等参数的设定。这一串命令通常由厂商提供也会在芯片数据手册的例程里给出。写命令和写数据在SPI总线上是通过DC引脚区分的。实现上写命令和写数据的硬件动作几乎一样区别只在于DC的电平。比如ST7789V的命令0x36是设置扫描方向MADCTL它后面要跟一个参数字节0x00或0xC0这时驱动就需要先DC拉低发0x36再DC拉高发参数0xC0。这里给出一段ST7789V典型的初始化序列作为示意实际参数要根据屏厂调试确定static const struct st7789v_cmd st7789v_init[] { { 0x01, NULL, 0 }, /* SWRESET */ { 0x11, NULL, 0 }, /* SLPOUT */ { 0x36, val, 1 }, /* MADCTL方向/颜色顺序 */ { 0x3A, val, 1 }, /* COLMOD0x05表示16位色 */ { 0xB2, val, 5 }, /* PORCTRL */ { 0xB7, val, 1 }, /* GCTRL */ { 0xBB, val, 1 }, /* VCOMS */ { 0xC0, val, 1 }, /* LCMCTRL */ { 0xC2, val, 1 }, /* VDVVRHEN */ { 0xC3, val, 1 }, /* VRHS */ { 0xD0, val, 2 }, /* PVGAMCTRL */ { 0xD1, val, 2 }, /* NVGAMCTRL */ { 0x21, NULL, 0 }, /* INVON反转显示按屏厂要求 */ { 0x13, NULL, 0 }, /* NORON */ { 0x29, NULL, 0 }, /* DISPON */ };初始化序列的调试过程基本是在“黑箱”里摸索写错了一个寄存器屏幕可能全白、全黑、偏色、闪烁或者出现残影。我的习惯是每屏厂提供的序列先原样搬上去点亮确认基本显示正常后再根据实际效果逐项调整寄存器。特别要注意的是不同批次、不同厂家的同型号屏其推荐的初始化参数可能有差异不能用“同一颗ST7789V所以序列都一样”的思路偷懒。3.3 显存映射与刷屏路径初始化做完屏幕处于待显示状态接下来要做的就是让FrameBuffer里的数据“流动”到屏幕上。SPI屏的GRAM相当于一块屏幕自带的内存FrameBuffer显存是主控侧的内存。刷屏就是把FrameBuffer里的内容搬到屏的GRAM里。应用层可以往/dev/fb0写入数据驱动侧需要通过fb_info的fbops来完成这次写入。在自研驱动中通常的做法是在fbops里把fb_write、fb_fillrect、fb_copyarea、fb_imageblit这几个回调都重新实现或者在fb_write里统一处理写入然后调用自己的刷屏函数。我实现刷屏函数时的核心逻辑是先把FrameBuffer里的显示区域按行切分每次通过SPI发送一条写GRAM起始地址的命令指定当前刷新的窗口坐标然后连续发送整块像素数据。这样比一像素一像素地写快了不止一个数量级。这里有个非常关键的优化点不要整屏刷新。如果只是状态栏某个数值改变了把脏矩形区域的坐标算出来只刷新那部分就可以了。ST7789V这类控制器都支持通过设置CASET列地址和RASET行地址来限定写入区域这样效率提升非常明显。我项目里最初的版本直接整屏刷新SPI总线瞬间成为瓶颈后来改成区域刷新刷新率直观上翻了一倍还多。帧率这个参数在驱动里也很重要。FrameBuffer framework里有一个tty模式的虚拟刷新率概念可以通过fb_var_screeninfo里的vmode字段来设置。但这个值对SPI屏的实际帧率没有直接控制意义真正决定刷得快不快的是SPI频率、刷屏效率和是否用区域刷新。所以设备树里那个fps参数更多是用来给上层应用参考的“标称值”不要指望靠调它就能提高实际刷新率。3.4 帧率天花板SPI带宽怎么算既然提到刷新率那就动手算一下SPI屏的理论帧率天花板。以我用的240x320、RGB565为例一帧数据量计算如下一帧字节数 240 × 320 × 2 153600 字节SPI时钟频率如果配置为20MHz8位模式理论有效数据速率是20Mbps换算成字节就是2.5MB/s。由于每传一帧数据可能需要额外的命令头、地址设置、以及少量延时有效数据率打八折到两千万位每秒以下大约就是2MB/s。那么理论帧率 2MB/s ÷ 153600字节 ≈ 13帧/秒。如果SPI频率提升到40MHz理论帧率约为26帧/秒。这个数字对于显示仪表盘、状态面板这类场景基本够用但如果你要做动画或视频预览就会明显感觉到卡顿。所以把SPI频率尽量跑到屏规格允许的上限很关键。ST7789V的规格书上通常写着SPI时钟最高可以到几十MHz但实际能不能跑上去和PCB走线长度、信号的上下拉、SPI控制器稳定性都有关系。我当时从10MHz往上升一路上探到30MHz都能正常工作最终定为20MHz给自己留了余量也兼顾了信号完整性。如果需要进一步压榨性能可以考虑SPI DMA传输。RK3568的SPI控制器支持DMA mode数据不需要CPU逐字节搬运CPU占用会显著下降但配置复杂度高一些后文还会提到。4. 调试方法、性能优化与实测记录4.1 白屏花屏的排查顺序这个项目里我最想分享的是屏幕上出现问题时怎么最快定位到根因。遇到白屏、花屏、黑屏千万别盲目改代码按照下面这个顺序走能省下大量时间。第一步先看电源。SPI屏的供电电压一般是3.3VLED背光供电可能也是3.3V更亮可以用5V或更高。用万用表量一下屏的VCC和背光LED正极确认电压稳定。电压不稳会造成各种诡异现象比如初始化正常但刷新时随机花屏有时候还会“越刷越白”。第二步看复位。确认RST引脚有正常的复位波形特别是上电延时那一段。用示波器测量的话能清楚看到低电平脉冲和高电平维持时间。如果示波器不方便可以临时在驱动里把复位拉高后延时加大观察是否有改善。如果确认复位没问题再看初始化命令有没有发送成功。第三步看SPI波形。用逻辑分析仪量SCLK、MOSI、CS、DC。重点观察CS低电平时MOSI上有没有数据SCLK的边沿是否干净有没有毛刺。我之前遇到过一次花屏最后查出来是CS引脚在SPI传输结束后没有正确释放导致下一次传输的前几个bit被吞了。这个问题通过观察逻辑分析仪波形一眼就能看出来。第四步看驱动日志。打开内核的SPI和FB调试信息比如动态调试确认驱动确实匹配了设备树节点probe流程走完了没有在资源申请阶段报错。很多“白屏”其实是驱动压根没跑起来屏幕上什么都没有和“驱动跑起来但初始化失败”是两种完全不同的故障。4.2 从dmesg到ioctl的调试工具箱驱动调通的标志不只是屏幕点亮还要保证上层应用能正常工作。调试过程中我常用的工具清单如下dmesg永远是第一环。内核打印里能看到驱动probe的日志、SPI传输的错误日志、注册fb0的消息。注册成功后dmesg里通常会有类似fb0: myvendor/ST7789V frame buffer device的输出确认之后再往下测。fbset可以查看当前FrameBuffer的几何参数和时序参数比如分辨率、色深、虚拟宽高。如果应用发现屏幕显示区域不对先用fbset确认内核侧拿到的是不是设备树里配置的240x320。写像素测试是最直观的功能验证。可以用简单的shell命令向/dev/fb0写入随机数据屏幕如果变成彩色的噪点花屏说明SPI数据通路是通的。更细致的测试是用一个几十行的小程序mmap映射framebuffer后填充纯色和渐变确认颜色格式、RGB顺序、方向是否正确。#include fcntl.h #include linux/fb.h #include sys/mman.h #include sys/ioctl.h int main(void) { int fd open(/dev/fb0, O_RDWR); struct fb_var_screeninfo vinfo; ioctl(fd, FBIOGET_VSCREENINFO, vinfo); int screensize vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; unsigned char *fbp mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); for (int i 0; i screensize; i 2) { fbp[i] 0x00; /* B */ fbp[i 1] 0x1F; /* G */ } munmap(fbp, screensize); close(fd); return 0; }这段小代码的作用是往显存里填蓝色。如果屏显示的是蓝色说明BGR顺序和预期一致如果显示成红色就是RGB顺序需要调整通常通过修改MADCTL寄存器的RGB/BGR位来解决。4.3 性能瓶颈与优化方向在实际调优过程中我认真测过几个版本的数据。最初的驱动是整屏刷新、SPI 10MHz、非DMA模式实测有效刷新率大概只有8帧/秒CPU占用率却到了40%以上。随后做了三步优化效果非常直观第一步把SPI频率提到20MHz有效刷新率提升到了13帧/秒左右CPU占用率略微下降了些。第二步改成了区域刷新只刷新界面变化的部分由于这个应用界面大部分时间只有一个数字在变等效的用户感知刷新率一下就上去了CPU占用率掉到了10%以下。第三步启用了SPI DMA传输CPU占用率进一步降到3%以内。这里说的CPU占用率是用top命令观察的实际效果和应用场景强相关。如果你的应用需要大范围快速刷新比如做波形显示那么区域刷新的收益会降低SPI频率和DMA就变成决定性能的关键因素了。如果后续还想继续提升性能可以考虑把像素格式改成RGB565打包传输而不是一像素两个独立字节传输。ST7789V支持8位和16位两种SPI传输模式16位模式下一个SPI时钟周期传输一个像素的高8位或低8位需要连续两个SCLK才能完整传完一个16位像素但如果模式配置得当传输效率比8位模式有一定提升。具体方式要看芯片手册的SPI interface配置不是所有屏都支持实现前先确认。5. 常见问题速查与避坑实录5.1 问题现象对照表整理一份我这次调试中遇到以及朋友项目中遇到的高频问题直接按现象对照处理现象可能原因排查方向解决办法上电白屏驱动日志正常初始化序列中DISPON未执行或执行失败逻辑分析仪抓初始化阶段命令检查命令列表确认0x29最后发送且后面有足够延时花屏且刷新速度越快越严重SPI时钟频率过高或信号质量差降低SPI频率测试用示波器看SCLK边沿降低spi-max-frequency优化PCB走线或加串阻整屏偏色显示为底片效果MADCTL的RGB/BGR位与屏硬件不匹配纯色测试找出实际颜色映射调整0x36参数中的RGB/BGR位只有上半屏或下半屏显示CASET/RASET窗口设置不对查看写GRAM命令是否指定了完整窗口检查初始化序列和刷屏函数的窗口设置触摸方向与显示方向不一致touch和display各有一套旋转参数分别检查触摸驱动和FB驱动的rotate修改触摸驱动设备树坐标交换/翻转参数屏幕闪一下后永久白屏背光正常但初始化失败导致无内容输出抓初始化序列和复位时序检查RST时序重新确认初始化命令完整SPI通信不稳定偶发丢数据CS时序有问题或DMA配置错误逻辑分析仪抓CS与SCLK的时序关系校正CS拉低提前量和释放时机或关闭DMA降级测试5.2 几个容易被忽略的坑第一个坑是设备树里SPI节点的CS极性配置。有些SPI控制器的片选极性默认是低有效而有些屏幕模块的CS脚电路设计成了高有效。如果设备树里的cs-gpios或spi控制器配置不正确会出现CS永远无效屏幕根本没被选中SPI数据全部被丢弃表现出来就是驱动一切正常但屏永远白屏。解决方法是仔细看屏模块的原理图手册里标注的小圆圈表示低有效要与内核的GPIO_ACTIVE_LOW对齐。第二个坑是GPIO初始状态。在驱动probe之前DC、RST这几个GPIO可能处于不确定状态。为了防止屏幕在驱动加载前的瞬间被误初始化设备树里尽量配置GPIO的默认方向。比如RST默认拉低让屏保持在复位状态等probe流程再释放DC默认拉低让总线处于命令模式。这些默认状态可以通过pinctrl节点的bias-pull-down或gpio-hog机制来实现不加的话初始化前的一小段时间里屏幕可能出现异常闪烁。第三个坑是帧率与刷屏函数的同步。如果上层应用写显存和底层驱动刷屏是并行发生的有可能会把屏幕刷成一半新数据一半旧数据出现“撕裂”感。这个问题在SPI屏上尤其明显因为SPI刷屏速度慢每帧传输时间很长。解决方案是在刷屏前关中断或加锁把拷贝到GRAM的时间窗缩短。如果整个界面变化频率不高也可以在应用层约定好写数据前先获取一个fence锁简单粗暴但有效。第四个坑是关于FB的cmap设置。SPI小屏虽然用的是RGB565直通模式内核的伪彩色cmap不一定需要但在fb_ops里如果没有实现fb_setcolreg部分GUI库初始化时会直接报错或显示异常。哪怕不用伪彩色我建议也把fb_setcolreg实现一下哪怕只是个空操作或简单的16位色填充能省掉很多莫名其妙的兼容性问题。最后再分享一个使用习惯修改设备树后很多人在编译时只编译kernel/dts却忘了还需要重新生成resource.img或boot.img在RK3568平台上通常是boot.img里带dts具体要看SDK的镜像打包方式。每次改完设备树一定要确认烧进去的是新生成的boot镜像否则折腾半天排查代码结果跑的还是老配置。这个项目做下来我最大的感受是RK3568的SPI LCD驱动并不复杂但它强迫你把Linux显示链路底层的这些概念都过一遍。设备树、framebuffer、SPI帧格式、GPIO控制、DMA传输每个知识点单独拎出来都不难串在一起就需要对整个系统有清晰的认识。如果你现在正好在做类似的事我的建议是不要急着追求点亮先把手册、时序、设备树这些基本功吃透然后一步一个脚印地过probe、初始化、刷屏、调试你会发现自己对Linux驱动开发的理解会变得踏实很多。
返回列表