Zephyr 在 NXP MR-NavQ95B(i.MX95)上的开发实践:异构多核实时固件、外部 Flash 启动与 NETC VSI 以太网共享
2026/9/19 21:26:05 网站建设 项目流程
  • 操作系统
  • 嵌入式
  • RTOS
  • 物联网

【免费下载链接】zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.

项目地址:https://gitcode.com/GitHub_Trending/ze/zephyr
点击查看免费下载

NXP MR-NavQ95B 是面向移动机器人应用的开源开发板,基于 NXP i.MX95 应用处理器,将 Cortex-A55 应用核与 Cortex-M7/M33 实时核集成在同一颗 SoC 中。本文以 boards/nxp/mr_navq95b/doc/index.rst 为主线,结合仓库内板级源码,系统讲解如何在 Zephyr 上为 MR-NavQ95B 的 Cortex-M7 核构建实时固件、从内部 TCM 或外部 Octal SPI NOR Flash 启动运行,以及如何在 M7 上通过 NETC VSI 与 A55 上的 Linux 共享一个物理以太网口。读完本文,你将掌握该板的完整构建、烧录与异构网络配置流程,并理解其板级设备树与启动链路的底层原理。

NXP MR-NavQ95B 开发板:中央为 i.MX95 处理器区域,左侧为千兆以太网接口,右侧带散热模组,底部为各类扩展排针与 USB 接口。

板卡概述与异构多核架构

MR-NavQ95B 是 NXP Robotics 推出的开源移动机器人开发板,面向需要同时承载"高性能应用处理"与"硬实时控制"的机器人场景。其核心价值在于异构多核:i.MX95 把不同实时性、不同算力需求的核放在同一颗芯片上,让开发者可以用一个 SoC 同时跑 Linux(应用/感知/导航)与 Zephyr(电机控制/传感器采集/实时通信)。

处理器与内存资源

  • NXP i.MX95 SoC
    • 6x Arm Cortex-A55 应用核(典型承载 Linux)
    • 1x Arm Cortex-M7 实时核(本文 Zephyr 固件的默认目标)
    • 1x Arm Cortex-M33 实时核(在 NavQ95 镜像中充当系统管理器 System Manager)

内存资源方面:

  • 片上 SRAM:1376 KiB(带 ECC 校验)
  • 外部 LPDDR5:16 GiB(支持 inline ECC 与加密)
  • 外部 Flash:64 MiB Octal SPI NOR

在 Zephyr 中,当前支持聚焦于Cortex-M7 核,它通常是实时固件的目标。这一点在 mr_navq95b_mimx9596_m7.dts 与 mr_navq95b_mimx9596_m7.yaml 中有清晰体现:identifier: mr_navq95b/mimx9596/m7arch: armtoolchain: zephyr/gnuarmemb,支持的子系统包括 uart、i2c、pwm、spi。

板级配置标识

board.yml定义了该板在 Zephyr 构建系统中的身份:

board: name: mr_navq95b full_name: MR-NavQ95B vendor: nxp socs: - name: mimx9596 variants: - name: ddr cpucluster: m7 - name: flash cpucluster: m7

socs.variants可以看出,该板在 M7 簇下提供ddrflash两个变体,对应"在外部 LPDDR5 中运行"和"在外部 Flash 中 XIP 运行"两种固件形态,后文会分别展开。

外部扩展与接口复用

MR-NavQ95B 由一块基板(base board)构成,可叠加可选扩展模块以增加接口与功能,其扩展板与可用外设的总览参见 NXP 提供的官方框图(见index.rst的 References 一节)。需要注意,这些接口是复用的(multiplexed),具体哪个外设可用取决于 i.MX95 平台的板级配置与 pinmux 设置。这一点在板级 pinctrl 文件中体现为按外设分别定义引脚组,例如 mr_navq95b-pinctrl.dtsi 中的lpuart2_defaultflexspi_defaultflexcan2_default等。

串口控制台配置

MR-NavQ95B 的默认串口控制台路由到UART2接口,有两种物理访问途径:

  • 通过 I/O 扩展板(I/O expansion board)上 USB-C 连接器(J10)的 USB-to-UART 桥接访问;
  • 或通过主板上专用的 JST-GH 板级连接器(J2)直接访问 UART2。

板级设备树中对应节点为lpuart2,mr_navq95b_mimx9596_m7.dts 将其配置如下:

&lpuart2 { status = "okay"; current-speed = <115200>; pinctrl-0 = <&lpuart2_default>; pinctrl-names = "default"; };

同时chosen节点把 UART2 同时指定为控制台与 shell 串口:

zephyr,console = &lpuart2; zephyr,shell-uart = &lpuart2;

即默认波特率为115200,连接 J10 或 J2 后即可看到 Zephyr 的 shell 与日志输出。设备树中还启用了lpuart5(同样 115200),供其他用途使用。

构建与运行 Hello World

运行形态总览

该板支持两种固件运行形态,构建目标名直接区分:

构建目标固件位置说明
mr_navq95b/mimx9596/m7ITCM(片上紧耦合内存)最小化起步,直接由调试器加载运行
mr_navq95b/mimx9596/m7/flashMX25UM51345G 外部 Octal SPI NOR配合 MCUboot 由外部 Flash XIP 执行

在 ITCM 上构建

west build -b mr_navq95b/mimx9596/m7 samples/hello_world/

默认(非 flash 变体)的设备树在chosen中把固件放在 TCM 上运行:

chosen { /* TCM */ zephyr,flash = &itcm; zephyr,sram = &dtcm; zephyr,flash-controller = &ext_flash_ctrl; zephyr,console = &lpuart2; zephyr,shell-uart = &lpuart2; zephyr,canbus = &flexcan2; };

即代码段放在 ITCM(zephyr,flash),数据段放在 DTCM(zephyr,sram),同时声明了 FlexSPI 外部 Flash 控制器与默认 CAN 总线(flexcan2)。配套的 mr_navq95b_mimx9596_m7_defconfig 启用CONFIG_XIP=y、串口控制台、GPIO,以及通过 SCMI 向 M33 系统管理器请求时钟的CONFIG_ARM_SCMI=yCONFIG_ARM_SCMI_NXP_VENDOR_EXTENSIONS=y,另外针对 FlexSPI 强制使用 OVRDVAL(CONFIG_FLASH_MCUX_FLEXSPI_FORCE_USING_OVRDVAL=yCONFIG_FLASH_MCUX_FLEXSPI_OVRDVAL=27)。

从外部 Flash 构建

west build -b mr_navq95b/mimx9596/m7/flash samples/hello_world/

Flash 变体在 mr_navq95b_mimx9596_m7_flash.dts 中覆盖chosen节点,把代码分区指向外部 NOR Flash 中的 slot0:

/ { model = "NXP MR-NavQ95B NOR flash variant"; chosen { zephyr,flash = &mx25um51345g; zephyr,itcm = &itcm; zephyr,code-partition = &slot0_partition; }; };

同时其 defconfig 启用 MCUboot 支持:CONFIG_BOOTLOADER_MCUBOOT=yCONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE=y,并继续保留CONFIG_XIP=y(从 Flash 直接执行)。

上传固件

固件上传可通过连接 J7 端口的 Segger/J-Link 探针完成:

west flash

board.cmake 根据目标变体为 runner 配置了不同参数:

  • flash 变体:pyocd 目标为--target=mimx95_cm7_mx25um、频率--frequency=20M,并根据zephyr,code-partitionCONFIG_ROM_START_OFFSET计算 VTOR 后以--flash-opt=-O vtor=<addr>传入;J-Link 使用--device=cortex-m7
  • 默认(TCM)变体:pyocd 目标为--target=mimx95_cm7,J-Link 同样使用--device=cortex-m7
关于 PyOCD 目标支持的重要说明

注意:要将固件烧写到外部 Flash,需要 PyOCD 支持mimx95_cm7_mx25um目标。截至文档编写时,该支持尚未合入主线 PyOCD,需按以下步骤手动获取:

  1. 安装 pyocd,用于通过板载 JTAG 设备烧写镜像;

  2. 将 pyocd 克隆到任意目录,并检出pr-imx95分支:

    git clone https://github.com/NXP-Robotics/pyOCD -b pr-imx95
  3. 构建安装 pyocd:

    cd pyocd-private python3 -m pip install .

推荐的整体运行方式:SD 卡镜像 + MCUboot

官方建议在 SD 卡上安装 NavQ95 镜像(构建与烧录说明参见 NXP 的imx-manifest-navq95)。该镜像会在启动时初始化 M33 与 A55 核,并让 M7 在启动时运行 MCUboot,从而从外部 Flash 运行 Zephyr 固件。从外部 Flash 运行时,标准启动流程为:

  1. 系统管理器(Cortex-M33)初始化系统;
  2. MCUboot被加载到 TCM;
  3. MCUboot 校验外部 Flash 中的固件;
  4. 固件从 Flash直接执行(XIP)

这一流程与 Flash 变体的设备树/defconfig 一一对应:zephyr,code-partition = &slot0_partition指向 MCUboot 管理的镜像槽位,CONFIG_BOOTLOADER_MCUBOOT=y让构建产物可被 MCUboot 签名/校验,CONFIG_XIP=y保证固件就地执行。

Flash 分区布局

Flash 变体所依赖的 MX25UM51345G 分区定义在 mr_navq95b_mimx9596_m7.dts 中:

分区标签地址偏移大小
boot_partitionmcuboot0x00000000128 KiB
slot0_partitionimage-00x000200007 MiB
slot1_partitionimage-10x007200007 MiB
storage_partitionstorage0x00e200002 MiB - 128 KiB

分区注释强调:分区大小必须与 Flash 扇区大小(4 KiB)对齐。此外,FlexSPI 控制器节点(nxp,imx-flexspi-mx25um51345g)配置了 120 MHz SPI 时钟、64 MiB 映射范围0x28000000以及 AHB 预取/缓存等优化项(ahb-prefetchahb-read-addr-optahb-bufferableahb-cacheable),为 XIP 执行提供硬件基础。

DDR 变体

除默认 TCM 与 Flash 两种形态外,mr_navq95b_mimx9596_m7_ddr.dts 还提供了DDR 变体:它删除zephyr,flash属性,并把zephyr,sram指向外部 LPDDR5 中 4 MiB 的映射窗口:

chosen { zephyr,sram = &ddr; /delete-property/ zephyr,flash; }; ddr: memory@80000000 { device_type = "memory"; reg = <0x80000000 DT_SIZE_M(4)>; };

对应 defconfig 中CONFIG_XIP=n(固件加载到内存中执行,而非 XIP)。该变体适合需要更大 RAM 内存空间的实验性场景。

Ethernet:在 Linux 旁运行 NETC VSI

共享同一物理网口的架构

i.MX95 的 NETC(ENETC)以太网控制器由 A55 上的Linux与 M7 上的Zephyr 共享

  • Linux通过 Physical Station Interface(PSI)拥有物理端口与 PHY,对应网络接口end0
  • Zephyr(M7)使用 Virtual Station Interface(VSI)——即同一控制器的虚拟功能(VF):enetc0_vsi1(ENETC0 VF1),通过该共享端口收发数据。

关键约束与分工:

  • VF 从属于 PF(Physical Function),因此 Linux 必须先创建 VF 并将其移交给 M7,M7 才能使用它;
  • M7 驱动从不触碰 PHY 或 PF,它只启动自己的 station interface,并通过 NETC VSI-to-PSI 消息通道请求 PSI 设置其 MAC 过滤。

这些约束在板级设备树中有明确体现。在 mr_navq95b_mimx9596_m7.dts 中:

/* * The NETC block controller (IERB/NETCMIX/PRB) and the ENETC PSIs are owned by * Linux on the Cortex-A55. The M7 only drives ENETC0 VF1 as a VSI, talking to * the Linux PSI over the VSI-to-PSI message channel. */ &netc_blk_ctrl { status = "disabled"; }; &enetc0_vsi1 { zephyr,random-mac-address; zephyr,mac-address-prefix = [00 04 9f]; status = "okay"; }; &enetc2_vsi1 { zephyr,random-mac-address; zephyr,mac-address-prefix = [00 04 9f]; status = "okay"; };

NETC 块控制器(IERB/NETCMIX/PRB)与 ENETC PSI 归 A55 上的 Linux 所有,因此被disabled;M7 仅驱动enetc0_vsi1(以及预留的enetc2_vsi1)作为 VSI,两者都使用00:04:9f前缀的随机 MAC 地址。

Linux 设备树:无需 M7 相关改动

Linux 设备树中不需要任何 M7 相关的修改。默认的 NavQ95 Linux 镜像(见 NXPimx-manifest-navq95)已经启用了 ENETC0 PF 作为带 SR-IOV 支持的end0——这就是全部所需。VF 本身是在运行时动态创建的,而不是在设备树中静态描述。

在 Linux 侧启动 VF

在 A55 上以 root 身份、Linux 启动后执行一次以下步骤(其中end0是移交给 M7 作为 VF1 的 ENETC0 PF):

# 关闭 Linux 的 VF 驱动对 VF 的探测,让 M7 独占 VF,然后创建 VF0+VF1。 echo 0 > /sys/class/net/end0/device/sriov_drivers_autoprobe echo 2 > /sys/class/net/end0/device/sriov_numvfs # 解析 VF1 的 PCI 地址,使其能够 DMA 并触发 MSI-X 中断。 vf=$(basename "$(readlink -f /sys/class/net/end0/device/virtfn1)") setpci -s "$vf" COMMAND=0x0006 # Bus Master Enable setpci -s "$vf" CAP_MSIX+2.w=0x8000:0x8000 # 信任该 VF,使 PSI 响应 M7 驱动发出的 MAC 过滤请求。 ip link set end0 vf 1 trust on

各命令的作用:

  • sriov_drivers_autoprobe=0:先阻止 Linux 自带 VF 驱动自动绑定 VF,避免抢占;
  • sriov_numvfs=2:创建 VF0 与 VF1,其中 VF1 被 M7 使用;
  • setpci ... COMMAND=0x0006:使能 VF 的 Bus Master,允许其发起 DMA;
  • setpci ... CAP_MSIX+2.w=0x8000:0x8000:使能 MSI-X 功能,允许 VF 触发中断;
  • ip link set end0 vf 1 trust on:将 VF1 标记为受信任,PSI 才会接受 M7 驱动设置的 MAC 过滤。

完成上述步骤后,M7 的 VSI 驱动会检测到 VF 已启用,并通过end0接入网络。

提示:NavQ95 BSP(见imx-manifest-navq95)自带一个enetc-vsi-handoff-mcore服务,会在开机时自动执行这些步骤,因此通常无需手动操作。这里展示手动流程是为了自定义场景(custom setups)的参考。

板级构建系统的支撑细节

Kconfig 结构

Kconfig.mr_navq95b 将三个构建目标统一映射到同一 SoC 型号:

config BOARD_MR_NAVQ95B select SOC_MIMX9596_M7 if BOARD_MR_NAVQ95B_MIMX9596_M7 || \ BOARD_MR_NAVQ95B_MIMX9596_M7_DDR || \ BOARD_MR_NAVQ95B_MIMX9596_M7_FLASH select SOC_PART_NUMBER_MIMX9596AVZXN

板级默认外设

板级设备树除串口与网络外,还启用了丰富的机器人常用外设,可作为实际应用的参考起点:

  • SPI 传感器lpspi1上的 InvenSense ICM-45686 六轴 IMU(加速度计 ±2g、陀螺仪 ±4000dps,ODR 400Hz,FIFO watermark=1);lpspi8上的 Bosch BMI088 加速度计与陀螺仪;
  • I3Ci3c1以 400 kHz I2C 模式挂载 Bosch BMP581 气压计与 BMM350 磁力计;
  • CANflexcan2(默认 CAN 总线)与flexcan3
  • PWMtpm3/tpm4/tpm5提供多路 PWM(可驱动电机或舵机);
  • GPIOgpio2gpio5使能并配置中断输出选择;
  • 定时器tstmr2启用。

这些节点与index.rst中"接口复用、取决于板级配置与 pinmux"的描述一致,开发者可以在 mr_navq95b-pinctrl.dtsi 中查看每个外设对应的引脚组定义。

常见问题与排查要点

  1. west flash在 flash 变体上报 PyOCD 目标不支持:说明本地 PyOCD 缺少mimx95_cm7_mx25um目标,需按上文步骤安装 NXP-Roboticspr-imx95分支的 pyocd。
  2. M7 以太网不工作:先确认 A55 侧已完成 VF 创建与移交(sriov_numvfs、Bus Master、MSI-X、trust on),并确认end0已 up;M7 驱动不会接触 PHY,因此 PHY 状态由 Linux 负责。
  3. 固件不启动或复位循环:检查是否安装了 NavQ95 SD 卡镜像以初始化 M33 系统管理器与时钟(SCMI),M7 的时钟与系统初始化依赖 M33。
  4. 分区大小修改:Flash 中的分区必须与 4 KiB 扇区对齐,修改partitions时注意reg的偏移与大小保持对齐。

参考

  • NXP MR-NAVQ95 板卡仓库(硬件原理图、框图等)
  • NXP imx-manifest-navq95(SD 卡镜像构建与烧录说明、NavQ95 BSP)
  • MR-NavQ95B 扩展板与外设总览框图

相关仓库路径速览:

  • 板级文档:boards/nxp/mr_navq95b/doc/index.rst
  • 板级设备树:mr_navq95b_mimx9596_m7.dts
  • Flash 变体:mr_navq95b_mimx9596_m7_flash.dts 与 mr_navq95b_mimx9596_m7_flash_defconfig
  • DDR 变体:mr_navq95b_mimx9596_m7_ddr.dts
  • Runner 配置:board.cmake
  • 引脚复用:mr_navq95b-pinctrl.dtsi
  • 操作系统
  • 嵌入式
  • RTOS
  • 物联网

【免费下载链接】zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.

项目地址:https://gitcode.com/GitHub_Trending/ze/zephyr
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询