FPGA复位的正确打开方式

本文探讨了FPGA复位的必要性,分析了同步复位与异步复位的优缺点,推荐了异步复位同步释放的方式,并讨论了高复位与低复位的选择。同时,详细介绍了复位电路的映射方法和上电延时的重要性。
摘要由CSDN通过智能技术生成


在没看这篇文章前,回想一下平时我们常用的复位方式:
① 首先,上电后肯定是要复位一下,不然仿真时会出现没有初值的情况;
② 最好有个复位的按键,在调试时按一下复位键就可以全局复位了;
③ 也许是同步复位,也许是异步复位,不同的工程师可能有不同的方案。
但如果认真看了Xilinx的White Paper,就会对复位有了新的认识。
我们把White Paper的内容总结为下面4个问题:
① 需不需要复位?
② 同步复位 or 异步复位?
③ 高复位 or 低复位?
④ 全局复位 or 局部复位?怎么用?

1. 需不需要复位?

看到这个问题,可能很多同学会有点懵,怎么可能不需要复位?其实Xilinx FPGA在系统上电配置时,会有一个GSR(Global Set/Reset)的信号,这个信号有以下几个特点:
• 预布线
• 高扇出
• 可靠的
这个信号可初始化所有的cell,包括所有的Flip-Flop和BRAM。
在这里插入图片描述如果我们在程序里用自己生成的复位信号,也只能复位Flip-Flop。
这个GSR信号我们可以在程序中通过实例化STARTUP直接调用,但Xilinx并不推荐这么使用。
在这里插入图片描述

主要原因是FPGA会把像系统复位这种高扇出的信号放到高速布线资源上,这比使用GSR要快,而且更容易进行时序分析。
虽然有GSR,但这并不是说要避免使用复位信号,以下两种情况就必须要加复位:

  • 带有反馈的模块,比如IIR这种滤波器和状态机,当状态跑飞了,就需要复位一下
    在这里插入图片描述
  • 应用过程中需要复位的寄存器

这个就具体看是什么应用了,我们公司的很多寄存器都需要在调试过程中需要经常复位,像这种复位就是必须的了。
所以,需不需要复位完全看设计。这里多提一点,时序收敛也是一样,主要看设计,而不是约束。

2. 同步复位 or 异步复位?

在这里插入图片描述在这里插入图片描述

module rst_demo(
 input clk,
 input rst1,
 input rst2,
 input in1,
 input in2,
 output reg out1,
 output reg out2);

 always @ ( posedge clk )
 begin
    if(rst1)
        out1 <= 1'b0;
    else
        out1 <= in1;
 end

 always @ ( posedge clk or posedge rst2 )
 begin
    if(rst2)
        out2 <= 1'b0;
    else
        out2 <= in2;
 end

 endmodule

在这里插入图片描述------------
前面我们也讲到然同步复位和异步复位都多多少少有些问题,那有没有一种方式可以结合同步复位和异步复位的优点?当然有,就是异步复位,同步释放。这种方法可以将两者结合起来,取长补短。如下图所示,所谓异步复位,就是输入的复位信号仍然是异步的,这样可以保证复位信号能够起效;而同步释放是指当复位信号释放时,输出的sys_rst并不是立即变化,而且被FF延迟了一个时钟周期,这样让复位和时钟同步起来。
在这里插入图片描述图中的Verilog代码如下:

module rst_demo(
 input      clk,
 input      rst_async,
 (* keep = "true" *)
 output  reg  rst_module1 = 0,
 (* keep = "true" *)
 output  reg  rst_module2 = 0
    );

reg         sys_rst;
reg         rst_r;

always @(posedge clk or posedge rst_async) begin
    if (rst_async) begin
        rst_r <= 1'b1;
    end
    else begin
        rst_r <= 1'b0;
    end
end

always @(posedge clk or posedge rst_async) begin
    if (rst_async) begin
        sys_rst <= 1'b1;
    end
    else begin
        sys_rst <= rst_r;
    end
end

always @ ( posedge clk ) begin
    rst_module1 <= sys_rst;
    rst_module2 <= sys_rst;
end

endmodule

在这里插入图片描述

3. 高复位 or 低复位?

很多处理器上的复位都是低复位,这也导致了很多同学在使用复位信号时也习惯使用低复位了。但从我们上一节所讲中可以看出,无论是同步复位还是异步复位,复位信号都是高有效,如果采用低复位,还需要增加一个反相器。
如果接收到其他处理器发过来的低有效复位信号,我们最好在顶层模块中翻转复位信号的极性,这样做可以将反相器放入IO Logic中,不会占用FPGA内部的逻辑资源和布线资源。
这里多补充一点,如果使用Zynq和Microblaze,则Reset模块默认是低复位,我们可以手动设置为高复位。

4.复位电路映射

4.1 同步复位

在很多其它芯片映射同步复位电路时会映射出选择器,如下代码和图示:

// 同步电路
always@(posedge clk) begin
	if(!rst_n)
		dout <= 'b0;
	else
		dout <= din;
end

映射的电路如下,rst_n为 0 则是 i0 通路接通,也就是高电平 1 接到 RST 上,此时复位;rst_n为 1 则是 i1 通路接通,也就是低电平 0 接到 RST 上,此时不复位。因此这个选择器实际上相当于是 rst_n 的反相器。
在这里插入图片描述

4.2 异步复位

代码

always@(posedge clk, negedge rst_n ) begin
	if(!rst_n)
		dout <= 'b0;
	else
		dout <= din;
end

4.3 异步复位,同步置数

代码

always@(posedge clk, negedge rst_n ) begin
	if(!rst_n)
		dout <= 'b0;
	else if(!en)
		dout <= 1'b1;
	else
		dout <= din;
end

4.4 异步复位,异步置数

代码

always@(posedge clk, negedge rst_n, negedge en ) begin
	if(!rst_n)
		dout <= 'b0;
	else if(!en)
		dout <= 1'b1;
	else
		dout <= din;
end

D触发器是复位优先级高于clk优先级,所以采用异步复位的方法,但是异步复位D触发器存在竞争与冒险,比如当clk的上升沿和rst_n的下降沿同时来临的时候这时候系统应该听谁的,同样当clk的上升沿和rst_n的上升沿同时来临的时候容易使寄存器出现亚稳态。

4.5 异步复位,同步释放

代码

always@(posedge clk, negedge rst_n ) begin
	if(!rst_n) begin
		rst_n1  <= 'b0;
		rst_n2  <= 'b0;
	end
	else begin
		rst_n1  <= rst_n;
		rst_n2  <= rst_n1;
	end
end

5. 上电延时

开发板接通电源后会有一小段不稳定的状态,在比较大的工程中,逻辑资源利用的比较多的情况下,如果加上电源后直接进行复位操作,同样会使寄存器不稳定,所以,类似于按键消抖的方法,我们也给板子加电源后延时50ms,当系统稳定后在进行复位操作,再看bingo的书时,他是将这两个个分成两个模块然后实例化到一起,但为了提高代码的可移植性,我将异步复位同步释放和上电延时50ms写在一个模块。具体实现如下。
在这里插入图片描述

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的示例代码,用于控制HMC349A射频开关的FPGA代码。请注意,这只是一个示例,实际的代码可能会因具体的FPGA平台和开发环境而有所不同。 ```verilog module HMC349A_control ( input wire clk, // FPGA时钟信号 input wire reset, // FPGA复位信号 output wire control_pin // 控制HMC349A开关的引脚 ); reg [1:0] state; // 控制状态寄存器,用于跟踪开关状态 always @(posedge clk or posedge reset) begin if (reset) begin state <= 2'b00; // 复位时将状态设置为初始状态 end else begin case (state) 2'b00: begin // 初始状态,关闭开关 control_pin <= 1'b0; state <= 2'b01; // 进入下一个状态 end 2'b01: begin // 打开开关 control_pin <= 1'b1; state <= 2'b10; // 进入下一个状态 end 2'b10: begin // 关闭开关 control_pin <= 1'b0; state <= 2'b01; // 进入下一个状态 end endcase end end endmodule ``` 上述代码使用Verilog硬件描述语言编写,模块名为`HMC349A_control`。该模块包含一个时钟信号`clk`、复位信号`reset`和控制引脚`control_pin`。通过时钟上升沿触发的状态机,控制`control_pin`引脚的状态,以实现对HMC349A射频开关的控制。 在该代码,状态寄存器`state`用于跟踪开关的状态。在每个时钟周期,根据当前状态,通过赋值给`control_pin`引脚来控制开关的打开和关闭。初始状态为00,在下一个状态00时关闭开关,然后进入01状态打开开关,再进入10状态关闭开关,循环往复。 请根据具体的FPGA平台和开发环境进行适当的调整和配置。确保正确连接FPGA引脚和HMC349A射频开关的控制引脚。 需要注意的是,这只是一个简单的示例代码,实际应用可能需要更复杂的控制逻辑和时序管理,以及与其他模块的接口和交互。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值