概述
本文将介绍Zynq软硬件协同开发所需要的核心概念、典型架构以及基本开发流程。文章从嵌入式系统出发,引入TinyML,再过渡到Zynq架构与PS‑PL协同计算。
1. 从嵌入式系统开始
当我们把一个应用部署到硬件设备上时,系统通常包含三个基本环节:
感知
获取温度、湿度、图像等环境数据。
计算
对输入数据进行处理,得到控制决策或识别结果。
作动 / 通信
执行动作,或者把结果发送给外部系统。
几乎所有嵌入式系统都包含感知与计算两个部分,而作动或通信则取决于具体应用场景。比如以下案例:
- 将湿度传感器插入土壤。
- 使用微控制器(MCU)读取湿度数据
- 当湿度低于阈值时启动水泵或水用电磁阀开始浇水
- 湿度恢复后停止浇水
- 可以进一步通过网络上传湿度数据
在该系统中:
| 组件 | 作用 |
|---|---|
| 湿度传感器 | 感知环境 |
| 水泵/电磁阀 | 作动器 |
| MCU | 控制与计算 |
MCU(例如C51、STM32、ESP32)通常作为系统的控制核心,协调各部分正常运行,因此需要在MCU上编写应用逻辑。输入输出通常通过通信协议(如UART、I2C、SPI)或ADC/DAC来实现。
手上没有单片机的可以去Wokwi网站上做一些demo学习一下嵌入式软件开发,对于案例一,我在官方的MicroPython案例上做了一些修改:
开始仿真后点击DHT22(温湿度传感器),上方会出现状态栏,可以手动调节温湿度。当湿度小于40%时LED灯会亮,表示打开水泵开始浇水;湿度大于60%时LED灯会灭,表示停止浇水。由于每5秒检测一次,所以不是即时变化的。

数据会通过MQTT协议发送到服务器 broker.mqttdashboard.com,主题为 wokwi-auto-water。
在PC上可以下载一个MQTTBox,点击“Create MQTT Client”,修改 Host 为该服务器,选择 Protocol 为 mqtt/tcp,然后保存。

connected 表示连接服务器成功。此时订阅 wokwi-auto-water 主题,即可远程收到来自ESP32发送的数据。

2. TinyML
如果希望在嵌入式设备上部署神经网络推理,系统结构仍然遵循相同流程:数据输入 → 模型计算 → 输出结果。考虑以下案例:
- 摄像头采集图像
- MCU执行神经网络推理
- 输出识别结果
为了在资源受限设备上运行机器学习模型,可以使用TinyML技术。
TinyML(Tiny Machine Learning)是将轻量化机器学习模型部署到资源受限的嵌入式设备(如微控制器、传感器节点)上的技术,通常运行在mW级功耗、KB级内存的硬件上,实现本地化智能推理。它融合了边缘计算、模型压缩、嵌入式系统优化等多领域技术,适用于无网络、低延迟、隐私保护等场景。
以TFLite(TinyML的其中一种)为例,可以把整个落地过程拆成两个阶段:
训练与部署
- 在PC/GPU上搭建模型并完成训练
- 导出TensorFlow Lite模型为
tflite文件 - 解析
tflite文件并转换为C数组 - 将模型和输入数据嵌入MCU程序
MCU推理
- 使用TFLite Micro加载模型
- 分配运行时内存(Tensor Arena)
- 在MCU上执行推理并输出结果
可以参考以下实现,由于Wokwi没法模拟摄像头,所以这里直接把数字图片转换成数组作为输入,MCU读取该输入数据做推理:
3. 从 MCU 到 Zynq
存储瓶颈
虽然TinyML已经实现了从训练到部署一体化,但单片机的SRAM通常只有几百KB,Flash只有几MB。模型权重往往存放在Flash中,因此模型规模会受限;中间结果保存在SRAM中,因此特征图大小也会受限。
计算瓶颈
MCU的CPU通常主频较低,也缺乏大规模并行计算能力,因此难以支撑高吞吐、低时延的计算任务。
这也是从MCU进一步走向Zynq的核心动机。就像PC训练模型时会把计算交给GPU一样,Zynq也是“CPU + 专用并行硬件”这一思路在嵌入式场景下的体现。
4. Zynq 架构
Zynq是一种CPU+FPGA的异构SoC。系统由两部分组成:
PS(Processing System)
ARM处理器系统,主频较高,可访问大容量DDR,适合执行数据预处理、外设控制、逻辑决策等串行任务。
PL(Programmable Logic)
FPGA可编程逻辑,适合把卷积、矩阵乘法等高并行度计算做成硬件流水线。
PS偏控制与调度,PL偏并行计算与加速。
5. PL端开发
PL端本质上是FPGA开发,可以使用Verilog/VHDL语言,但对于算法开发者来说,使用HLS(High Level Synthesis)更容易。
HLS能帮我们做什么
- 将高层语言(C、C++、SystemC)转换成RTL语言(Verilog、VHDL),并生成IP核。
- 提供
pipeline、unroll等优化手段,可以进一步提升运行效率,但过度优化可能导致FPGA资源不足。 - 为输入输出生成AXI接口,便于后续与PS侧系统集成。
相关教程如下:
Vivado用于Xilinx系列FPGA的开发,也就是PL端的开发,基本的使用教程如下:
6. PS端开发
PS端本质上属于嵌入式软件开发,开发环境为Vitis(旧版叫Vivado SDK),不过与普通的嵌入式开发有所不同,这里需要在Vivado中配置Zynq IP核,然后才能在此基础上编程,可以参考以下教程:
如果使用的是Pynq(Python on Zynq)开发板,顾名思义其也是Zynq架构,只是在PS端编程时可以用Python开发,类似于案例一用MicroPython开发ESP32一样。基本使用教程如下:
上面只简单打印了一个helloworld,下面这个视频更加详细介绍Pynq上Jupyter Notebook的使用:
有关Pynq相关的API可以在以下网站中找到:
7. PS与PL通信
PS需要将任务卸载到PL端去运算,那么PS和PL之间就需要进行数据的传输。

上图里面是PS,外面灰色是PL。PS和PL之间的接口有很多,但去除时钟复位中断等能用来传输数据的就是图中框出来的部分。
7.1 EMIO方式
PS中很多外设(GPIO/SPI/UART/I2C等)原本只能通过MIO引脚连接到板子外部,但如果MIO不够或需要在PL内部使用,就可以走EMIO → PL。这种方式通常用作少量、低速的数据运输。使用方式可以参考我先前的博客:
7.2 AXI总线方式
7.2.1 AXI协议
AXI有三种协议,AXI Lite、AXI Full、AXI Stream。简单来说:
AXI Lite
轻量级地址映射协议,每次传输都携带地址和数据,协议开销小,通常用于寄存器读写。
AXI Full
支持突发传输。发送一次地址后可以连续传多个数据,适合批量且地址连续的数据搬运。
AXI Stream
无地址的数据流协议,适合模块之间连续传输数据,常见于视频流和DSP流水线。
有关AXI协议的更加详细的说明可以看以下视频:
7.2.2 PS提供的AXI接口
PS端有三种AXI接口,分别是AXI GP、AXI HP和AXI ACP。
AXI GP既可以主动发起读写请求(Master),也可以被动接收读写请求(Slave)。它的带宽较低,最常见的用途是由PS侧通过Master接口去配置寄存器。协议上可以使用AXI Lite或AXI Full,但通常使用AXI Lite。
AXI HP(High Performance)接口对PL侧只提供Slave模式,也就是PL作为Master发起访问。它的带宽远高于AXI GP,适合大批量数据传输,通常配合AXI Full协议使用。常见做法是PS先把数据写到DDR,再由PL通过AXI HP访问PS DDR,实现高速交换。
AXI ACP同样只有Slave接口,但它连到了CPU Cache,可以自动维护一致性,适合需要CPU Cache协同访问的场景。不过从带宽角度看,它通常不如AXI HP。
关于这几种接口的具体说明可以看下面这个视频:
7.3 DMA方式
在高性能系统中通常使用DMA进行数据搬运,本质上也是使用了AXI总线。
AXI DMA是一个IP核,主要包含两个方向:
| 通道 | 方向 |
|---|---|
| MM2S | Memory → Stream |
| S2MM | Stream → Memory |

PS → PL(MM2S)
- CPU先通过
S_AXI_LITE配置AXI DMA的控制寄存器,例如DDR起始地址、数据长度和传输模式。 - AXI DMA随后通过
M_AXI_MM2S从PS DDR读取数据,这一路通常需要连到PS的AXI HP接口。 - 读取到的数据再通过
M_AXIS_MM2S送给PL模块,例如自定义的AXI Stream IP核。
PL → PS(S2MM)
- 如果数据方向相反,AXI DMA会通过
S_AXIS_S2MM接收来自PL模块的数据。 - 然后使用
M_AXI_S2MM把结果写回PS DDR,因此这一路通常也连接PS的AXI HP接口。 - CPU再从DDR中读取运算结果,继续执行后续软件逻辑。
相关视频如下:
Pynq可以参考:
8. 示例工程
这是一个简单但完整的案例,介绍了从HLS、Vivado到Pynq的完整过程。
加法器案例主要演示单个数值的传输与运算,而实际工程里更常见的是矩阵、数组等批量数据处理,因此下一步可以看这个案例。
下面这个工程比较复杂:HLS实现向量加法,PS与PL通过AXI DMA交互,PS端使用Vivado SDK(Vitis)开发。
9. 尾言
写在最后
(1)将复杂算法从CPU迁移到FPGA后,资源限制并未消失,而是转移到了FPGA端——FPGA同样会受运算资源(LUT / DSP / FF数量)和存储资源(BRAM容量)的限制。
(2)前面说的主要是深度学习推理。其实用Zynq做训练并不是不行,但需要自己实现反向传播,工程复杂度会明显上升。可以参考我之前写的LSTM反向传播剖析与C++实现:
(3)本文里提到的PS端开发主要偏裸机路线,但在Vitis创建platform时也可以选择FreeRTOS,还可以进一步走向PetaLinux嵌入式Linux开发:
(4)hls4ml 可以把深度学习框架中的模型转换成可被HLS综合的C++代码,除了转换外还会做一些量化优化。但它主要支持常见算子(如 Conv2D、Dense、Relu),如果是更复杂的算子(如attention)或自定义算子,仍然需要自己补代码,具体介绍如下:
(5)除了Zynq这种 CPU + FPGA 架构,现在 CPU + NPU 也很热门,例如RK3588。借助RKNN Toolkit这类工具链,开发者通常不需要手写硬件层代码,更多是做模型转换和Python/C++上层调用。
MCU
适合低算力(GOPS级以下)、超低功耗场景。
FPGA
适合中等算力、对数据通路和算子形式有较高定制化要求的场景。
NPU
适合中高算力场景,开发效率更高,但灵活性不如FPGA。