0
收藏
微博
微信
复制链接

复位电路处理不当,异步复位释放时的亚稳态谁管

2026-05-26 16:27
6

做FPGA设计,复位电路几乎每个工程都会用到。很多人觉得复位嘛,不就是给个低电平或者高电平把寄存器清零?写代码的时候加个if(rst)就完事了。但真到了板子调试阶段,随机出现的死机、状态机跑飞、数据通路错乱,追来追去发现根子出在复位释放那一刻——亚稳态把系统坑了。

这个问题说实话不算新鲜,但踩坑的人还是一茬接一茬。今天就把异步复位释放时亚稳态这个事掰扯清楚,顺便给几个靠谱的解决思路。

一、异步复位为什么容易出亚稳态

异步复位最大的问题在于:复位释放(也就是rst从有效变无效的那个沿)跟时钟沿之间没有任何固定的时间关系。如果复位释放的时刻刚好落在时钟沿附近的建立/保持时间窗口内,触发器就进入了亚稳态——输出既不是0也不是1,而是卡在中间一个不确定的电平上,而且这个状态持续多久谁也说不准。

这跟异步复位的"进入"不一样。复位有效的时候,不管时钟什么状态,触发器都会被强制拉到已知状态,这个没问题。问题出在"离开"复位的那一刻——释放沿跟时钟沿撞上了。

cddecb788162c1a1a3bb99c19079d4.png

亚稳态的后果看具体场景。如果只是某个数据寄存器抖了一下,可能就是一帧数据出错;但如果复位释放时状态机的寄存器进了亚稳态,那状态机可能跳到一个非法状态,整个系统就卡死了。更麻烦的是,这种问题是随机的,复现概率低,排查起来很头疼。

二、异步复位同步释放——最经典的解决方案

这个方案的核心思路很简单:异步复位、同步释放。也就是说,复位进入的时候仍然是异步的(保证及时响应),但释放的时候要跟时钟同步,避免释放沿落在时钟的建立保持窗口里。

实现方式通常用一个两三级的触发器链来同步复位释放信号:

always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rst_sync1 <= 1'b0; rst_sync2 <= 1'b0; end else begin rst_sync1 <= 1'b1; rst_sync2 <= rst_sync1; end end // 用 rst_sync2 作为系统复位信号

第一级触发器可能进亚稳态,但经过一两个时钟周期的"沉淀"之后,第二级或第三级触发器的输出基本稳定了。两级同步能解决大部分场景,如果是高可靠性设计,可以加到三级。

ed1a392000e046b1d24dede6939649.png

三、几个容易被忽略的细节1. 同步后的复位仍然是异步复位

有个常见的误解,以为用了同步释放电路之后,整个系统就变成同步复位了。其实不是。rst_sync2对下游逻辑来说,仍然是一个异步复位信号——只不过它的释放沿已经跟时钟对齐了。所以下游寄存器的always块里,还是要写成异步复位的写法(posedge clk or negedge rst_sync2)。

2. 复位网络的扇出问题

同步释放电路输出的rst_sync2要接到系统中所有需要复位的寄存器上。在大设计中,这个信号的扇出可能非常大,导致布线延迟不一致——有的寄存器先收到释放,有的后收到,这就相当于不同的模块在不同时刻退出了复位状态。

解决这个问题的办法是插入BUF或者用多个同步器分别驱动不同模块的复位。FPGA厂商一般也会提供专门的BUFG资源来处理高扇出复位信号。

3. 上电复位和热复位的区别

上电时FPGA内部有个全局的初始化过程(GSR),所有寄存器都会被初始化到指定值,这个是FPGA架构保证的。但热复位(运行中拉低rst_n再释放)就不一样了,没有GSR帮你兜底,完全靠你的复位逻辑。所以热复位场景下,异步复位同步释放电路就更关键了。

f465678025ae893e0cf43fda0e6235.png

四、还有别的方案吗

如果你的设计对复位没有严格要求——比如所有寄存器都有确定初始值、状态机用了独热编码且有非法状态恢复逻辑——那完全不用异步复位也行,纯同步复位或者干脆不复位。Xilinx和Intel的FPGA都支持寄存器初始化,很多简单设计确实不需要额外的复位信号。

但如果你的设计里有时序要求严格的控制逻辑、需要快速响应外部复位请求,那异步复位同步释放还是最稳妥的选择。

有个经验可以分享:做项目的时候,把复位策略想清楚再动手写代码。别等到调试阶段才发现复位有问题,那时候排查的成本比设计阶段加个同步器高太多了。

登录后查看更多
0
评论 0
收藏
侵权举报
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表凡亿课堂立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。

热门评论0

相关文章

开班信息