
大家用SoC FPGA做项目最绕不开的一个场景就是FPGA端有一堆实时信号HPS端跑着Linux或裸机程序两边得配合干活那FPGA怎么“通知”HPS呢轮询太浪费CPU串口更不可能最正经的方案就是中断。上一篇文章我们把Agilex 5 SoC FPGA的HPS启动流程、FPGA和HPS之间的通信方式捋了一遍结论是HPS要响应FPGA中断硬件链路上其实就靠在Quartus工程里把FPGA侧的中断信号接到HPS的f2h_irq上。今天这篇就专门讲这部分也就是GHRD工程Golden Hardware Reference Design里到底要改哪里、怎么改、改完怎么编译、编译完还有哪些坑等着你。这篇文章适合正在用Agilex 5做开发、手里已经有Quartus Prime Pro和一块Agilex 5开发板的朋友。如果你从来没碰过GHRD工程也没关系我会从工程怎么获取、打开之后长什么样开始说保证你照着做就能把硬件侧的中断通路打通为后面写Linux驱动或裸机中断服务例程打好基础。1. 动手前的脑图一帧图看穿HPS响应FPGA中断的完整链路1.1 中断是怎么从FPGA逻辑跑到HPS的很多第一次接触SoC FPGA的人会有个误区以为FPGA端给HPS发中断就像MCU的GPIO中断一样找个引脚拉到HPS的某个中断脚就行。实际上在Agilex 5这类SoC FPGA里FPGA fabric和HPS不是两颗芯片而是一个封装里的两个部分它们之间的物理连接是芯片内部的专用总线不需要经过外部引脚。中断信号走的是HPS的FPGA-to-HPS接口里的一组专用信号名字就叫f2h_irq。这一组信号在芯片内部直接连到HPS的GICGeneric Interrupt Controller通用中断控制器上。GIC是整个HPS中断体系的中枢CPU核本身不直接管外设中断所有中断都先进GICGIC再根据优先级、使能状态决定要不要把中断发给哪个核。所以你在硬件侧要做的核心工作就是让FPGA逻辑里的某个中断请求信号最终出现在f2h_irq这根线上并且让GIC那边对应中断的SPI号是有效且匹配的。GIC里的中断类型分三种——SGI软件触发中断、PPI私有外设中断每个核独享、SPI共享外设中断可以路由到任意核。FPGA到HPS的中断f2h_irq走的正是SPI。每一个f2h_irq信号都会对应GIC里的一个SPI中断号比如有的SoC里f2h_irq0对应SPI 97f2h_irq1对应SPI 98具体编号不同型号略有差异。这个编号在后续写设备树、写驱动时都要用到所以硬件侧配置时就得心里有数。1.2 GHRD工程是什么、为什么要拿它当起点GHRD全称是Golden Hardware Reference Design翻译过来就是“黄金硬件参考设计”听起来很玄乎其实它就是Intel官方为每一款SoC FPGA开发板提供的一份可以直接编译、可以直接跑到板子上的Quartus工程。里面已经把HPS的引脚复用、DDR控制器参数、启动配置、时钟树、外设接口都按开发板的实际情况配好了你拿到手直接编一版烧进去Linux就能启动起来。讲道理如果你的板子就是官方开发板那GHRD就是最靠谱的起点。因为SoC FPGA的HPS配置是一个非常繁琐的过程DDR的时序参数、引脚分配的bank电压、启动模式的选择任何一项搞错轻则起不来重则把板子搞得不稳定。而GHRD把这些脏活累活都提前干完了你要做的只是在这个基础上按需修改而不是从零开始建一个HPS子系统。有人可能会问那我自己从头搭一个Platform Designer系统行不行答案是行但没必要。你想啊HPS子系统里有上百个寄存器、几十个外设接口还有DDR控制器需要根据具体DDR颗粒型号做初始化配置这些光靠看手册就要看很久而且自己搭出来的系统大概率在某些隐性细节上漏掉东西。GHRD是官方验证过的哪怕你最终产品要裁剪掉很多功能也建议在GHRD基础上删减而不是从空白工程开始。1.3 本篇要改的到底是什么一句话总结把整个目标拆到最简单的表述我们要在GHRD工程里把Platform Designer以前叫Qsys中HPS IP核的FPGA-to-HPS中断数量配置从默认的0改成我们需要的数值比如1或4然后在FPGA侧生成一个能产生中断信号的组件最简单的是PIO IP核把这个组件的irq输出连接到HPS的f2h_irq0上最后重新生成、重新编译Quartus工程。就这么一件事。但这件事做完之后你获得的是一个硬生生从FPGA到HPS CPU的中断通路。之后你在FPGA逻辑里写一个小模块检测到某个事件就拉高f2h_irq0HPS端的GIC就能收到中断CPU就能跳到中断服务函数里处理。为了验证通路我们甚至可以先不做复杂逻辑直接用一个按键或者一个拨码开关接到PIO上HPS端裸机轮询一下状态或者Linux下挂个中断驱动按一次按键就打印一条信息。2. 环境准备与GHRD工程的正确获取姿势2.1 Agilex 5开发应该用哪个Quartus版本先说工具链。Agilex 5是Intel较新的SoC FPGA系列器件家族比较新所以对Quartus版本有硬性要求——老版本根本认不出这颗芯片。我建议直接上Quartus Prime Pro的最新版本至少是24.1以上因为GHRD工程本身也是跟随新版本发布的版本太旧可能打不开工程或者生成的handoff文件不匹配。这里有个容易被新手忽略的点Agilex 5要用的是Pro版本不是Standard或Lite版本。Pro和Lite的界面、器件支持、Platform Designer版本都有差异。你如果电脑上装的是Lite版就算版本号再新也找不到Agilex 5的器件型号。装好后在Quartus主界面的Device Family里应该能看到Agilex 5的相关系列如果没有多半就是版本装错了或者license有问题。安装Quartus Prime Pro没什么特别要说的跟着向导走就行。唯一要提醒的是它体积很大完整安装可能要占用几十GB磁盘空间建议装在固态硬盘上工程编译的速度能快不少。另外Agilex 5的编译还需要额外安装对应的器件支持包Device Support安装器会提示你勾选别漏了。2.2 从GitHub拉取GHRD工程GHRD工程的获取方式主要是从Intel的GitHub官方仓库拉取。Agilex 5对应的GHRD仓库一般在github.com/intel下仓库名通常包含agilex5和ghrd关键字。你在命令行里用git clone把它拉下来就行。如果你在公司内网或者访问GitHub比较慢也可以直接下载zip压缩包效果一样。拉下来之后解压你会看到典型的Quartus工程结构顶层是.qpf文件Quartus Project File旁边是.qsf文件Quartus Settings File还有sdc时序约束文件、Platform Designer的系统文件.qsys、以及软件相关的文件。注意GHRD工程里往往不只是Quartus工程还带着uboot源码、Linux内核补丁、设备树源文件这些软件部分因为官方希望给你一个“开箱即用”的完整参考。在动手修改之前建议你先不要急着双击打开工程而是花几分钟把目录结构看一遍。我自己的习惯是打开README文件GHRD仓库里的README通常会写清楚这个工程对应的开发板型号、Quartus版本要求、编译步骤、如何生成handoff、如何编译uboot和内核。读完README能帮你避免很多版本不匹配的问题。2.3 打开工程前先确认三件事在双击.qpf打开Quartus工程之前有三件事值得先确认不然可能白忙活大半天。第一确认工程对应的开发板型号。GHRD通常会针对特定的开发板比如Agilex 5 DK系列。如果你手里的板子不是官方开发板直接编译GHRD大概率会出问题至少引脚分配是对不上的。非官方板卡建议找板卡厂商要对应的BSP和参考工程。第二确认Quartus版本。打开工程的时候Quartus会提示“这个工程是用XX版本创建的是否要迁移到当前版本”如果版本跨度太大迁移过程中可能出现IP核版本不兼容、Platform Designer组件缺失等问题。我的经验是尽量用相近版本打开别用太老的工程硬顶新版本。第三确认工程里有没有包含Platform Designer系统文件。GHRD工程中的.qsys文件是整个HPS子系统的核心后续我们要在Platform Designer里改的就是它。打开Quartus工程后在Project Navigator里应该能看到一个或多个.qsys条目双击就能进入Platform Designer图形界面。3. 核心操作在Platform Designer里打通f2h_irq通道3.1 进入HPS配置向导开启F2H中断打开Platform Designer之后你会看到一个系统拓扑图GHRD工程里的HPS IP核通常已经放在了里面名字可能叫hps_0或者类似的名字。双击这个HPS组件会弹出HPS配置向导。这个向导左边是一系列配置页签包括FPGA Interfaces、Peripherals、PLL、DDR等。我们要找的是FPGA Interfaces这一页里面有各种FPGA和HPS之间的接口开关比如FPGA-to-HPS AXI总线接口、HPS-to-FPGA AXI总线接口、轻量级HPS-to-FPGA接口还有我们今天的主角——Interrupts相关配置。在Interrupts配置区域你会看到F2H Interrupt的选项可能是一个数字输入框让你填需要几个中断或者是一组复选框让你勾选具体的f2h_irq信号。把数量从0改成1或者勾选Interrupt 0然后点击Finish或OK保存。这一步做完Platform Designer主界面里的HPS组件会多出几个引脚名称类似f2h_irq0。这个信号现在还是悬空的下一步我们要让FPGA侧的某个中断源连到它上面。3.2 配置PIO作为中断源在Platform Designer里添加一个PIOParallel I/OIP核这是最直接的中断源。名字可以改成irq_pio或者pio_in方向设置为Input位宽设为1这样它只有一根输入线。PIO本身是一个很轻量的组件适合用来做演示、按键输入、LED控制这类简单场景它也自带中断输出非常适合我们现在验证中断通路。在PIO的配置界面里有一项是Interrupt我们需要设置它的触发方式。PIO支持多种中断触发模式上升沿触发也就是输入从0变1的那一瞬间产生中断。下降沿触发输入从1变0的瞬间产生中断。任意边沿触发不管是升还是降都产生中断。电平触发比如高电平持续期间一直产生中断实际上电平触发通常是高或低电平有效。演示场景下我一般选任意边沿触发简单省事。后面接一个按键每按一下不管按下还是松开都有中断调试起来最直观。配置好PIO之后注意看它的时钟和复位接口。PIO的s_clock和s_reset必须连接到系统时钟和复位网络上而且最好和HPS域的时钟一致不然会有跨时钟域问题。GHRD工程里通常已经有现成的时钟和复位管理器你把PIO的时钟连过去就行。3.3 连接中断信号并Validate现在Platform Designer的系统图里多了两个东西一个HPS组件带着f2h_irq0引脚一个PIO组件带着irq输出引脚。下一步就是用连线把PIO的irq输出接到HPS的f2h_irq0上。在Platform Designer里中断信号的连线方式有两种常见情况。如果你的系统里有一个interrupt_requester这样的桥接组件那PIO的中断可能要先进这个桥再统一连到HPS的中断口。如果系统比较简单你可以直接尝试把PIO的irq连到f2h_irq0。实际操作的时候点一下PIO的irq引脚拖一条线到hps的f2h_irq0引脚即可。连好之后点击Platform Designer右下角的Validate按钮。这一步会检查整个系统的连接完整性、时钟复位是否正确、有没有遗漏的接口。Validate通过是底线如果报错按提示修好再继续。常见的Validate报错有irq引脚悬空说明你还没连中断线。时钟未连接说明PIO的s_clock没接。中断优先级冲突说明多个中断源接到了一个中断号上。3.4 重新生成HDL这一步发生了什么Validate通过后接下来是Generate环节也就是重新生成HDL。这一步会把你配置好的Platform Designer系统生成成Verilog或VHDL代码并更新相关IP核的仿真模型和SDK文件。在Platform Designer菜单里找到Generate选择Generate HDL...弹窗里可以选生成语言默认Verilog就行、输出目录等。点击Generate工具会跑一段时间过程类似Quartus的分析综合。跑完后会提示生成成功。这一步很多人会忽略它的意义觉得就是个Build动作。但其实它至关重要Platform Designer把你的图形化配置翻译成了真实的硬件描述包括中断信号是怎么连的、地址是怎么分配的、寄存器是怎么映射的全都在这一步固化下来。如果这一步没做哪怕你在Platform Designer里画得再完美底层RTL代码还是旧的编译出来的bitstream也不会包含中断通路。生成完之后回到Quartus主界面你会发现工程里的.qsys条目已经更新相关的HDL文件也重新生成好了。接下来就可以进入全流程编译。4. 全流程编译从RTL到bitstream/sof4.1 Quartus编译四部曲Quartus的完整编译流程可以拆成四个阶段Analysis Synthesis、Fitter、Assembler、Timing Analysis。在Quartus Prime Pro里你可以直接点工具栏上的Start Compilation一键跑完这四个阶段也可以分阶段跑方便定位问题。Analysis Synthesis阶段Quartus会把你写的RTL代码和Platform Designer生成的HDL综合成网表同时做语法检查。这个阶段报错最常见的就是语法错误、模块例化错误、信号位宽不匹配。如果GHRD工程本身是完整的你只是加了PIO和连线这个阶段一般不会出问题但如果你手动改过顶层RTL就要多留意。Fitter阶段是布局布线把网表里的逻辑单元映射到FPGA的实际逻辑单元和布线资源上。这个阶段耗时最长对Agilex 5这种规模不小的芯片来说跑个十几分钟到半小时都是正常的。Fitter阶段如果报错常见原因是资源不足、引脚冲突、时序约束不满足。GHRD工程自带时序约束sdc文件正常改的话不太会触发新的时序问题。Assembler阶段生成最终的配置文件也就是.sof文件SRAM Object File这个文件直接用来烧写FPGA的SRAM配置也可以转成其他格式用于烧写配置芯片。到了这一步说明编译已经基本成功了。4.2 编译常见报错与排查我实际编译GHRD工程时遇到过几个典型问题整理成一张表方便你对照排查。报错现象可能原因排查思路器件型号不匹配Quartus版本太旧不认识Agilex 5器件换用Quartus Prime Pro 24.1以上版本IP核版本不兼容工程迁移时旧IP核没有升级在Platform Designer里重新生成所有IP核或手动执行IP Upgrade引脚约束冲突新加的PIO信号被分配到了已有管教检查.qsf里有没有额外的引脚分配新信号保持自动分配即可Fitter资源不足工程逻辑量接近芯片上限检查是不是误开了很多调试逻辑或者限制了LogicLock区域时序违规新加的PIO时钟约束没跟上查看Timing Report确认PIO相关路径的时钟约束是否存在生成handoff失败Platform Designer生成不完全回到Platform Designer重新Validate Generate确保无警告这里要特别提醒一下如果你在Platform Designer里只是加了PIO、连了中断线其他什么都没动但编译却报出了一堆时序违规问题先别急着怀疑新加的逻辑。GHRD工程有时候在特定Quartus版本下本身就会有一些轻微的时序告警只要不是Critical Warning且影响到了关键路径一般不影响使用。你可以先看编译报告里的Fmax和关键路径延迟心里有个底。5. 编译完成后handoff、设备树与中断号的衔接5.1 生成handoffLinux启动加载的第一步Quartus编译成功生成的.sof文件只是FPGA侧的配置但SoC FPGA的系统里HPS是独立于FPGA的处理器它需要一套软件配置才能跑起来。这套软件配置的源头就是handoff文件。在Quartus的菜单里找到Generate HPS handoff或类似的选项不同版本位置略有差异它会把HPS的初始化配置、DDR参数、引脚复用信息打包导出供SoC EDSEmbedded Design Suite里的工具链生成uboot、ATFARM Trusted Firmware等启动组件。如果你用的是较新的SoC EDS或命令行工具handoff文件的后续处理步骤跟老型号类似。生成handoff之后整个Quartus侧的工作才算真正闭环。没有handoff你就算烧了.sofHPS也可能因为DDR初始化参数不对而无法引导Linux。GHRD工程默认的handoff流程是配套的只要你在Platform Designer里改了HPS配置生成handoff时就会带上新的中断配置信息。5.2 设备树里interrupts属性怎么填如果你跑的是Linux那么设备树里必须描述清楚这个中断源内核驱动才能正确申请中断。设备树里描述中断的核心属性是interrupts格式通常是三个数值中断类型、中断号、触发类型。对FPGA到HPS的中断来说中断类型一般是GIC的SPI在设备树里通常用0表示也有的是1要看具体binding文档SOCFPGA系列一般是0或GIC_SPI代表SPI中断。中断号就是你之前查到的那个SPI编号比如f2h_irq0对应多少号。触发类型要跟你硬件配置里的PIO触发方式对应如果是上升沿触发这里就写IRQ_TYPE_EDGE_RISING数值4如果是高电平触发就写IRQ_TYPE_LEVEL_HIGH数值4。设备树里写中断通常还需要一个interrupt-parent属性指向GIC节点的phandle。GHRD工程配套的设备树文件里GIC节点已经定义好了你只要在你的PIO设备节点上添加interrupt-parent和interrupts属性即可。例如irq_pio: gpio10000040 { compatible snps,dw-apb-gpio; interrupt-parent intc; interrupts 0 0 4; ... };注意这里的SPI中断号0只是示意实际要填什么必须根据你用的SoC型号查对应手册或设备树源文件。别照抄网上的例子不同型号的中断号映射不一样填错了驱动申请中断的时候会报错。我自己调试时最常用的办法是先编译一版设备树跑起来在Linux下查看/proc/interrupts那里会列出所有已注册的中断。你可以对照硬件设计文档确认f2h_irq0对应的中断号出现在列表里没有。这比对着手册猜要快得多。5.3 验证中断是否真的通了到这里硬件侧的工作基本完成下一步就是验证了。最简单的方式是烧写.sof文件到FPGA启动Linux然后在设备树里把中断配置好、加载驱动或者用一些现成的工具直接看中断计数。在Linux环境下如果你已经把中断号对应到了一个驱动节点上可以通过下面这种方式快速验证cat /proc/interrupts查看对应中断号的计数是否一直在增加。如果每次按动按键或触发FPGA逻辑事件计数都在增加说明中断通路完全是通的——FPGA发出中断、GIC收到中断、CPU响应中断、驱动处理中断整个链路跑通了。如果计数不增加问题可能出在以下几个环节FPGA逻辑没有真正拉高f2h_irq信号可以用Signal Tap或示波器查一下。设备树中断号配置不对GIC收到了但内核不知道哪个驱动处理。中断被其他驱动屏蔽或共享冲突检查内核日志有没有相关报错。6. 一些经验之谈硬件侧改动值得避开的弯路整个GHRD工程改下来说难真不难但有几个地方容易让人卡住。我按踩坑频率从高到低给大家排个序。第一不要忽略时钟域。PIO和HPS的f2h_irq接口如果不在同一个时钟域理论上是需要通过同步器处理的。GHRD工程里如果系统比较干净PIO直接挂在HPS域时钟下问题不大但如果你在FPGA逻辑里自己写了一个模块跑在另一个时钟域直接连到f2h_irq上就很容易出现中断丢失、毛刺的问题。最好的做法是让中断信号在进入f2h_irq之前做一次双触发器同步或者直接用PIO这类自带同步的IP核。第二中断触发器类型要和设备树保持一致。很多人在Platform Designer里配的是上升沿触发设备树里却写了电平触发结果中断要么一直触发停不下来要么完全不触发。这个一致性检查应该放在排查第一步。第三f2h_irq和h2f_irq别搞混。GHRD里可能既有FPGA-to-HPS中断f2h也有HPS-to-FPGA中断h2f方向完全相反。我们要的是f2h也就是FPGA发往HPS的中断。连线的时候看图仔细一点别连着连着连到h2f上了。第四GHRD工程里默认的设备树、uboot配置不一定马上支持新加的中断功能有些配置文件是固定写在源码里的。你可能需要在编译内核时打开对应的配置选项或者手动修改设备树编译脚本。这个偏软件侧我会在下一篇详细展开但是你要有心理准备硬件改完不等于整个链路通了软件侧还有一截路要走。第五保存版本。改GHRD工程前建议先复制一份原始工程或者用git把原始配置提交一下这样万一改坏了可以快速回退。Platform Designer的改动不像代码一样容易看出差异有版本控制心里踏实得多。我个人在实际操作中的体会是SoC FPGA的硬件配置修改其实不复杂真正花时间的反而是理解和验证整个中断链路。只要你在Platform Designer里把f2h_irq通路配通Quartus编译通过handoff生成成功后面无论是裸机还是Linux都只是在这个硬件基础上写软件的事。最后再分享一个小技巧改完GHRD工程后先别急着写复杂逻辑用PIO加一个按键验证中断通路往往能最快定位问题的根源在硬件还是软件。