这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【Zephyr|MCXA366】LVGL移植实战分享:FRDM-MCXA366+

共1条 1/1 1 跳转至

【Zephyr|MCXA366】LVGL移植实战分享:FRDM-MCXA366+LCD-PAR-S035(Zephyr4.4)

高工
2026-08-28 18:28:41     打赏
LVGL 移植实战分享:FRDM-MCXA366 + LCD-PAR-S035(Zephyr 4.4)

平台:Zephyr 4.4.0 + zephyr-sdk-1.0.1,板卡 FRDM-MCXA366(MCX A366, Cortex-M33 @ 180 MHz,1 MB Flash,240 KiB 可用 RAM) 屏幕:NXP LCD-PAR-S035(3.5" 480×320,ST7796S 主控 + GT911 电容触摸,8080 并口) 本文重点:prj.conf 逐条解读LCD-PAR-S035 的匹配(适配)分析

ui_layout.png

1. 移植成果一览

  • LVGL 9.5 正常显示,全屏 DMA 刷新 ~15 ms,单帧渲染 3~4 ms,表盘动画流畅(33 FPS);

  • GT911 触摸开箱即用,坐标方向与画面一致,按钮响应正常;

  • 应用侧没有一行显示/触摸初始化代码——全部由 shield + devicetree + Zephyr LVGL 胶水层自动接好;

  • 代价:板级 dts 增加 3 个 nodelabel 节点,FlexIO LCD 驱动修复 3 个 eDMA V4 缺陷。

LVGL 显示/触摸数据链路lvgl_port_stack.png

整条链路分六层:应用只跟 LVGL API 打交道;LVGL 渲染后通过 Zephyr 胶水层的 flush 回调走 display_write();DISPLAY 子系统按 chosen: zephyr,display 找到 ST7796S 节点;底层 mipi_dbi_nxp_flexio_lcdif 驱动把像素经 FlexIO0 的 16 位并口

  • eDMA 推给屏幕。触摸方向相反:GT911 中断 → INPUT 子系统 → 胶水层自动创建的 lv_indev(含坐标旋转变换)→ LVGL 控件事件。

2. prj.conf 逐条解读

prj.conf 是整个工程的"总开关",按功能分五组(完整文件见仓库根目录):

prj.conf 配置分组lvgl_port_prjconf.png

2.1 外设驱动组

CONFIG_GPIO=y
CONFIG_PWM=y                 # eFlexPWM via drivers/pwm/pwm_mcux.c (nxp,imx-pwm)
CONFIG_I2C=y                 # LPI2C1 -> AS5600, LPI2C3 -> GT911 touch
CONFIG_ADC=y                 # LPADC1 -> Vbus

CONFIG_DISPLAY=y
CONFIG_INPUT=y
CONFIG_INPUT_GT911=y
  • CONFIG_DISPLAY=y / CONFIG_INPUT=y 是 LVGL 胶水层挂接显示和触摸的前提; 真正的屏幕驱动(ST7796S、MIPI-DBI、FlexIO、eDMA)由 devicetree 节点的 status = "okay" 和依赖关系自动带入,不需要手写。

  • CONFIG_INPUT_GT911=y:GT911 在 DT_HAS_GOODIX_GT911_ENABLED 时本来就会 default y,显式写出只是为了可读性——读 prj.conf 就知道触摸用的是哪颗料。

2.2 浮点 FPU 组(本工程最大的坑)

CONFIG_FPU=y
CONFIG_FPU_SHARING=y
CONFIG_CBPRINTF_FP_SUPPORT=y # printk %f (called from the control thread only)
  • FOC 算法要求硬浮点;CONFIG_FPU_SHARING=y 的语义是:只有创建时声明了 K_FP_REGS 的线程才允许执行浮点指令,否则直接 Usage Fault。

  • 这条对 LVGL 移植有直接影响:LVGL 9 内部大量使用 float(例如 lv_scale 画表针要算三角函数),所以 LVGL 必须跑在带 K_FP_REGS 的专用线程里: K_THREAD_DEFINE(ui_tid, 8192, ui_thread, NULL, NULL, NULL, 6, K_FP_REGS, 0) (见 src/main.c:53)。

  • Shell 线程没有 FPU 上下文,凡是涉及浮点参数的命令(motor tune 等)都采用 "延迟执行"模式:Shell 只保存字符串,由控制线程代为解析执行。

  • CONFIG_CBPRINTF_FP_SUPPORT=yprintk("%f") 可用,但只从有 FPU 权限的 控制线程调用。

2.3 Shell 组(调试通道)

CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_SHELL_PROMPT_UART="motor> "
CONFIG_SHELL_VT100_COMMANDS=y
CONFIG_SHELL_TAB_AUTOCOMPLETION=y

串口 115200 上的交互式命令行(motor calib/open/vel/pos/stop/clear/status/ print/tune),和触摸 UI 并行使用,方便调试与自动化测试。

2.4 LVGL 组

CONFIG_LVGL=y
CONFIG_LV_Z_MEM_POOL_SIZE=65536
CONFIG_LV_FONT_MONTSERRAT_12=y
CONFIG_LV_FONT_MONTSERRAT_14=y
CONFIG_LV_FONT_MONTSERRAT_16=y
CONFIG_LV_FONT_MONTSERRAT_18=y
CONFIG_LV_FONT_MONTSERRAT_20=y
CONFIG_LV_FONT_MONTSERRAT_28=y
CONFIG_LV_FONT_MONTSERRAT_36=y
CONFIG_LV_USE_SCALE=y        # lv_scale gauge (replaces LVGL v8 lv_meter)

CONFIG_LV_USE_SYSMON=y
CONFIG_LV_USE_PERF_MONITOR=y

逐条说明:

配置取值理由
CONFIG_LVGL=y启用 LVGL 模块和 Zephyr 胶水层(display/input 自动绑定)
CONFIG_LV_Z_MEM_POOL_SIZE=65536LVGL 堆 64 KB。480×320 界面 + 7 档抗锯齿字体,默认值不够用;64 KB 实测充裕
CONFIG_LV_FONT_MONTSERRAT_*Montserrat 每个字号独立编译进 Flash,按需开。界面用到 7 个字号就开 7 个。注意内置字体无中文字形,界面文字需用英文,要中文得用 LVGL font converter 导字库
CONFIG_LV_USE_SCALE=yLVGL 9 迁移要点:v8 的 lv_meter 被删除,表盘必须用 lv_scale(刻度 + section 弧 + 线条指针)自行拼装,不开此项 lv_scale 不编译
CONFIG_LV_USE_SYSMON=y + CONFIG_LV_USE_PERF_MONITOR=y左下角 FPS/CPU 监视窗,移植阶段验证刷新性能非常直观,量产可关

2.5 系统杂项组

CONFIG_MAIN_STACK_SIZE=4096
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3

UI 线程栈(8 KB)是在 K_THREAD_DEFINE 里指定的,这里的 MAIN_STACK_SIZE 只服务 main() 本身(只做 motor_foc_init(),4 KB 足够)。

3. LCD-PAR-S035 匹配分析

这是移植的核心工作量所在。结论先行:Zephyr 上游有 lcd_par_s035 shield, 但官方从未适配 frdm_mcxa366,需要补齐板级 dts 的"契约节点",并修复驱动在 eDMA V4 平台上的三个既有缺陷。

3.1 shield 机制与 overlay 处理顺序

构建命令 west build -b frdm_mcxa366 --shield lcd_par_s035_8080 ... 会把 zephyr/boards/shields/lcd_par_s035/lcd_par_s035_8080.overlay 叠加进设备树。 关键时序:shield overlay 先于应用 overlay 处理

设备树匹配链lcd_s035_dt_chain.png

shield overlay 里写的是 &zephyr_mipi_dbi_parallel { ... } 这样的引用 它假定板级 dts 已经提供三个约定俗成的 nodelabel:

nodelabel内容定义位置
nxp_lcd_8080_connectorJ8 排针 gpio-map(pin9=触摸 INT,pin10=背光,pin11=复位)frdm_mcxa366.dts
zephyr_mipi_dbi_parallelnxp,mipi-dbi-flexio-lcdif,16 位总线、eDMA ch0 请求 71frdm_mcxa366.dts
nxp_8080_touch_panel_i2c挂在 lpi2c3(GT911,P3_27/P3_28 是板级默认 pinmux)frdm_mcxa366.dts

FRDM-MCXA366 的板级文件原本一个都没有——这正是官方没适配这块板的原因。 如果把它们写在应用 overlay 里,shield 展开时 label 尚不存在,编译直接报 undefined node label。所以三个节点必须加在 Zephyr 树的板级 dts 中(同家族 frdm_mcxa156 可当模板),配套 pinctrl 加在 frdm_mcxa366-pinctrl.dtsi pinmux_flexio_lcd:16 根数据线 + WR/RD + CS/RS/RST/背光)。

应用 overlay(boards/frdm_mcxa366.overlay)因此只剩一件屏幕相关的事: 背光 gpio-hog,上电即点亮:

&gpio4 {
lcd_backlight_hog: lcd-backlight-hog {
 gpio-hog;
 gpios = <4 GPIO_ACTIVE_HIGH>;
 output-high;
};
};

3.2 引脚与外设匹配

屏幕直插 J8 排针,信号与 MCU 资源的对应关系(与 UM12438 Table 17 一致):

引脚匹配lcd_s035_pinmap.png

匹配设计上有几个值得注意的点:

  • 数据/选通全在 FlexIO0 上:16 根数据线映射到 FlexIO0 D16..D31,WR/RD 用 D7/D8,由 FlexIO 的 shifter+timer 拼出标准 8080 时序,CPU 完全不参与位翻转。

  • CS/RS/RST/背光是普通 GPIO,由 MIPI-DBI 层和 gpio-hog 管理。

  • 触摸 INT(P2_24)不需要 pinctrl:MCXA 引脚复位默认 mux 即 GPIO。

  • eDMA 通道 0、请求源 71(FlexIO0 shifter0,编号来自 NXP HAL 的 PERI_DMA.h)。

  • MCXA366 的 FlexIO0 只有 4 个 shifter(PARAM=0x04200404), shifters-count 必须配 <4>;照抄其他板子配 8 会在初始化报 -ENOBUFS

  • 与电机引脚零冲突:电机用 P3_1/9/11/22/30/31 + P1_0/1,屏幕全部信号 一个不沾;GT911(LPI2C3)和 AS5600(LPI2C1)也不在同一总线。

3.3 显示链路:ST7796S over FlexIO + eDMA

shield overlay 基于 zephyr_mipi_dbi_parallel 创建 ST7796S 节点并设置 chosen { zephyr,display = &st7796s; }。板级 dts 侧的总线节点核心属性:

flexio0_lcd: zephyr_mipi_dbi_parallel {
compatible = "nxp,mipi-dbi-flexio-lcdif";
data-pin-start = <16>;      /* FlexIO0 D16..D31 = 16 根数据线 */
enwr-pin = <7>;             /* WR = FlexIO0 D7 */
rd-pin = <8>;               /* RD = FlexIO0 D8 */
shifters-count = <4>;       /* MCXA366 FlexIO0 只有 4 个 shifter */
timers-count = <1>;
dmas = <&edma0 0 71>;       /* ch0, 请求源 71 = FlexIO0 shifter0 */
...
};

驱动(mipi_dbi_nxp_flexio_lcdif)工作方式:4 个 shifter 级联成 16 字节 缓冲链,timer 生成 WR 时序,每根线 10 MHz × 16 位;像素由 eDMA 从帧缓冲 搬进 shifter,理论速度全屏 ~15 ms。

3.4 触摸链路:GT911 五步使能(应用零代码)

  1. shield overlay 自带 GT911 节点(lpi2c3 @ 0x5D,swapped-x-y + inverted-x),并设好 chosen { zephyr,touch }

  2. lpi2c3 的 pinmux(SCL=P3_27、SDA=P3_28)和时钟是板级默认,status = "okay" 即生效;

  3. prj.conf 显式加 CONFIG_INPUT_GT911=y

  4. LVGL 指针输入由 LV_Z_POINTER_FROM_CHOSEN_TOUCH 自动创建并绑定到 zephyr,display,坐标旋转/翻转映射一并完成;

  5. shield.c 的 lcd_par_s035_init()(POST_KERNEL)先把 INT 拉低再初始化 GT911,完成 0x5D 地址选择——GT911 节点没接 reset-gpios,靠上电状态 + INT 拉低选中地址,实测工作正常。

3.5 驱动层三个缺陷与修复(eDMA V4)

调试中发现 nxp,mipi-dbi-flexio-lcdif 驱动在 eDMA V4(MCXA,无 DMAMUX) 平台上的三个既有缺陷,修复文件: zephyr/drivers/mipi_dbi/mipi_dbi_nxp_flexio_lcdif.c

三个驱动缺陷与修复lcd_s035_dma_fixes.png

  1. DMA 方向错误(现象:顶部一条彩带 + 全屏噪点):驱动声明 MEMORY_TO_MEMORY,eDMA V4 把整行 960 B 压成单个 burst 灌入,FlexIO 只有  4 shifter(16 B 缓冲),排空前数据即被覆写,每行仅 ~8 像素到达屏幕。  修复:channel_direction 改为 MEMORY_TO_PERIPHERAL,由 shifter 空请求  按 16 B minor loop pacing。

  2. DOFF 被清零(现象:传输死锁):Zephyr DMA API 约定 M2P 外设侧地址不 递增(TCD DOFF=0),但目标是 SHIFTBUF0..3 四个寄存器,必须 16 B 取模循环  寻址。修复:dma_config() 后恢复 TCD_DOFF = sizeof(uint32_t)

  3. WFI 下请求停摆(现象:每块写屏 ~950 ms):eDMA V4 的 FlexIO 请求 pacing 在 CPU 进 idle(WFI)时基本停摆(~4k loops/s),忙等时跑满  ~1.4M loops/s;EARQ 位无效,疑似平台级怪癖(NXP 官方 SDK 在此芯片上也用  SmartDMA 而非 eDMA 推 LCD)。修复(workaround):忙等 DMA 完成回调,不再  k_sem_take 睡眠。代价是刷屏期 CPU 被占(全屏上限 ~15 ms)。

同平台的 FRDM-MCXA156 大概率存在同样问题,这三处修复值得上游化。

3.6 性能与资源占用(实测)

指标数值
编译体积FLASH 487 KB(46%),RAM 163 KB(66%,含 LVGL 64 KB 内存池)
裸屏色带测试480×64×5 块,每块 3 ms,全屏 ~15 ms(总线理论速度)
LVGL 单帧渲染3~4 ms(性能监视窗显示 33 FPS)
UI 线程30 ms 心跳,8 KB 栈,prio 6,K_FP_REGS

4. LVGL 8 → 9 迁移要点

从 LVGL v8 代码迁移时踩到的三个点:

  • lv_meter 没了:表盘用 lv_scale 重建——刻度尺(31 格 / 270° 扫角)

    • 一个 section 弧(目标转速)+ 一根 lv_line 指针(实际转速),刷新就是 lv_scale_set_line_needle_value() + lv_scale_set_section_range() 两行 (实现见 src/motor_demo_ui.c)。

  • 线程模型lv_timer_handler() 30 ms 周期调用,配合脏区域局部刷新; LVGL API 只能在 UI 线程调用,其他线程想刷新界面就写共享整型变量,由 UI 线程的定时器读取重绘。

  • FPU 权限:见 2.2 节——CONFIG_FPU_SHARING 下 UI 线程必须带 K_FP_REGS,这是带屏工程相对裸机工程最容易漏的一项。

5. 常见坑速查

症状原因对策
编译报 undefined node label三个契约 nodelabel 写在了应用 overlay挪到板级 frdm_mcxa366.dts
初始化报 -ENOBUFSshifters-count 配了 8MCXA366 FlexIO0 只有 4 个 shifter,配 <4>
画面顶部彩带 + 噪点DMA 方向 M2M驱动改 MEMORY_TO_PERIPHERAL(3.5 节问题 1)
写屏死锁TCD DOFF=0恢复 DOFF=4(问题 2)
刷新 ~1 秒一块WFI 下 eDMA 停摆忙等完成回调(问题 3)
Usage Fault(一进 LVGL 就崩)UI 线程没声明 K_FP_REGSK_THREAD_DEFINE(..., K_FP_REGS, 0)
中文显示为方框Montserrat 无中文字形界面改英文,或 font converter 导中文字库
west flash 报 No matching devices板载调试器固件非 linkserver本板 MCU-Link 已刷 J-Link 固件,用 west flash -r jlink

6. 构建与验证

west build -b frdm_mcxa366 --shield lcd_par_s035_8080 -p always . -d build
west flash -r jlink

验证路径:上电背光即亮 → LVGL demo 界面出现(左下角性能窗看 FPS)→ 触摸按钮计数正常 → 触摸/串口两条通道都能控制电机。

7. 参考来源

  • 引脚映射:NXP MCUXpresso SDK frdmmcxa366 display 例程 smartdma_camera_flexio_mculcdlvgl_examples)+ UM12438 Table 17

  • DMA 请求源:modules/hal/nxp periph2/PERI_DMA.h kDma0RequestMuxFlexIO0ShiftRegister0Request = 71

  • Zephyr shield:zephyr/boards/shields/lcd_par_s035/

  • 同家族参考实现:zephyr/boards/nxp/frdm_mcxa156/






关键词: Zephyr          FRDM-MCXA366     LCD-    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]