
简介《PYNQ-Z2入门指导手册_v2.01》面向希望借助Python快速上手Xilinx Zynq APSoC开发板的嵌入式初学者与教学人员解决不熟悉可编程逻辑设计却想调用FPGA硬件加速能力的问题。手册依次讲解PYNQ开源框架与Jupyter Notebook交互环境、软硬件准备网络连接、主机名与代理配置、开发板接口设置及在线编程连接方法并给出按键控制LED、录音与音频处理、动态实时面部识别三个由浅入深的实践例程覆盖GPIO控制、音频接口与视频图像处理等典型场景。资源包共1个PDF文件大小约1.68MB结构按章节与实验划分便于对照操作与课堂演示。目前已有2698人学习适合作为课程实验、自学入门与原型验证的参考起点。1. 拿到 PYNQ-Z2 别急着点灯这份手册真正省掉的是哪几步板子到手很多人第一反应是插电、连网、打开浏览器然后在pynq:9090那个登录框前面卡住半小时——用户名密码是什么、为什么主机名解析不到、SD 卡烧完插上去四个红灯闪完就没动静。这些不是技术难点是信息差。这份《PYNQ-Z2 入门指导手册_v2.01》的价值就在这儿它把从空白 SD 卡到跑通三个例程的路径压成了一条直线省掉的是你在论坛里翻旧帖、在报错信息里猜原因的时间。PYNQ 这套东西的定位值得先说清楚。它跑在 Zynq XC7Z020 上ARM A9 双核加 FPGA 逻辑但和传统 Zynq 开发最大的区别是你不需要写 Verilog、不需要跑综合实现FPGA 逻辑以 overlay 的形式预编译好Python 里BaseOverlay(base.bit)一加载硬件就变成了可以调用的对象。base.leds、base.buttons、base.audio、base.video这些属性背后是实实在在的 PL 资源但对使用者来说和调一个 Python 库没区别。手册面向的就是这批人会写 Python、想用硬件加速、但不想碰时序约束和管脚分配。三个例程的梯度也合理——按键控 LED 是 GPIO 读写录音是音频编解码链路人脸识别是视频流加 OpenCV。走完这三个你对 PYNQ 的 API 风格、overlay 加载机制、Jupyter 里的调试节奏就有了体感。下面按实际操作的顺序拆重点放在手册里一笔带过但实际会卡住的地方。2. 从空白 SD 卡到 Jupyter 首页镜像烧写与网络链路2.1 镜像烧写win32DiskImager 与 dd 的差别在哪手册给了两条路Windows 用 win32DiskImagerLinux/macOS 用dd。这不是随便选的背后是块设备写入方式的不同。win32DiskImager 直接对物理磁盘扇区写入绕开文件系统dd同理但参数写错就是灾难。Windows 下的操作没什么坑选镜像文件、选设备盘符、点 Write。唯一要注意的是 Device 下拉框里别选成你的移动硬盘——它列的是所有可写物理盘SD 卡一般显示为 E 盘或 F 盘容量对得上再点。Linux/macOS 下用dd先确认设备名# 插入 SD 卡后查看新出现的块设备通常是 /dev/sdX 或 /dev/diskN lsblk # 或者 macOS 下 diskutil list确认之后写入注意of后面是整盘设备而不是分区# Linux假设 SD 卡是 /dev/sdb务必确认不要写成 /dev/sdb1 sudo dd ifpynq_z2_v2.01.img of/dev/sdb bs4M statusprogress convfsyncbs4M是块大小影响写入速度4M 在大多数卡上是甜点值statusprogress让你看到进度而不是干等convfsync保证数据真正落盘再返回不加这个有时候拔卡太快会写不完整。macOS 下设备名是/dev/rdiskX带 r 的原始设备更快写完用diskutil eject弹出。提示烧写完成后 Windows 可能弹窗提示「需要格式化磁盘」千万别点格式化那是系统不认识 Linux 分区表点取消直接拔卡即可。2.2 跳线与供电Boot 和电源两个跳线帽别搞反硬件设置这步手册列了六条实际最容易翻车的是前两条。Boot 跳线决定从哪儿启动必须拨到 SD 位置否则板子会去找 QSPI 里的旧固件表现就是串口没输出、网口不亮。电源跳线选 USB 还是 REG 取决于你用什么供电Micro USB 线供电就选 USB外接 12V 适配器就选 REG。用 USB 供电时注意电脑 USB 口的电流能力有些老笔记本的 USB 2.0 口带不动板子会反复重启换 USB 3.0 口或者带外部供电的 Hub 就正常了。启动完成的标志手册写得很具体大约一分钟后两个蓝色 LED 和四个红色 LED 同时闪动随后蓝色灭、四个红色常亮。这个状态说明 Linux 起来了、overlay 加载了、Jupyter 服务在跑。如果超过两分钟还是只有电源灯亮先查 SD 卡是不是没插紧再查串口有没有输出。2.3 网络两种接法DHCP 与静态 IP 的取舍手册给了两条网络路径选哪条取决于你手边有没有路由器。接路由器/交换机走 DHCP板子自动拿 IP浏览器访问http://pynq:9090。这里依赖的是 mDNS 主机名解析Windows 10 以后原生支持但有些精简版系统或者公司网络策略会禁掉。解析不到就改用 IP进路由器管理页看 DHCP 客户端列表找 hostname 为pynq的那台拿到 IP 直接访问http://那个IP:9090。直连电脑走静态 IP电脑网卡手动配一个同网段地址比如192.168.2.100子网掩码255.255.255.0网关留空。板子默认静态地址是192.168.2.99访问http://192.168.2.99:9090。这条路的代价是板子没有外网pip install和apt update都用不了只适合纯离线跑例程。登录凭据两处都是xilinx/xilinxJupyter 和 Samba 文件共享共用这一套。Samba 在 Windows 资源管理器地址栏输\\pynq\xilinx或者\\192.168.2.99\xilinx能把板子主目录挂成网络驱动器传文件比在 Jupyter 里上传方便得多。2.4 改主机名与串口兜底网络不通时的后门多块板子接同一个网络时默认主机名pynq会冲突手册建议第一时间改掉。在 Jupyter 里 New → Terminal 开一个终端执行# 把 NEW_HOST_NAME 换成你要的名字脚本会改 /etc/hostname 和 /etc/hosts sudo /home/xilinx/scripts/hostname.sh mypynq # 重启生效 sudo shutdown -r now如果网络彻底不通、Jupyter 进不去串口是最后的救命通道。用 Micro USB 线接 PROG UARTJ14Windows 设备管理器里看 COM 口PuTTY 选 Serial参数是 115200 波特率、8 数据位、1 停止位、无校验、无流控。连上后按回车出现xilinxpynq:~$就通了ifconfig看 IP、hostname看主机名、lsblk看存储都是在这里查。3. 三个例程的代码拆解GPIO、音频链路与视频流3.1 按键控 LEDoverlay 加载与轮询模型第一个例程在base/board/board_btn_leds.ipynb核心逻辑是一个while循环轮询四个按键。代码不长但把 PYNQ 的几个关键概念都串起来了from time import sleep from pynq.overlays.base import BaseOverlay # 加载 base overlay这一步把 bitstream 下载进 PL base BaseOverlay(base.bit) Delay1 0.3 # 按键0换色后的停留时间 Delay2 0.1 # 流水灯每步的间隔 color 0 rgbled_position [4, 5] # 板载两颗 RGB LED 在数组里的下标 for led in base.leds: led.on() # 按键3是退出键读值为0表示未按下 while (base.buttons[3].read() 0): if (base.buttons[0].read() 1): color (color 1) % 8 # 8 种颜色循环 for led in rgbled_position: base.rgbleds[led].write(color) sleep(Delay1) elif (base.buttons[1].read() 1): for led in base.leds: led.off() sleep(Delay2) for led in base.leds: led.toggle() # 从右到左流水 sleep(Delay2) elif (base.buttons[2].read() 1): for led in reversed(base.leds): led.off() sleep(Delay2) for led in reversed(base.leds): led.toggle() # 从左到右流水 sleep(Delay2) print(End of this demo ...) for led in base.leds: led.off() for led in rgbled_position: base.rgbleds[led].off()BaseOverlay(base.bit)这行是整段代码的地基。base.bit是预编译好的 bitstream加载过程把 PL 配置成一组固定外设LED、按键、RGB LED、音频、HDMI、Pmod 都在里面。加载耗时一两秒期间 Jupyter 单元格显示[*]别急着点下一个。base.buttons[n].read()返回 0 或 1是纯轮询没有中断。这意味着按键响应有延迟取决于循环体执行时间。Delay10.3和Delay20.1这两个值直接决定手感调小流水灯更快但 CPU 占用上升调大更省资源但按键反应变钝。实际调试时如果发现按一下跳好几步就是循环太快没做消抖把Delay2加到 0.15 以上通常能缓解。base.rgbleds[led].write(color)里的color是 0 到 7 的整数对应 8 种预设颜色不是 RGB 三通道值。这是 PYNQ 封装层做的简化底层还是 PWM 调三路但 API 层面只暴露了枚举。想自定义颜色得往下挖pynq.lib的源码入门阶段用枚举够了。3.2 录音与音频处理bypass、record、load 三个动作的区别第二个例程在base/audio/audio_playback.ipynb音频链路比 GPIO 复杂因为涉及模拟前端、编解码器和 DMA。先看操作部分from pynq.overlays.base import BaseOverlay base BaseOverlay(base.bit) pAudio base.audio # 选 Line_in 作为输入源bypass 是把输入直通到输出用来快速验证链路 pAudio.select_line_in() pAudio.bypass(seconds5) # 录 5 秒到内存缓冲区 pAudio.record(5) # 存成 wav 文件路径不写就存到当前 notebook 目录 pAudio.save(recording_1.wav) # 从文件加载并播放 pAudio.load(/home/xilinx/jupyter_notebooks/base/audio/recording_0.wav) pAudio.play()select_line_in()切输入源板子上还有 MIC 输入做录音实验时如果没声音先查这里选对没有。bypass(seconds5)是个诊断动作——把输入直接环到输出插耳机应该能听到 Line in 进来的声音听不到说明硬件链路有问题跟代码无关。record(5)录到内存save()才落盘两个动作分开是为了让你能在保存前做处理。后面的 PCM 绘图部分用了wave加numpy手动解析 wav 头再fft出频谱、specgram出时频图。这段代码的价值不在绘图本身在于演示了怎么把板子录的音频拿进标准 Python 科学计算栈。temp_buffer那段位操作是把不同采样宽度的字节对齐到 32 位整型sample_width为 2 时高两字节用符号位填充这是处理 16 位 PCM 的通用写法换成 24 位录音也能用。注意pAudio.play()是阻塞的播放期间单元格一直显示[*]别以为卡死了。要边播边处理得用pAudio.load()之后另开线程入门阶段不建议碰。3.3 实时人脸识别视频管线与 Haar 级联的参数第三个例程在base/video/opencv_face_detect_webcam.ipynb需要 USB 摄像头插 USB HOST、HDMI OUT 接显示器。这条链路是三段摄像头采集 → OpenCV 处理 → HDMI 输出。初始化部分from pynq.overlays.base import BaseOverlay from pynq.lib.video import * base BaseOverlay(base.bit) # HDMI 输出配成 640x480 24 位 BGR Mode VideoMode(640, 480, 24) hdmi_out base.video.hdmi_out hdmi_out.configure(Mode, PIXEL_BGR) hdmi_out.start() # 摄像头采集分辨率 frame_in_w, frame_in_h 640, 480 import cv2 videoIn cv2.VideoCapture(0) videoIn.set(cv2.CAP_PROP_FRAME_WIDTH, frame_in_w) videoIn.set(cv2.CAP_PROP_FRAME_HEIGHT, frame_in_h) print(Capture device is open: str(videoIn.isOpened()))VideoMode(640, 480, 24)三个参数是宽、高、色深PIXEL_BGR指定像素格式和 OpenCV 的默认通道顺序一致省掉一次转换。hdmi_out.start()之后显示器才出画面之前 configure 只是设参数。检测循环里两个级联分类器的路径是硬编码的face_cascade cv2.CascadeClassifier( /home/xilinx/jupyter_notebooks/base/video/data/haarcascade_frontalface_default.xml) eye_cascade cv2.CascadeClassifier( /home/xilinx/jupyter_notebooks/base/video/data/haarcascade_eye.xml) gray cv2.cvtColor(np_frame, cv2.COLOR_BGR2GRAY) # 1.3 是每次图像缩小的比例5 是判定为脸所需的最少邻域数 faces face_cascade.detectMultiScale(gray, 1.3, 5) for (x, y, w, h) in faces: cv2.rectangle(np_frame, (x, y), (xw, yh), (255, 0, 0), 2) roi_gray gray[y:yh, x:xw] roi_color np_frame[y:yh, x:xw] eyes eye_cascade.detectMultiScale(roi_gray) for (ex, ey, ew, eh) in eyes: cv2.rectangle(roi_color, (ex, ey), (exew, eyeh), (0, 255, 0), 2)detectMultiScale的scaleFactor1.3和minNeighbors5是两个手感参数。scaleFactor越小检测越细但越慢1.1 能抓到更小的脸代价是帧率掉一半minNeighbors越大误检越少但漏检越多5 是 OpenCV 的默认值光线差的环境调到 6 到 8 能压掉不少假阳性。这段代码在 XC7Z020 的 ARM 核上跑640x480 下大概 5 到 8 帧每秒属于能看但不流畅的水平——想提帧率要么降分辨率到 320x240要么把检测间隔改成隔帧跑。4. 避坑清单五个实际会卡住的现象与解法4.1 浏览器打不开 pynq:9090但 IP 能通现象地址栏输http://pynq:9090一直转圈换成路由器里查到的 IP 就正常。原因mDNS 解析失败。Windows 的 mDNS 依赖 Bonjour 服务部分精简系统没装公司网络也可能屏蔽 5353 端口。解决直接用 IP 访问或者在电脑 hosts 文件里加一条静态映射。长期用的话在路由器里给板子的 MAC 地址绑定固定 IP省得每次查。4.2 板子启动后四个红灯不亮串口无输出现象上电后只有电源灯等三分钟也没动静。原因按概率排第一是 Boot 跳线没拨到 SD第二是 SD 卡烧写不完整第三是供电不足导致反复重启。解决先看跳线帽位置再重新烧一次镜像烧完用lsblk确认卡上出现了 FAT 分区和 ext4 分区最后换 USB 3.0 口或外接 12V 电源试。串口接上按回车没反应多半是波特率不对确认是 115200 而不是 9600。4.3 音频例程跑完没声音现象record和play都执行完了耳机里静悄悄。原因输入源选错Line in 没接信号却选了 Line in、输出音量被静音、或者耳机插在了错误的孔上。解决先跑bypass(seconds5)确认硬件链路有直通声说明编解码器正常再查select_line_in()和select_mic()选的是不是当前实际接的那路最后在终端里alsamixer看有没有通道被 mute。4.4 人脸识别报错找不到 xml 文件现象CascadeClassifier加载返回空后面detectMultiScale抛异常。原因notebook 里的路径是绝对路径如果你把 notebook 复制到别的目录跑相对路径就断了或者 overlay 版本不同data 目录位置有变。解决在终端里find /home/xilinx -name haarcascade_frontalface_default.xml找到实际路径替换进去。更稳的做法是把 xml 拷到 notebook 同目录用相对路径./haarcascade_frontalface_default.xml。4.5 改了主机名之后 Jupyter 连不上现象执行完hostname.sh重启原来的pynq:9090打不开新名字也解析不到。原因主机名改了但电脑的 DNS 缓存还指着旧名字或者路由器 DHCP 租约没更新。解决用 IP 访问确认服务正常然后在 Windows 上ipconfig /flushdns等一两分钟让路由器更新租约。急用就直接走 IP主机名只是方便记。5. 把例程改成自己的东西从改参数到换 overlay跑通三个例程只是起点真正要用起来得知道改哪里。最省事的切入点是调参数按键例程里把Delay2从 0.1 改成 0.05 看流水灯快多少音频例程里把record(5)改成record(10)看内存占用人脸识别里把scaleFactor从 1.3 降到 1.1 看帧率掉多少。这些改动不改架构但能让你对每个参数的实际影响有数。再进一步是换输入输出。按键例程的base.buttons换成 Pmod 接口上的外设音频例程的select_line_in()换成select_mic()用板载麦克风视频例程把cv2.VideoCapture(0)换成 HDMI IN 采集——base.video.hdmi_in的用法和hdmi_out对称configure加start之后readframe()拿帧。这一步开始接触 PYNQ 的流式接口和 OpenCV 的VideoCapture是两套模型混用的时候注意帧格式转换。真正进阶是换 overlay。base.bit是官方给的通用外设集合如果你要跑自己的加速器得用 Vivado HLS 或者 Vitis 生成新的 bitstream 和对应的 Python 驱动放到板子上用Overlay(your.bit)加载。这条路手册没展开但三个例程已经把 API 风格演示清楚了加载、拿句柄、调方法、读写寄存器换 overlay 只是换句柄名和寄存器映射。验证改动有没有生效我习惯用两个笨办法一是串口终端里top看 CPU 占用流水灯调快之后 Python 进程的 CPU 应该明显上升二是 Jupyter 里%timeit测单次操作耗时比如%timeit base.buttons[0].read()能看出轮询一次的开销在微秒级还是毫秒级。这两个数比肉眼观察靠谱。有个细节值得单独说Jupyter notebook 里改过的单元格会直接改文件下次打开就是改后的版本。手册提到可以从 GitHub 重新下载原始 notebook 恢复但更稳妥的做法是动手之前先cp board_btn_leds.ipynb board_btn_leds_backup.ipynb改坏了随时回滚。我吃过这个亏——调参数调乱了想找回原始值结果发现保存过的 notebook 已经覆盖了只能重新拉。从那以后我每次拿到新板子第一件事是把官方 notebook 整个目录复制一份到~/mywork/原目录只读不动所有改动在副本里做。这个习惯看着笨但省掉了无数次「原始代码长什么样来着」的回忆。希望帮到你。本文还有配套的精品资源点击获取