当前位置:首页>Linux>把Linux部署到FPGA上,然后让你的NPU在Linux操作系统里工作

把Linux部署到FPGA上,然后让你的NPU在Linux操作系统里工作

  • 2026-10-11 06:21:52
把Linux部署到FPGA上,然后让你的NPU在Linux操作系统里工作
紧接上篇“从Pytorch到FPGA:搭建你的第一个机器学习加速器”的逻辑版本,这次完成了将linux部署到FPGA上,并完成与部署在FPGA上的NPU的通信,实现一个完整应用。

第一步:Vivado硬件设计——把Tensil NPU放进系统

这一步在第一篇文章中已经涉及了这里不再详细说明了,具体操作请参照前一篇的文档。
这里我们需要把设计好的NPU的hdf文件拷贝到ubuntu的petalinux的工程中

第二步:PetaLinux构建——编译你的专属Linux系统

首先,创建petalinux工程完成对linux的kernel,boot,rootfs,设备树的配置。创建工程的命令如下:

petalinux-create -t project --name my_linux --template zynq

改名命令创建了一个名为my_linux的工程,创建结果如下图所示:

其次,进入到该目录下运行如下命令

petalinux-config --get-hw-description=/home/alinx/Downloads/tensil_peta_project/tensil_pynqz1.sdk

该命令将硬件设计文件hdf(硬件描述文件)导入到petalinux的工程中,完成对硬件信息的提取,并进入到配置界面,如下所示:

做过linux开发的人看到该页面应该是很熟悉的,使用方法和其他嵌入式开发是类似的,这里不再介绍如何配置

接着,完成对linux驱动的代码的编写,创建linux驱动代码的方法如下

petalinux-create -t modules --name my-tensil-driver --enable

my-tensil-driver就是创建的linux驱动模块如下图所示:

下面是NPU在linux中的驱动代码片段

.......static const struct of_device_id tensil_tcu_of_match[] = {    { .compatible = "tensil,tcu", },    { /* sentinel */ },};MODULE_DEVICE_TABLE(of, tensil_tcu_of_match);static struct platform_driver tensil_tcu_driver = {    .probe  = tensil_tcu_probe,    .remove = tensil_tcu_remove,    .driver = {        .name       = DRIVER_NAME,        .of_match_table = tensil_tcu_of_match,    },};module_platform_driver(tensil_tcu_driver);MODULE_LICENSE("GPL v2");MODULE_AUTHOR("MY NPU");MODULE_DESCRIPTION(DRIVER_DESC);MODULE_VERSION(DRIVER_VERSION);

然后,添加设备树节点,由于是自定义的设备,所以需要手动的将设备添加到设备树中,如下所示

/include/ "system-conf.dtsi"/ {	&amba {	    tensil_npu@0x08000000 {		compatible = "generic-uio";		reg = <0x0 0x08000000 0x0 0x10000>;	    };	};};

然后,调用下面的命令完成rootfs的配置

petalinux-config -c rootfs

运行后如下图所示,我们编写的驱动程序被加载到rootfs里面了

调用下面的命令完成对kernel的配置,将UIO和UIO Platform Dirver打开

petalinux-config -c kernel

最后,调用下面的命令去编译整个linux

petalinux-build
下图是我们编译生成的驱动模块my-tensil-dirver.ko和启动linux时用的相关image

将编译生成的内核,设备树,rootfs打包到SD卡中,通过如下命令

petalinux-package --boot --fsbl images/linux/zynqmp_fsbl.elf --u-boot --fpga images/linux/system.bit

打包后,将UBOOT.bin和image.ub复制到SD卡中,将FPGA的开发板启动模式切换到SD卡启动模式。

第四步:NPU验证                                                                                      

上面的驱动已经完成了,后面需要在linux的用户空间打开NPU的设备

1)通过下面的代码打开NPU的设备

/* ============================================================	 * Step 1: Open device (equivalent to init_platform + driver_init)	 * ============================================================ */	ctx = tensil_tcu_open();if (!ctx) {		fprintf(stderr, "FAILED: tensil_tcu_open()\n""Is the kernel module loaded? (sudo insmod tensil-tcu.ko)\n");return 1;	}	printf("[1] Device opened: /dev/tensil-tcu\n");

2)加载.tmodel文件

/* ============================================================	 * Step 2: Load .tmodel file (equivalent to tensil_model_from_file)	 * ============================================================ */printf("[2] Loading model from %s...\n", tmodel_path);if (tensil_tcu_model_from_file(&model, tmodel_path) != 0) {fprintf(stderr, "FAILED: tensil_tcu_model_from_file()\n");        	tensil_tcu_close(ctx);return 1;	}

3)加载神经网络模型

/* ============================================================	 * Step 3: Load model into driver	 *         (equivalent to tensil_driver_load_model)	 * ============================================================ */printf("[3] Loading model into driver...\n");if (tensil_tcu_load_model(ctx, &model) != 0) {fprintf(stderr, "FAILED: tensil_tcu_load_model()\n");tensil_tcu_close(ctx);return 1;	}

4)加载并处理待测试bmp文件

if (load_cifar_image(image_path, red, green, blue,				     &expected_label) != 0) {fprintf(stderr, "FAILED: load_cifar_image()\n");tensil_tcu_close(ctx);return 1;		}preprocess_image(red, green, blue, input_data);

5)加载模型使用的参数

/* ============================================================	 * Step 5: Load input scalars to DRAM0	 *         (equivalent to tensil_driver_load_model_input_scalars)	 * ============================================================ */	printf("[5] Loading input \"%s\" (%d scalars) to DRAM0...\n",	       model.inputs[0].name, CIFAR_TOTAL_PIXELS);if (tensil_tcu_load_input_scalars(ctx, &model,					  model.inputs[0].name,					  CIFAR_TOTAL_PIXELS,					  input_data) != 0) {		fprintf(stderr, "FAILED: tensil_tcu_load_input_scalars()\n");		tensil_tcu_close(ctx);return 1;	}

6)运行模型

/* ============================================================	 * Step 6: Run inference	 *         (equivalent to tensil_driver_run)	 * ============================================================ */printf("[6] Running inference...\n");if (tensil_tcu_run(ctx) != 0) {fprintf(stderr, "FAILED: tensil_tcu_run()\n");tensil_tcu_close(ctx);return 1;	}

7)获取NPU推理结果

/* ============================================================	 * Step 7: Get output scalars from DRAM0	 *         (equivalent to tensil_driver_get_model_output_scalars)	 * ============================================================ */	printf("[7] Reading output \"%s\" (%d scalars) from DRAM0...\n",	       model.outputs[0].name, CIFAR_NUM_CLASSES);if (tensil_tcu_get_output_scalars(ctx, &model,					  model.outputs[0].name,					  CIFAR_NUM_CLASSES,					  output_data) != 0) {		fprintf(stderr, "FAILED: tensil_tcu_get_output_scalars()\n");		tensil_tcu_close(ctx);return 1;	}

以上是一个完整的从pytorch到硬件,然后在linux上完成应用的开发,但是在开发工程中要注意设备树中的compatible这个属性以及自定义设备的内存地址,另外,要对petalinux的开发很熟悉,包括BSP和kernel的配置一以及在Linux上应用的开发。还要熟悉如何实现自定义硬件的指令集,这部分可以参考 “从指令到硬件:在 Chipyard 中实现 RoCC 自定义加速器”的文章。

希望这篇文章能起到抛砖引玉的作用,谢谢大家。

最新文章

随机文章