危险的未分配引脚(FPGA)

本文讲述了在FPGA设计过程中遇到的问题及解决过程,重点分析了未分配引脚导致系统崩溃的原因,强调了合理约束引脚的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一波三折——危险的“未分配”引脚 


    第一折。半个月前,美国的同事对当前的一个工程进行了编译,并提交二进制文件(FPGA配置文件)给软件工程师进行集成。结果该二进制文件导致了整个系统的崩溃:FPGA二进制文件刚下载完毕,整个系统就不工作了。这一事件导致了美国FPGA工程师一整天的停工和系统恢复。Kevin给出的分析结果是,FPGA给出的中断信号有问题,该信号经过CPLD转发到CPU后导致CPU反复跳入中断,造成系统崩溃。后来,因为经过重新编译的二进制文件没有引发类似现象,该问题就被当作是一个偶然事件被忽略了。 riple 



    第二折。上周的某一天,在我们这边,类似的现象“终于”也发生了。由于时差的关系,我们没能得到美国软件工程师的及时支持。眼瞅着手上仅有的两个系统陷入瘫痪,工作不能继续,没办法,只能自己硬着头皮调试一下看看。系统崩溃后,嵌入式Linux操作系统的响应异常缓慢,通过网络登陆无法进行调试和控制。幸好还有串口调试台,通过串口可以看到系统反复打印出对总线上特定地址范围的数据写入失败。由于该现象发生在FPGA文件下载完成后,我通过在系统启动后FPGA下载前杀掉相关进程的方法阻止了系统的崩溃:只要不下载FPGA文件,或者替换为旧文件,系统就不会崩溃。 riple 

    接下来,我试图找出FPGA引发系统崩溃的原因。中断信号引发系统崩溃的说法首先被排除了,原因是FPGA的中断产生逻辑电路相当标准,不可能产生随机的错误行为。问题缩小到FPGA连接到CPU的双向数据总线上,这里是除中断外唯一一个由FPGA驱动到CPU的逻辑电路。我的推论是,由于该FPGA工程没有对CPU相关的输入输出引脚进行时序约束,两次编译会导致双向数据总线的输出使能信号的响应差异,这一差异进一步影响了FPGA驱动双向数据总线的速度差异,在某些情况下,FPGA或早或晚地驱动了总线,引发了总线驱动冲突,导致CPU对总线上其它设备的访问失败。经过对所有CPU相关的信号进行时序约束后,编译的二进制文件没有引发系统崩溃。 riple 



    第三折。问题并没有这样得到解决。两天后,在又一次对该工程进行编译后,一模一样的问题又出现了。去除我先前给工程施加的时序约束后,问题反而没有了。不加约束会错,加了约束也会错,看来约束并没有作用到问题的本质上。唯一可以得到确认的结论是:两次FPGA编译的结果是有差异的,特定电路的编译结果并没有得到时序约束的有效控制;问题随机出现,但是表现一致。 riple 

    这一次,为了定位导致问题的具体逻辑电路,我必须对出问题的编译结果进行分析和实验。二进制文件是最终的编译结果,时序分析报告也是编译结果,但是这两个结果要么不可分析,要么包含了太多的信息而无法分析。我唯一可以进行分析和实验的对象就是布局布线(P&R)之后的底层网表数据。 riple 

    通过RTL视图,我逐个定位了CPU相关引脚在Chip Planner视图中的位置。通过在Resource Property Editor中修改特定LE的对外连接和内部逻辑关系,我把所有可能驱动CPU的相关逻辑都关闭了:中断信号被禁止了,双向数据总线的使能被禁止了。通过执行Check & Save All Netlist Changes,我在不影响所有其他逻辑的功能和时序特性的情况下,得到了一个完全不会驱动CPU总线相关信号的FPGA二进制文件。出乎意料的是,该二进制文件下载后,系统依然崩溃。 riple 



    到了这一步,我找遍了“路灯下所有能找的地方”,只能向其他方向“胡乱”摸索了。我尝试了给来自CPU的控制输入信号,包括所有的地址线,增加上拉电阻的方法,也没有成功。 riple 

    经过了类似的一系列摸索,最终我在Pin Planner视图中发现了蹊跷:在该工程中竟然存在没有分配布局位置的输出引脚,而这些输出引脚在该项目中并没有被实际的输入逻辑驱动,这些引脚被Analysis & Synthesis工具缺省地连接到了逻辑“0”上。通过比较成功和失败两次编译结果中给出的最终引脚分配报告,我发现,这些没有得到位置约束的引脚竟然可能随机出现在任意的空闲引脚上。 riple 

    通过进一步分析,在导致系统崩溃的编译结果中我最终找到了答案:一个没有逻辑驱动,也忘了分配布局位置的输出引脚被Fitter工具随机分配到了FPGA没有用到(也没有位置约束)的一根CPU地址输入线上,这根地址线就被短路到了“0”电平上,进而导致CPU外部总线上特定地址范围不能被CPU访问到,最终引发了系统崩溃。 riple 



    通过这一问题的解决,我获得了以下几点认识: riple 

1. 没有约束位置的引脚是很危险的,尤其是输出引脚。随机分配的结果很可能是灾难性的。所以,PCB原理图上的所有引脚,即使在FPGA内部没有被用到,也最好如实地加以约束。 riple 

2. Quartus II提供的ECO工具,即“增量式布局布线后网表修改功能”非常好用。既保留了上一次的全编译结果,还缩短了编译时间。用来做快速实验(quick and dirty)最合适不过了。 riple 

3. Resource Property Editor中对输出使能信号的控制方法。(乍看起来,逻辑上的连接与示意图上的连接正好相反,其实不然。需要注意。) riple 

4. 为什么会存在未分配的输出和输入引脚?这是因为该工程还存在尚未实现的后期功能。这些引脚就是给以后开发留下的,由于我们太专注于眼前要实现的功能而被忽视了。 riple 

5. 为什么会存在未用到,却实际连接了的地址线?这是PCB设计上的“冗余设计”。这样的冗余设计在该项目中还有很多,有一些还真在关键时刻给了我们FPGA开发上的便利。 riple 

6. 既然上述两个问题都有合理的解释,为什么还会出现这么不合理的错误?原因之一是在PCB和FPGA设计上缺乏完善的设计文档,PCB设计者的意图没有有效传达给FPGA设计者,而FPGA设计者之间也没能充分交流。原因之二是FPGA开发流程上缺乏被称之为“Peer Review”的设计评审和设计质量保证措施,一个显而易见的错误就被这样忽略并遗留了下来。 riple
<think>嗯,用户遇到了Vivado仿真没问题,但上板后数据变化的情况。这个问题可能有很多原因,我需要一步步梳理可能的问题点,帮助用户排查。 首先,仿真和实际硬件运行的环境同。仿真可能没有考虑时序问题,比如时钟信号的抖动或者偏移。实际硬件中,如果时序约束正确,可能导致建立或保持时间违规,数据无法正确锁存。这时候需要检查时序报告,看是否有违例,尤其是跨时钟域的部分。 然后,时钟和复位信号的问题。硬件上的时钟可能没有正确连接,比如时钟引脚分配错误,或者频率设置对。复位信号方面,如果复位是异步的,但正确处理,或者复位释放的时机对,可能导致模块无法正常初始化。 接着是引脚约束的问题。用户的I/O引脚分配是否正确?电压标准是否匹配?比如,某个引脚配置成了3.3V LVCMOS,但外设是1.8V的话,信号可能无法正确传输。另外,使用的引脚如果正确设置,可能会引入噪声干扰。 硬件连接问题也能忽视。需要检查FPGA的供电是否稳定,JTAG下载是否可靠,外设的连接是否牢固。有时候接触良会导致信号无法传输,或者电源波动影响电路稳定性。 跨时钟域处理方面,如果设计中存在多个时钟域,而异步信号没有同步处理,比如使用两级触发器,可能会导致亚稳态,数据无法更新。这时候需要检查跨时钟域的信号是否做了同步处理。 代码中的可综合语句也是一个可能点。仿真能通过,但有些语句无法综合成实际电路,比如某些延迟语句或初始化块。需要检查代码是否全部可综合,尤其是组合逻辑是否形成了锁存器,导致数据锁死。 调试手段方面,建议用户使用ILA(Integrated Logic Analyzer)插入探针,实时抓取信号,观察数据路径中的问题。比较仿真波形和实际抓取的波形,找出差异点。 此外,还可以检查编译选项,比如优化设置是否过于激进,导致关键逻辑被优化掉。或者版本兼容性问题,某些IP核在同版本中的行为可能同,需要确认版本匹配。 还有可能是硬件本身的故障,比如FPGA芯片损坏,或者外部元件有问题。这时候可以尝试更换硬件或测试其他功能来排除。 总结下来,需要从时序、时钟复位、引脚约束、硬件连接、跨时钟域、代码综合、调试工具等多个方面逐一排查。用户可能需要结合具体的设计和硬件环境,逐步缩小问题范围,找到根本原因。</think>在FPGA开发中,仿真通过但上板异常是常见问题,以下是系统性排查思路和解决方案: --- ### 一、时序问题(最常见原因) 1. **建立/保持时间违例** - 现象:数据在时钟边沿附近变化 - 检查方法: ```tcl report_timing_summary -delay_type min_max ``` - 解决方案: - 增加时序约束 - 降低时钟频率验证 - 插入流水寄存器 2. **跨时钟域问题** - 典型错误:使用同步器 - 正确实现: ```verilog always @(posedge clk_B) begin sync_reg1 <= async_signal; sync_reg2 <= sync_reg1; // 两级同步 end ``` --- ### 二、硬件配置问题 #### 引脚约束排查 1. 检查`.xdc`文件: ```tcl set_property PACKAGE_PIN "Y4" [get_ports {data_in}] set_property IOSTANDARD LVCMOS33 [get_ports {data_in}] ``` - 确认电压标准匹配外设 - 验证引脚复用功能配置 2. **使用引脚处理**: ```tcl set_property BITSTREAM.CONFIG.UNUSEDPIN Pullnone [current_design] ``` --- ### 三、时钟与复位问题 1. **时钟有效性验证** - 使用ILA抓取时钟信号 - 测量实际时钟频率 2. **复位问题排查** - 异步复位同步释放电路: ```verilog always @(posedge clk, posedge ext_rst) begin if(ext_rst) begin rst_sync1 <= 1'b1; rst_sync2 <= 1'b1; end else begin rst_sync1 <= 1'b0; rst_sync2 <= rst_sync1; end end ``` --- ### 四、硬件电路问题 1. **电源完整性检查** - 测量核心电压纹波(应 < ±5%) - 检查去耦电容布局 2. **信号完整性验证** - 使用示波器观测关键信号 - 检查阻抗匹配(特别是高速信号) --- ### 五、代码陷阱排查 1. **锁存器生成** ```verilog // 危险代码示例(生成锁存器) always @(*) begin if(en) q = d; } ``` 2. **可综合结构** - 避免使用`initial`块初始化寄存器 - 替换`#delay`等仿真专用语法 --- ### 六、调试方法 1. **ILA核心插入** ```tcl create_debug_core u_ila ila set_property C_DATA_DEPTH 1024 [get_debug_cores u_ila] ``` 2. **分段验证策略** - 从最小系统逐步添加功能 - 用LED/IO输出中间状态 --- ### 七、典型案例分析 **案例:SPI接口数据锁存失败** - 仿真表现:正确传输128bit数据 - 硬件现象:最后32bit丢失 - 根本原因: - 跨时钟域同步`busy`信号 - 实际传播延迟导致状态机提前跳转 - 解决方案:增加握手协议 --- ### 八、检查清单 1. [ ] 时序报告无违例 2. [ ] 时钟频率匹配硬件能力 3. [ ] 复位信号已同步处理 4. [ ] 所有端口已正确约束 5. [ ] 无组合逻辑环路 6. [ ] 电源纹波在允许范围内 通过以上步骤系统性排查,可解决90%以上的仿真/实测一致问题。建议优先检查时序约束和跨时钟域处理,这两个是导致数据锁存失败的最常见原因。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值