IMX93 运行NPU demo,解决1G内存下的运行问题

前言

IMX93在2G内存情况下NPU是正常的,在1G的情况下就会推理超时,然后卡住。解决下这个问题以及记录下NPU的操作步骤。使用的是NXP yocto自带的NPU demo。

步骤

我是 6.6.36_2.1.0 的yocto release版本,主要参考L6.6.36_2.1.0-DOCS.zip里面的UG10166_i.MX_Machine_Learning_User's_Guide.pdf文档。

如何下载可以参考我写的 https://www.cnblogs.com/allalonewithyou/p/23223977

先说IMX93 的 2G内存 正常情况,把步骤说清楚:

1. 转化模型

cd /usr/bin/tensorflow-lite-2.16.2/examples

alt text

要用Dedicated_Sram模式:

vela --accelerator-config ethos-u65-256 --system-config Ethos_U65_High_End --memory-mode Dedicated_Sram --config /usr/lib/python3.12/site-packages/ethosu/config_files/Arm/vela.ini mobilenet_v1_1.0_224_quant.tflite

可以使用默认的配置,命令简化:

# 把CPU的模型转为NPU可以运行的模型
vela mobilenet_v1_1.0_224_quant.tflite

会输出到output文件夹下。

2. 运行

# ethosu delegate + vela 模型
./label_image -m output/mobilenet_v1_1.0_224_quant_vela.tflite \
    -i grace_hopper.bmp -l labels.txt \
    --external_delegate_path=/usr/lib/libethosu_delegate.so

对比

识别demo的图片,类型是军装。

alt text

CPU 推理:

cd /usr/bin/tensorflow-lite-2.16.2/examples
./label_image -m mobilenet_v1_1.0_224_quant.tflite -i grace_hopper.bmp -l labels.txt

alt text

NPU 推理:

alt text

127ms 对 3.7ms ,30倍的速度

测试模型

# 测试模型
./benchmark_model --graph=mobilenet_v1_1.0_224_quant.tflite

1G的情况

内存保留配置之前是官方写的:

alt text

现在改为:

-               ethosu_mem: ethosu_region@C0000000 {
+               /*
+                * 必须落在 M33/NPU 的 Non-Secure DRAM 段内(i.MX93 RM "M33 memory map"):
+                *   NS : 0x8000_0000-0x8FFF_FFFF / 0xA000_0000-0xAFFF_FFFF / 0xC000_0000-0xCFFF_FFFF
+                *   S别名: 0x9000_0000 / 0xB000_0000 / 0xD000_0000  ← 绝不能用
+                * A55 视角里 0xB000_0000 只是普通 DRAM,但在 M33/NPU 视角它是第 2 段(0xA000_0000)的
+                * Secure 别名 ⇒ 固件按该地址取命令流/权重会读到别的物理内存或被拒 ⇒ 推理失败。
+                * 原值 0xB0000000 就是踩了这个坑(1G 板必失败;2G 板换该 DTB 同样失败,已实测)。
+                * 这里取第 1 段 NS 内的 0x88000000(2MB 对齐、避开内核 0x80410000-0x8300d000),1G/2G 通用。
+                */
+               ethosu_mem: ethosu_region@88000000 {
                        compatible = "shared-dma-pool";
                        reusable;
-                       reg = <0x0 0xB0000000 0x0 0x8000000>;
+                       reg = <0x0 0x88000000 0x0 0x8000000>;
                };

发现是内存大小的问题,是通过对比发现的,使用相同的1G的保留内存的设备树配置到2G的板子上,运行NPU也不行,就说明是这个设备树配置的问题。

看IMX93的RM手册中system memory map:

alt text

NS/S 只是 TrustZone 视图,且只有 0x8000_0000 以下才有 NS/S 别名,所以 DRAM 段全是 (NS) —— 和 NPU 的问题无关。

看IMX93的RM手册,M33部分的system memory map:

alt text

上面代码注释部分写的很清楚。

参考

https://community.nxp.com/t5/i-MX-Processors-Knowledge-Base/Config-Tool-Introduction-and-Use/ta-p/1986035

https://github.com/nxp-imx/ethos-u-firmware/tree/lf-6.6.36_2.1.0

IMX93RM.pdf

额外

调试记录

libtensorflow-lite + libethosu* + libethosu_delegate.so + ethosu_firmware 是必须兼容的,同一个yocto release里面即可。

root@imx93-11x11-lpddr4x-evk:/usr/bin/tensorflow-lite-2.16.2/examples# strings output/mobilenet_v1_1.0_224_quant_vela.tflite | grep -iE "ethos-u|vela|OfflineMemory"
OfflineMemoryAllocation
vela_version
Vela 3.12.0 Optimised
ethos-u

固件位置:

https://github.com/nxp-imx/ethos-u-firmware/tree/lf-6.6.36_2.1.0

相关的APP可以下载源码编译,查看UG10166_i.MX_Machine_Learning_User's_Guide.pdf文档:

alt text

# 开启关闭ethos
echo start > /sys/class/remoteproc/remoteproc0/state
echo stop > /sys/class/remoteproc/remoteproc0/state

保留内存:

# 查看保留内存
ls /sys/firmware/devicetree/base/reserved-memory/ 2>/dev/null || ls /proc/device-tree/reserved-memory/
# 查看寄存器  注意是小端的
od -An -tx4 /sys/firmware/devicetree/base/reserved-memory/rsc-table@2021e000/reg 2>/dev/null

网上有6.19+ mainline 的 accel/ethosu + Mesa/Teflon 可以让 A55 直连 NPU、完全不经 M33,还是开源的。

https://www.linaro.org/blog/direct-kernel-access-to-ethos-u65-npu-on-i-mx9-benchmarks-using-latest-kernel-and-mesa-support

日志相关的:

# 内核需要开启 CONFIG_DYNAMIC_DEBUG 选项
# 全开动态调试(重启会丢)+ 清空日志
echo -n '+p' > /sys/kernel/debug/dynamic_debug/control
dmesg -C

可以交给AI,让AI反编译固件和so文件。

然后可以open下ethos节点:

/*
 * ethosu_caps_probe.c —— 不接 M33 串口,直接从内核 ethоsu 驱动读 NPU 硬件能力
 *
 * 原理:Linux 驱动的 ETHOSU_IOCTL_CAPABILITIES_REQ 会让 CM33 固件去读 Ethos-U 的
 *       ID 寄存器(product / arch / macs_per_cc / cmd_stream_version / custom_dma),
 *       再把结果回给用户态。所以这个程序能回答两件事:
 *         1) NPU 到底有没有响应(读回来全是 0 ⇒ 供电/时钟/NPU 没起来);
 *         2) 硬件自报的配置是什么(用来和模型里编进去的配置对比)。
 *
 * 交叉编译(主机上):
 *     aarch64-linux-gnu-gcc -O2 -Wall -o ethosu_caps_probe ethosu_caps_probe.c
 * 拷到板子,重启后运行(需要 root):
 *     ./ethosu_caps_probe
 *
 * QY 板(i.MX93 = Ethos-U65-256)实测正确的值:
 *   version_status=1, product_major=6 (NPU_ID 的 part 号;U65 的 NPU_CONFIG[31:28]=1),
 *   macs_per_cc=8 (=2^8=256 MACs 的原始编码), cmd_stream_version=0, custom_dma=0,
 *   arch=1.0.6 (= Vela 的 ARCH_VER), driver 0.16.0。
 *   硬件 NPU_CONFIG 读数为 0x10003008,与 Vela 编进模型的 optimizer config 字完全相同。
 */

#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

/* ---- 与 drivers/staging/ethosu/uapi/ethosu.h 保持一致的 UAPI 定义 ---- */
struct ethosu_uapi_device_hw_id {
        uint32_t version_status;
        uint32_t version_minor;
        uint32_t version_major;
        uint32_t product_major;
        uint32_t arch_patch_rev;
        uint32_t arch_minor_rev;
        uint32_t arch_major_rev;
};

struct ethosu_uapi_device_hw_cfg {
        uint32_t macs_per_cc;
        uint32_t cmd_stream_version;
        uint32_t custom_dma;
};

struct ethosu_uapi_device_capabilities {
        struct ethosu_uapi_device_hw_id hw_id;
        struct ethosu_uapi_device_hw_cfg hw_cfg;
        uint32_t driver_patch_rev;
        uint32_t driver_minor_rev;
        uint32_t driver_major_rev;
};

#define ETHOSU_IOCTL_BASE 0x01
#define ETHOSU_IOR(nr, type) _IOR(ETHOSU_IOCTL_BASE, nr, type)
#define ETHOSU_IOCTL_VERSION_REQ \
        _IO(ETHOSU_IOCTL_BASE, 0x01)
#define ETHOSU_IOCTL_CAPABILITIES_REQ \
        ETHOSU_IOR(0x02, struct ethosu_uapi_device_capabilities)

int main(void)
{
        struct ethosu_uapi_device_capabilities c;
        int fd, i, ret;

        /* open() 会顺带把 CM33 固件拉起来(并等待 rpmsg 通道就绪) */
        fd = open("/dev/ethosu0", O_RDWR | O_NONBLOCK);
        if (fd < 0) {
                fprintf(stderr, "open /dev/ethosu0 failed: %s\n", strerror(errno));
                return 1;
        }
        printf("/dev/ethosu0 opened\n");

        /* 和官方 delegate 一样先发一次 version 请求(只为对齐,无返回数据) */
        (void)ioctl(fd, ETHOSU_IOCTL_VERSION_REQ, NULL);

        /* 内核里 capabilities 请求最多等 5s,失败会打 "Capabilities response timeout" */
        for (i = 0; i < 3; i++) {
                memset(&c, 0, sizeof(c));
                ret = ioctl(fd, ETHOSU_IOCTL_CAPABILITIES_REQ, &c);
                if (ret == 0)
                        break;
                fprintf(stderr, "try %d: ioctl CAPABILITIES_REQ failed: %s\n",
                        i + 1, strerror(errno));
                sleep(1);
        }
        if (ret != 0) {
                fprintf(stderr,
                        "CAPABILITIES_REQ 一直失败 —— 看 dmesg 里 'Capabilities response timeout'\n");
                close(fd);
                return 2;
        }

        printf("hw_id : version_status=%u version=%u.%u product_major=%u arch=%u.%u.%u\n",
               c.hw_id.version_status,
               c.hw_id.version_major, c.hw_id.version_minor,
               c.hw_id.product_major,
               c.hw_id.arch_major_rev, c.hw_id.arch_minor_rev, c.hw_id.arch_patch_rev);
        printf("hw_cfg: macs_per_cc=%u cmd_stream_version=%u custom_dma=%u\n",
               c.hw_cfg.macs_per_cc, c.hw_cfg.cmd_stream_version, c.hw_cfg.custom_dma);
        printf("driver: %u.%u.%u\n",
               c.driver_major_rev, c.driver_minor_rev, c.driver_patch_rev);

        printf("\n---- 解读提示 ----\n");
        if (c.hw_id.version_status == 0 || c.hw_cfg.macs_per_cc == 0) {
                printf("!! version_status/macs_per_cc 为 0:固件没读到 NPU 的 ID 寄存器,\n"
                       "   基本可以判定 NPU 没上电/没时钟(板级问题),而不是模型问题。\n");
        } else {
                printf("NPU 有响应。QY 板(i.MX93=Ethos-U65-256)正确的实测值:\n"
                       "   version_status=1  product_major=6(NPU_ID)  macs_per_cc=8(=256 MACs)\n"
                       "   cmd_stream_version=0  custom_dma=0  arch=1.0.6  driver=0.16.0\n"
                       "硬件 NPU_CONFIG=0x10003008 与 Vela 编进模型的 config 字一致 => 配置不匹配已排除。\n");
        }

        close(fd);
        return 0;
}
posted @ 2026-10-09 17:20  杨旭0324  阅读(5)  评论(0)    收藏  举报