LVGL在嵌入式Linux上的移植与性能优化实战
做嵌入式Linux开发这几年我接触过的图形方案不算少。从早些年用DirectFB做简单界面到后来接触Qt、GTK再到最近两年LVGL在ARM开发板、工业HMI项目里频繁被点名。说句实在话LVGL能在嵌入式Linux上流行起来不是因为它功能比Qt全面而是因为它把轻量和易上手这两件事做到了极致。这篇文章是我基于一个实际量产项目的完整复盘记录——LVGL在嵌入式Linux上的移植过程、性能调优、问题排查以及一些在官方文档里不太容易找到的经验。项目最终跑在Cortex-A7双核1.2GHz的平台上内存256MB屏幕是1024x600的RGB屏系统是BusyBox裁剪后的精简LinuxLVGL版本从8.3升级到了9.2。整个过程踩了不少坑也总结了不少可复用的方法希望能给正在做类似方案的朋友一些参考。1. 移植前必读为什么在Linux上要选LVGL1.1 从MCU到Linux的图形方案演进很多团队走上LVGL这条路其实是从MCU开发转过来的。早期的STM32、GD32等MCU上跑LVGL非常成熟工程师们已经习惯了LVGL的控件风格和开发节奏。到了Linux平台资源从捉襟见肘变成了相对宽裕但这不是说就能随意铺张——工业产品对成本极度敏感很多主控板用的还是老一代Cortex-A7/A9内存就128MB到512MB还要跑业务逻辑、通信协议、数据库留给图形的资源并不多。在这个环境下常见的图形方案有几种Qt、GTK、AWTK、LVGL。Qt全家桶功能最强但也最重一个最小的Qt Widgets应用内存占用轻松飙到80MB以上启动时间按秒算GTK在嵌入式Linux上的定位更偏向桌面或复杂应用依赖组件多裁剪起来费劲AWTK是国内团队维护的跨平台GUI也很轻但生态相对窄LVGL的优势在于它本身就是一个为资源受限场景设计的图形库1MB内存的MCU都能跑到了Linux上更是游刃有余。我用一个表格简单对比一下方案最小内存占用启动速度开发门槛界面效果典型场景Qt/Widgets80MB秒级较高丰富复杂桌面级HMIGTK50MB秒级较高丰富特定Linux桌面/工业AWTK20MB左右百毫秒级中等良好国产化HMI项目LVGL5-15MB百毫秒级低良好设备面板/中控屏LVGL在Linux上还有一个隐性优势它和MCU端的代码结构几乎一样。团队里熟悉MCU开发的人可以直接复用底层逻辑不需要像Qt那样重新学习一套对象模型和信号槽机制。如果你所在的团队之前在单片机项目里积累过LVGL代码那搬到Linux上几乎是平滑过渡。1.2 项目场景与选型依据什么样的产品适合用LVGL做Linux端界面我根据自己的项目经验总结为四类第一类是设备控制面板类比如工业触摸屏、电力监控终端、医疗设备操作界面特点是界面层级浅、控件数量有限、强调响应速度与稳定性。第二类是家电和智能家居中控比如带屏的智能音箱、变频空调控制面板界面简单且动画需求不高LVGL内置的动画完全够用。第三类是仪器仪表界面偏数据展示需要大量图表和仪表盘LVGL有chart控件和仪表控件稍微美化一下就很专业。第四类是对启动速度极度敏感的设备比如汽车后装设备开机要在几百毫秒内出画面LVGL这这种轻量库能快速点亮屏幕而Qt要考虑大量动态库加载很难做到同样速度。反过来如果你的产品需要复杂的非规则窗口、高密度表格交互、网页风格排版或者要嵌入视频播放器和浏览器那LVGL并不是好选择。它本质上还是面向图块化界面的控件库做不到浏览器那种布局灵活性。遇到这种需求别硬扛换Qt或直接上Web技术栈更靠谱。1.3 显示后端选型fbdev还是DRM/KMS这是移植第一步就要面对的问题。Linux下让LVGL把画面输出到屏幕有两条主流路径传统framebufferfbdev和现代DRM/KMS。fbdev是历史悠久的显示子系统通过/dev/fb0这样的设备节点向用户空间暴露显存。好处是简单——打开设备、mmap内存、写入像素数据屏幕就亮了坏处是内核社区早已把fbdev标记为过时新平台尤其是带GPU的SoCfbdev多是用DRM模拟出来的性能和功能都有限制。如果你的目标平台是树莓派、RK系列这类现代芯片只用fbdev会浪费掉硬件合成、多平面显示这些能力。DRM/KMS是现代Linux的标准显示方案。KMS负责管理显示模式、分辨率、连接器等DRM则提供渲染与提交接口。用DRM/KMS需要处理更复杂的ioctl调用和对象模型比如connector、encoder、crtc、plane初期学习曲线比fbdev陡。但换来的是更好的可控性能利用硬件plane做图层合成能配合VBlank信号做垂直同步防撕裂能使用GPU的DMA-BUF直接提交渲染结果。我的建议是如果只是快速验证UI逻辑先用fbdev跑通成本最低驱动代码加显示注册总共不到200行如果产品要量产或者你的平台有GPU/G2D加速单元直接用DRM/KMS走省得后面重新适配。我这次项目最终使用的是DRM/KMS方案因为目标平台主控芯片内部带了2D硬件加速器想物尽其用。fbdev版本我留了分支代码用来做单元测试和模拟器调试。2. 一步步完成LVGL在嵌入式Linux上的移植2.1 获取源码与目录结构LVGL的源码管理非常成熟GitHub官方仓库分为LVGL核心库lvgl和显示/输入驱动库lv_drivers。不过到了9.x版本驱动库的维护重心已经迁移很多平台直接建议开发者自己实现display和input后端不再强依赖lv_drivers。我建议你也按这个思路来用官方核心库自己写Linux下的display/input适配层。版本选择上LVGL目前有两条主流分支8.3.x是最后的稳定大版本API非常稳定网上资料最丰富很多老项目都停留在这条线9.x是当前迭代版本API变化较大但加入了更多现代特性比如更灵活的样式系统、新的事件机制、更好的缩放支持。如果你参考的教程和示例代码大多是8.x的建议先用8.3版本上手如果项目周期长、想保持前瞻性可以选9.x但一定要去官网看迁移文档。我这次项目因为要长时间维护选择了9.2版本。拉取代码很简单git clone https://github.com/lvgl/lvgl.git --branch release/v9.2仓库内部结构清晰核心目录是src里面有display、indev、widgets、draw、misc等子目录。移植时不需要改核心库源码只需要在项目里新建一个lv_port目录放自己的平台适配代码。2.2 配置lv_conf.h正确启停特性LVGL的裁剪配置集中在lv_conf.h文件里。第一次使用要先从lvgl目录复制模板出来cp lvgl/lv_conf_template.h lv_conf.h这个文件至关重要它决定了LVGL编译后的大小和运行时的功能集。对Linux平台有几个关键宏必须正确设置。#define LV_COLOR_DEPTH 32 #define LV_MEM_CUSTOM 1 #define LV_DPI_DEF 130 #define LV_FONT_MONTSERRAT_14 1 #define LV_USE_PERF_MONITOR 1 #define LV_FPS_MONITOR 1LV_COLOR_DEPTH必须和屏幕实际像素格式匹配。如果你的屏幕是RGB888就用32如果是RGB565用16。颜色深度不匹配会导致画面颜色错乱这一点在调试时特别容易让人抓狂。LV_MEM_CUSTOM在Linux平台强烈建议设为1这样LVGL会使用系统标准库的malloc/free来管理内部内存省去手动配置LVGL内部内存池的麻烦。MCU端因为堆空间有限才需要用内部内存池Linux上根本没有这个必要。另外几个宏根据需求打开需要内嵌英文字体就启用对应字号需要中文字体就去lv_font模块里打开LV_FONT_SIMPLIFIED_CHINESE。尺寸控制上如果产品只用少量控件可以关掉不用的扩展组件比如LV_USE_FLEX和LV_USE_GRID如果项目用不到就关闭能省不少内存。2.3 显示驱动实现framebuffer初始化与刷新流程显示适配的核心是让LVGL能把渲染好的像素数据拷贝到屏幕的显存区域。在Linux下无论是fbdev还是DRM/KMS最终逻辑都殊途同归获取一个可写的显存指针然后定义一个flush回调函数LVGL在需要刷新时调用它。先看DRM/KMS模式下如何获取显存指针。关键步骤是打开DRM设备文件通常是/dev/dri/card0然后查询可用的connector和crtc最后通过drmModeAddFB和drmModeSetCrtc设置显示模式。这段代码比较长我简化核心流程int drm_fd open(/dev/dri/card0, O_RDWR); drmModeRes *res drmModeGetResources(drm_fd); // 遍历connector、encoder、crtc找到第一个已连接的connector drmModeConnector *conn drmModeGetConnector(drm_fd, res-connectors[0]); // 挑选匹配当前分辨率的mode drmModeModeInfo mode conn-modes[0]; // 创建framebuffer uint32_t fb_id; int ret drmModeAddFB(drm_fd, mode.hdisplay, mode.vdisplay, 24, 32, stride, (uint32_t)framebuffer_addr, fb_id); // 设置显示模式 drmModeSetCrtc(drm_fd, crtc-crtc_id, fb_id, 0, 0, conn-connector_id, 1, mode);之后用mmap将显存映射到用户空间得到一个void *buf指针。到这里屏幕已经点亮我们可以自由地向这块内存写入像素。LVGL端显示驱动的初始化也很直接。核心是创建一个display对象并绑定flush回调lv_display_t *disp lv_display_create(1024, 600); lv_display_set_flush_cb(disp, flush_cb); lv_display_set_buffers(disp, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_DIRECT);flush_cb是真正的渲染核心函数LVGL会把需要刷新的区域和渲染好的颜色数据传进来我们只需要拷贝到显存并在结束后调用lv_display_flush_ready告诉LVGL这块已经搞定。实现如下static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *color_p) { int w lv_area_get_width(area); int h lv_area_get_height(area); // area-x1, area-y1是刷新区域左上角坐标 for (int y 0; y h; y) { memcpy(fb_base (area-y1 y) * fb_stride area-x1 * bytes_per_pixel, color_p y * w * bytes_per_pixel, w * bytes_per_pixel); } lv_display_flush_ready(disp); }这里有几个坑要注意。第一是行字节数必须对齐很多显示控制器要求每行字节数按照16或32字节对齐代码里要用fb_stride而不是简单的宽乘字节数。第二是颜色格式转换如果LVGL的LV_COLOR_DEPTH是32而屏幕实际是24位或16位需要做像素格式转换这一步最耗CPU后面优化部分会细说。第三是lv_display_flush_ready一定要在数据真正写到显存之后调用否则LVGL认为显存已经可读下一个帧可能直接读旧数据导致闪烁。2.4 输入设备接入触摸屏与按键显示通了以后输入设备是第二个必须处理的环节。嵌入式Linux的触摸屏和按键大多通过输入子系统上报事件用户空间通过/dev/input/eventX读取。LVGL自带的lv_indev框架可以对接键盘、鼠标、触摸屏、编码器等多种输入设备。触摸屏适配时逻辑上要做两件事从evdev读原始触摸坐标然后把这个坐标映射为LVGL的坐标。evdev读数据的核心代码很短int fd open(/dev/input/event1, O_RDONLY); struct input_event ev; while (read(fd, ev, sizeof(ev)) 0) { if (ev.type EV_ABS) { if (ev.code ABS_X) touch_x ev.value; else if (ev.code ABS_Y) touch_y ev.value; } else if (ev.type EV_KEY ev.code BTN_TOUCH) { touch_pressed (ev.value 1); } }拿到坐标以后喂给LVGL的方式有两种。一种是自己解析事件并调用lv_indev_set_state和lv_indev_set_point去更新一个lv_indev另一种是更常见的做法——在LVGL的输入设备read_callback里返回当前的坐标和按键状态。后者能让LVGL内部的事件循环更统一我推荐用这种方式。static void touchpad_read(lv_indev_t *indev, lv_indev_data_t *data) { >scale_x 1024.0 / 4095.0; scale_y 600.0 / 4095.0;如果产品遇到过触摸不准问题之后可以在采样时再叠加校准参数。按键输入方面如果产品只有物理按键没有触摸屏LVGL的LV_INDEV_TYPE_ENCODER可以同时处理按键和旋钮事件。我在项目里做过一版纯按键控制配置一个encoder输入设备把一个GPIO短按映射为LV_EVENT_CLICKED加一个旋转编码器映射为focus切换用户的操控体验完全不输触摸屏。3. 性能优化实战从30帧到60帧的调优记录3.1 渲染缓冲策略与双缓冲实现图形库最影响帧率的往往是渲染路径上几个点——缓冲大小、刷新方式、像素拷贝效率。LVGL在Linux端跑不高帧率很多时候不是LVGL本身慢而是我们的缓冲策略没有用好。LVGL支持三种渲染模式LV_DISPLAY_RENDER_MODE_PARTIAL部分刷新、LV_DISPLAY_RENDER_MODE_DIRECT直接模式、LV_DISPLAY_RENDER_MODE_FULL全屏模式。在Linux平台上如果屏幕不大推荐用DIRECT模式配合双缓冲能有效减少撕裂。我用的是双缓冲方案。在DRM模式下创建两个framebuffer对象LVGL绘制时轮流提交等垂直同步信号到来时切换显示源。这样用户在屏幕上看到的始终是完整的一帧不会出现画面中间断裂的撕裂现象。static lv_display_t *disp; static void *buf1, *buf2; buf1 malloc(1024 * 600 * 4); buf2 malloc(1024 * 600 * 4); disp lv_display_create(1024, 600); lv_display_set_buffers(disp, buf1, buf2, 1024 * 600 * 4, LV_DISPLAY_RENDER_MODE_DIRECT);在flush回调里不是急着memcpy而是用DRM的drmModePageFlip或drmModeSetCrtc切换显示指针到渲染好的buffer。这一招能极大提升流畅度代价是要能守住显存指针的同步逻辑。如果你不想用DRM层面的双缓冲也可以在LVGL层面做双缓冲即上面代码里的buf1和buf2都作为LVGL的绘制目标LVGL内部轮流渲染flush时才拷贝到屏幕。这样也能减少撕裂但多一次内存拷贝会耗掉一些性能适合对代码复杂度比较敏感的团队。3.2 局部刷新与脏矩形原理LVGL渲染不是整屏重画而是只绘制脏矩形——也就是内容发生变化的区域。这跟很多UI框架的思路一样。如果你不理解这个概念可能在flush回调里傻乎乎地每次都整屏memcpy那性能就废了。在flush回调里area参数就是LVGL认为需要更新的脏区域。我一开始的代码是整屏拷贝结果帧率非常低CPU飙到80%。后来改成只拷贝area指定的区域渲染负载立刻降低一个量级。局部刷新还有一个隐藏收益可以配合显示控制器的部分显示功能。比如有些RGB屏支持设置显示窗口partial window只需要把变化区域告诉LCD控制器它就能只刷新那一块这对低速总线接口如SPI屏尤其有效。在RGB屏加DRM方案下虽然没有窗口收益但memcpy的数据量减少了缓存命中率提高了效果同样明显。3.3 显存访问与DMA/硬件加速在嵌入式Linux上显存访问比MCU更复杂因为涉及CPU缓存一致性。很多ARM平台上外部DMA控制器和CPU看到的物理内存视图是同一块内存但CPU写完后数据还在cache里没有真正落到内存。这时候如果显示控制器直接从内存读就会读到旧数据画面变成花屏。解决办法有几种。最简单的是在flush回调完成后调用dma_cache_sync或者msync刷新缓存但这很拖性能。更好的方案是在DRM模式下使用DRM_IOCTL_MODE_MAP_DUMB创建带DMA-BUF能力的buffer并通过DRM_IOCTL_SYNCOBJ或显式的fence机制保证数据就绪后再提交显示这个路径完全绕开了用户空间手动同步的麻烦。如果平台带了2D硬件加速器比如Rockchip的RGA、Allwinner的DE2那还抱着memcpy优化就太浪费了。这类加速器提供了blit和rotate的硬件实现LVGL的flush回调可以改为把数据交给硬件加速器处理。我在RK平台上的实践是使用libdrm提供的drmPrimeHandleToFD拿到DMA-BUF文件描述符直接提交给RGA做色彩格式转换和缩放CPU基本空闲下来帧率从35帧直接跳到60帧。不过硬件加速并不是一上来就要搞的东西。开发阶段先用CPU memcpy把功能调通等确认真有性能瓶颈再上硬件加速否则会平白增加调试复杂度。我的建议是分两步走先软加速跑通再用perf工具测量哪里热点最高最后针对热点做定向优化。3.4 内存占用与CPU占用平衡LVGL在Linux下的内存优化策略和MCU不太一样。MCU要考虑静态内存池限制Linux则可以用系统malloc看起来没有上限但如果界面写得臃肿内存照样会被吃爆。我在项目里做了两件事控制内存一是精简动画资源LVGL的动画其实很耗内存因为它要保存插值计算的中间状态动画多而杂的话内存蹭蹭涨二是对位图素材做了取舍很多图标用字体图标替代而不是存成一张张PNG节省了大量内存。CPU占用方面LVGL的main loop通常是一个while(1)循环里反复调用lv_timer_handler()。这个函数的调用频率直接决定帧率上限。默认刷新周期是33ms也就是30帧左右。如果你的界面动画不多可以把刷新周期调大降低CPU占用如果是展示数据变化频繁的图表可以调小。我这边把LV_DEF_REFR_PERIOD从33调整到20动画流畅度明显提升CPU占用也只增加了3%。LVGL还提供了性能监控功能显示左上角的帧率和CPU占用。开发阶段务必开起来调优时数据说话比凭感觉靠谱得多。4. 移植与优化中的常见问题速查4.1 屏幕闪烁、撕裂如何解决屏幕闪烁大多数情况是因为LVGL绘制时数据直接写到了当前正在显示的显存里。用户看到的是边擦边画的效果视觉上就是闪。撕裂则是屏幕刷新一半时显存内容被替换画面上半帧和下半帧来自不同的渲染帧。这两类问题的通用解法就是双缓冲加垂直同步。在DRM/KMS方案下用drmModePageFlip切换显示buffer并等待VBlank事件可以从机制上确保用户看到的永远是完整的一帧。fbdev方案下需要自己控制两个缓冲区的切换并且尽量在屏幕的防撕裂等待期间完成拷贝逻辑上麻烦不少。我在项目里遇到过一种特殊情况LVGL的flush回调还没执行完显示控制器已经开始扫描扫描线导致屏幕顶部正常、底部闪烁。解决方法是把flush回调里的memcpy拆成上下两半先拷完上半帧再让LVGL继续但这引入了额外复杂度。最后还是切到了DRM的PageFlip方案才彻底解决。4.2 触摸漂移、点击位置不对触摸不准是嵌入式Linux上最常见的输入问题尤其是杂牌触摸屏。表现形式有两种点击位置整体偏移或者屏幕边缘区域点击误差大。第一种问题通常是因为触摸坐标未做缩放匹配。LINUX触摸设备通过ABS_X和ABS_Y上报的通常不是像素坐标而是模数转换值需要根据设备报告的axis范围做比例换算。可以用ioctl(fd, EVIOCGABS(ABS_X), absinfo)拿到轴的范围代码里做映射。如果映射后还是偏那就是触摸屏本身有旋转或者贴合偏差需要通过tslib或者手动校准。第二种边缘误差大的情况往往是触摸屏的触控IC线性度一般四周区域响应不准确。可以在LVGL层面做区域过滤把靠近边缘的坐标做一定的拉伸校正。不过这个属于治标不治本最好还是换好一些的触摸屏模组。4.3 启动卡死、显示异常移植过程中最容易遇到的三类启动问题一是打开/dev/fb0或/dev/dri/card0时提示权限拒绝。这是Linux的ACL权限问题把运行LVGL程序的用户加入video组或者给设备文件加0666权限即可。二是屏幕没有信号黑屏但程序不报错。DELL排查顺序是先确认设备节点存在再确认连接器是connected状态然后用modetest工具测试DRM能否正常出图最后才轮到LVGL。三是LVGL初始化后立即崩溃或死循环。多半是lv_conf.h里定义的颜色深度和显存格式不匹配或者LV_MEM_CUSTOM设置为0导致内部内存池不够用。排查方法是打开LV_USE_LOG观察日志输出到哪一步卡住。4.4 中文字体显示为方块LVGL默认不带中文字体如果你直接用一个自定义字符串显示你好屏幕上是不会出现字形的要么是空白要么是方块。解决方法是让LVGL使用自定义字体有两种路径一种是在代码里加载字体文件比如lv_font_load(path/to/font.bin)这需要先把TTF字体转换成LVGL格式的bin文件转换工具是lv_font_conv。另一种是转换成C数组编译时直接嵌入可执行文件省去文件系统依赖。我常用后者因为很多精简Linux没有完整的文件系统直接编译进固件最稳妥。中文显示还有两个细节一是字体文件通常很大一个完整的中文字库动辄几MB如果只需要常用字可以在转换时指定--range参数只提取需要的字符比如0x4E00-0x9FA5的前三千个常用字体积能缩小到几百KB二是LVGL渲染大字体时内存占用可观建议优先用内置字体实在要自定义再加载外部字体。5. 实践复盘移植优化中的几条个人经验5.1 我踩过的几个值得说的坑第一个坑在双缓冲和DRM切换逻辑上。我一开始参考了一些简化示例在flush_cb里直接切换显存地址没有等VBlank信号结果画面撕裂非常厉害。后来加了线程等待drmWaitVBlank情况好很多但也引入了延迟。最终改为在VBlank事件中提交PageFlip这才算稳定下来。第二个坑是区域坐标转换。LVGL在DIRECT模式下坐标是相对于display左上角的但DRM的framebuffer可能因为对齐策略多了一些边缘填充导致拷贝到显存时坐标总是不对。后来我仔细看DRM的stride参数发现它可能比实际显示宽度大很多于是所有行地址计算都改用stride而不是width * 4问题迎刃而解。第三个坑更隐蔽。在fbdev调试时我发现手动修改一个像素测试显示正常但LVGL刷上来就是花屏。后来查了很多资料才明白有些fb驱动默认是RGB565格式而LVGL按RGB888渲染两者不匹配。这种问题用fbset查一下屏幕depth就能定位但我当时绕了不少弯路。5.2 移植完成后的团队协作经验移植LVGL到Linux不只是底层适配工程师一个人的事UI和应用开发同样需要配合。我发现一个很有效的协作模式底层适配完成后先把LVGL跑在PC模拟器上LVGL官方支持SDL模拟器UI设计师和前端工程师在模拟器里开发界面底层工程师在真机上做性能和稳定性测试。两边通过统一的lv_conf.h和代码仓库同步等UI在模拟器上验收通过后再合并到真机分支做联调。这个方法特别适合团队中有多个开发人员的场景避免了真机资源争抢也加快了UI迭代速度。模拟器模式还能输出日志和异常栈调试起来比真机方便得多。我在实际项目中还发现一个容易被忽视的点LVGL的线程安全问题。由于LVGL 9.x开始支持多线程渲染通过LV_USE_OS配置如果你的业务代码会从别的线程里调用LVGL接口必须加锁保护。我这边选择的是单线程模型所有LVGL调用都集中在主循环里避免了很多竞态问题。业务线程通过队列和信号量与主循环通信虽然代码稍多但稳定性和可排查性非常好。5.3 后续可以继续扩展的方向这次项目做完我给自己留了一个关于LVGL性能优化的long-running任务把更多绘制工作从CPU搬到GPU。虽然平台有2D加速器但目前只是用在了flush阶段的memcpy上LVGL自身的光栅化绘制alpha混合、边框、圆角等仍然由CPU完成。如果能把LVGL的draw接口重定向到GPU的绘制队列整个界面的渲染成本会进一步下降。这个方向官方已经有实验性的GPU加速支持应用在复杂界面时提升幅度很可观。另外一个可扩展的方向是显示内容分层。很多HMI产品其实可以分成背景层、业务层、警告层分别对应DRM的多个plane让硬件完成合成。这样LVGL只需要管业务层警告层可以通过系统级机制直接点亮响应时间能做到很低。这个思路在医疗或工控产品里价值很大我准备在下一个项目里重点验证。5.4 给后来者的三点真诚建议第一不要一上来就想把所有功能都跑起来。先用fbdev的最小demo点亮屏幕再用模拟器跑通UI最后再上DRM和双缓冲。底层适配和界面开发解耦能让团队并行工作整体节奏反而更快。第二lv_conf.h里的宏不是越多越好相反没用的功能模块最好全关掉。LVGL的代码是模块化的哪些宏没有定义编译器就会连对应的代码都不编译。我见过一个团队把所有控件都开着编译出来的库比我这边多了200KB不止内存占用也高了不少。第三做性能优化时一定把perf工具用起来不要凭感觉猜瓶颈。先用top看看CPU占用再用perf top定位具体函数确认是memcpy慢还是LVGL内部绘制慢再决定开不开放硬件加速。我调试过程中有两次以为是显示刷新问题结果却是中断风暴导致系统长时间处理中断与LVGL本身没关系。拿数据说话是最稳妥的调优方式。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →