FPGA 系统中的同步与异步复位
Synchronous vs Asynchronous Resets in FPGA system
我刚开始使用各种不同的模块创建 FPGA 系统来驱动 I2C 总线(尽管我想这个问题适用于任何 FPGA 系统),并且都使用同步复位。
这些模块使用时钟分频器模块计时,该模块采用系统时钟并向系统的其余部分输出较低的频率。
我遇到的问题是,当复位信号变低时,时钟分频器复位,因此其他模块依赖的时钟停止 - 因此其他模块不注册复位
一个明显的解决方案是进行异步复位,但是,在 Xilinx ISE 中,它似乎不喜欢它们,并发出警告说这与 Spartan-6 FPGA 不兼容(尤其是当代码之后异步代码是同步的,这是因为 I2C 总线使用总线时钟将位放到总线上)。
另一个解决方案是让时钟分频器简单地不可重置,因此时钟永远不会停止,所有模块都会正确重置。然而,这意味着时钟分频器寄存器不能 initialised/reinitialised 到已知状态 - 有人告诉我这将是一个大问题,虽然我知道你可以在模拟中使用 := '0'/'1';
运算符,但是一旦在实际的 FPGA 上编程(?),这就不起作用了。
同步重置的约定是什么?时钟发生器通常只是不复位吗?还是它们只在复位信号的瞬时沿复位?或者我的 none 个建议是真正的解决方案!
我放了一个时序图和我的代码来说明我的意思,并展示我一直在使用的代码。
非常感谢!
大卫
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library UNISIM;
use UNISIM.VComponents.all;
ENTITY CLK_DIVIDER IS
GENERIC(INPUT_FREQ : INTEGER;
OUT1_FREQ : INTEGER;
OUT2_FREQ : INTEGER
);
PORT(SYSCLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
OUT1 : OUT STD_LOGIC;
OUT2 : OUT STD_LOGIC);
END CLK_DIVIDER;
architecture Behavioral of Clk_Divider is
constant divider1 : integer := INPUT_FREQ / OUT1_FREQ / 2;
constant divider2 : integer := INPUT_FREQ / OUT2_FREQ / 2;
signal counter1 : integer := 0;
signal counter2 : integer := 0;
signal output1 : std_logic := '0';
signal output2 : std_logic := '0';
begin
output1_proc : process(SYSCLK)
begin
if rising_edge(SYSCLK) then
if RESET_N = '0' then
counter1 <= 0;
output1 <= '1';
else
if counter1 >= divider1 - 1 then
output1 <= not output1;
counter1 <= 0;
else
counter1 <= counter1 + 1;
end if;
end if;
end if;
end process;
output2_proc : process(SYSCLK)
begin
if rising_edge(SYSCLK) then
if RESET_N = '0' then
counter2 <= 0;
output2 <= '1';
else
if counter2 >= divider2 - 1 then
output2 <= not output2;
counter2 <= 0;
else
counter2 <= counter2 + 1;
end if;
end if;
end if;
end process;
OUT1 <= output1;
OUT2 <= output2;
end Behavioral;
不要使用用户逻辑生成内部时钟,但如果确实需要多个时钟,请使用特定于设备的 PLL/DCM。派生时钟上的所有用户逻辑 运行 应保持复位状态,直到时钟稳定,然后可根据设计要求释放用户逻辑的复位。可以使用同步复位或异步复位。
但在这种情况下,可能会生成一个时钟启用信号,并在每次需要更新信号时将此启用信号断言一个周期,以生成所需的任何协议,例如具有适当时序的 I2C 协议。
使用更少的时钟,结合同步时钟启用信号,为 Static Timing Analysis (STA) easier, and also avoid issues with reset synchronization and Clock Domain Crossing (CDC) 进行设置。
在这样的系统中处理重置的稳健方法如下:
在 Xilinx FPGA 中使用 DCM/PLL/MMCM 来处理输入系统时钟并生成您需要的所有输出时钟频率,请记住,对于非常低的频率,您应该使用时钟规格范围内的时钟管理器并生成时钟使能信号以与其结合使用。这可以在启动时从主机系统重置,或者如果在任何时候删除输入时钟然后重新应用。
反转来自时钟管理器的LOCKED信号,以在复位或锁定输入的过程中生成高电平有效复位。这应该通过 SRL16 或 SRL32 传递以延迟它。在使用 BUFG 将其放入全局时钟路由后,此 SRL 应使用 PLL 的输出进行计时。在 SRL 之后使用一个额外的触发器来改善时序。然后,该信号可用作设备中需要的其余逻辑的高电平有效同步复位。
如果时钟启用信号出现时序错误,因为它是高扇出网络,也可以通过 BUFG 访问快速全局时钟网络以改善时序。
@斯图尔特维维安
(这应该作为评论发布,但我没有足够的声望点数,抱歉)
考虑使用计数器而不是移位寄存器来延迟重置,因为如果在加载比特流后未清除 LUT 内容(某些 FPGA 系列有此行为),重置信号可能会反弹,从而导致不可预测的结果。
我刚开始使用各种不同的模块创建 FPGA 系统来驱动 I2C 总线(尽管我想这个问题适用于任何 FPGA 系统),并且都使用同步复位。
这些模块使用时钟分频器模块计时,该模块采用系统时钟并向系统的其余部分输出较低的频率。
我遇到的问题是,当复位信号变低时,时钟分频器复位,因此其他模块依赖的时钟停止 - 因此其他模块不注册复位
一个明显的解决方案是进行异步复位,但是,在 Xilinx ISE 中,它似乎不喜欢它们,并发出警告说这与 Spartan-6 FPGA 不兼容(尤其是当代码之后异步代码是同步的,这是因为 I2C 总线使用总线时钟将位放到总线上)。
另一个解决方案是让时钟分频器简单地不可重置,因此时钟永远不会停止,所有模块都会正确重置。然而,这意味着时钟分频器寄存器不能 initialised/reinitialised 到已知状态 - 有人告诉我这将是一个大问题,虽然我知道你可以在模拟中使用 := '0'/'1';
运算符,但是一旦在实际的 FPGA 上编程(?),这就不起作用了。
同步重置的约定是什么?时钟发生器通常只是不复位吗?还是它们只在复位信号的瞬时沿复位?或者我的 none 个建议是真正的解决方案!
我放了一个时序图和我的代码来说明我的意思,并展示我一直在使用的代码。
非常感谢!
大卫
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library UNISIM;
use UNISIM.VComponents.all;
ENTITY CLK_DIVIDER IS
GENERIC(INPUT_FREQ : INTEGER;
OUT1_FREQ : INTEGER;
OUT2_FREQ : INTEGER
);
PORT(SYSCLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
OUT1 : OUT STD_LOGIC;
OUT2 : OUT STD_LOGIC);
END CLK_DIVIDER;
architecture Behavioral of Clk_Divider is
constant divider1 : integer := INPUT_FREQ / OUT1_FREQ / 2;
constant divider2 : integer := INPUT_FREQ / OUT2_FREQ / 2;
signal counter1 : integer := 0;
signal counter2 : integer := 0;
signal output1 : std_logic := '0';
signal output2 : std_logic := '0';
begin
output1_proc : process(SYSCLK)
begin
if rising_edge(SYSCLK) then
if RESET_N = '0' then
counter1 <= 0;
output1 <= '1';
else
if counter1 >= divider1 - 1 then
output1 <= not output1;
counter1 <= 0;
else
counter1 <= counter1 + 1;
end if;
end if;
end if;
end process;
output2_proc : process(SYSCLK)
begin
if rising_edge(SYSCLK) then
if RESET_N = '0' then
counter2 <= 0;
output2 <= '1';
else
if counter2 >= divider2 - 1 then
output2 <= not output2;
counter2 <= 0;
else
counter2 <= counter2 + 1;
end if;
end if;
end if;
end process;
OUT1 <= output1;
OUT2 <= output2;
end Behavioral;
不要使用用户逻辑生成内部时钟,但如果确实需要多个时钟,请使用特定于设备的 PLL/DCM。派生时钟上的所有用户逻辑 运行 应保持复位状态,直到时钟稳定,然后可根据设计要求释放用户逻辑的复位。可以使用同步复位或异步复位。
但在这种情况下,可能会生成一个时钟启用信号,并在每次需要更新信号时将此启用信号断言一个周期,以生成所需的任何协议,例如具有适当时序的 I2C 协议。
使用更少的时钟,结合同步时钟启用信号,为 Static Timing Analysis (STA) easier, and also avoid issues with reset synchronization and Clock Domain Crossing (CDC) 进行设置。
在这样的系统中处理重置的稳健方法如下:
在 Xilinx FPGA 中使用 DCM/PLL/MMCM 来处理输入系统时钟并生成您需要的所有输出时钟频率,请记住,对于非常低的频率,您应该使用时钟规格范围内的时钟管理器并生成时钟使能信号以与其结合使用。这可以在启动时从主机系统重置,或者如果在任何时候删除输入时钟然后重新应用。
反转来自时钟管理器的LOCKED信号,以在复位或锁定输入的过程中生成高电平有效复位。这应该通过 SRL16 或 SRL32 传递以延迟它。在使用 BUFG 将其放入全局时钟路由后,此 SRL 应使用 PLL 的输出进行计时。在 SRL 之后使用一个额外的触发器来改善时序。然后,该信号可用作设备中需要的其余逻辑的高电平有效同步复位。
如果时钟启用信号出现时序错误,因为它是高扇出网络,也可以通过 BUFG 访问快速全局时钟网络以改善时序。
@斯图尔特维维安
(这应该作为评论发布,但我没有足够的声望点数,抱歉)
考虑使用计数器而不是移位寄存器来延迟重置,因为如果在加载比特流后未清除 LUT 内容(某些 FPGA 系列有此行为),重置信号可能会反弹,从而导致不可预测的结果。