我们正在为项目使用OR1200,我们希望为FPGA板的第8个按钮分配一个中断。以下是生成中断的代码:
inrpt: process(CLK_I, RST_I)
begin
if RST_I = '1' then
butt_int_pul <= '0';
butt_int_tmp <= '0';
elsif rising_edge(CLK_I) then
if(DATA_I(8) = '1' and butt_int_tmp = '0') then
butt_int_pul <= '1';
else
butt_int_pul <= '0';
end if;
butt_int_tmp <= DATA_I(8);
end if;
end process inrpt;
process(CLK_I, RST_I)
begin
if RST_I = '1' then
butt_int <= '0';
elsif butt_int_pul = '1' then
butt_int <= '1';
elsif clear_int = '1' then
butt_int <= '0';
end if;
end process;
我们只希望这个中断只被处理一次(按住按钮不应该再次调用中断),这就是为什么我们要包含一个标志来检查这个(butt_int_tmp
)。
问题是中断调用不稳定。每按一次按钮,它都不会调用。当我们删除标志时,它会起作用,但在这种情况下,它会按照我们按住按钮的次数进行处理。
我们做错了什么?
答案 0 :(得分:0)
首先,第二个过程没有正确编写。它应该具有与第一个进程相同的结构(即if(rising_edge(CLK_I))
围绕除复位逻辑之外的所有进程。您目前正在描述具有多个启用信号和错误灵敏度列表的锁存器。
继续前进,你根本没有理由需要第二个过程。您只需要一个寄存器作为中断(butt_int
),另一个用于跟踪按钮的先前状态(butt_prev
)。当DATA_I(8)
为'1'
而butt_prev
为'0'
时(即按钮从未按下更改为按下按钮),中断将在一个周期内触发。
process(CLK_I, RST_I) begin
if(RST_I='1') then
butt_prev <= '0';
butt_int <= '0';
elsif(rising_edge(CLK_I)) then
if(DATA_I(8)='1' and butt_prev='0') then
butt_int <= '1';
else
butt_int <= '0';
end if;
butt_prev <= DATA_I(8);
end if;
end process;
请注意,这仅适用于您的按钮被正确去抖动的情况,否则您可能会在按下(甚至释放)按钮时触发多次中断。
答案 1 :(得分:0)
最好不考虑中断。当你的目标是FPGA时,你正在描述数字逻辑,而不是软件处理器。
有许多方法可以根据您的需要构建电路。 最简单的可能是重新定时的锁存器
signal latched_button : std_logic;
signal meta_chain : std_logic_vector(2 downto 0);
p_async_latch: process(rst_i,data(8))
begin
if rst_i = '1' then
latched_button <= '0';
elsif data(8) = '1' then
latched_button <= '1';
end if;
end process;
p_meta_chain: process(rst_i,clk_i)
begin
if rst_i = '1' then
meta_chain <= (others => '0');
elsif rising_edge(clk_i) then
meta_chain <= meta_chain(1 downto 0) & latched_button;
end if;
end process;
button_int <= '1' when meta_chain(2 downto 1) = "01" else '0';
这会导致按下按钮异步锁定。然后锁存信号沿移位寄存器计时,该中断仅在一个周期内有效,这是在时钟域上看到锁存器的第一个时钟周期。