Handling Interrupt in VHDL

3.3k views Asked by At

We are using OR1200 for our project and we would like to assign an interrupt to the 8th button of FPGA Board. Here is the code to generate interrupt:

   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;

We only want this interrupt to be handled only once (holding the button should not call the interrupt again), that's why we included a flag to check this (butt_int_tmp).

The problem is that the interrupt call is not stable. It does not call each time we press the button. When we remove the flag, it works, but in this case, it is handled as many as we hold the button.

What are we doing wrong?

2

There are 2 answers

2
zennehoy On

To start with, that second process is not properly written. It should have a structure equivalent to the first process (i.e., if(rising_edge(CLK_I)) surrounding all but the reset logic). You are currently describing a latch with multiple enable signals and wrong sensitivity list.

Moving on, there's no real reason you need that second process at all. You just need one register to act as interrupt (butt_int), and one to keep track of the previous state of the button (butt_prev). The interrupt is triggered for one cycle when DATA_I(8) is '1' while butt_prev is '0' (i.e., the button changed from not-pressed to pressed).

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;

Note that this will only work if your button is properly debounced, otherwise you are likely to get multiple interrupts triggered when you press (or even release) the button.

0
OllieB On

Its best not to think about interrupts. As you're targetting an FPGA, you're describing digital logic, not a software processor.

There a numerous way to build a circuit with the behaviour you want. The simplest is probably a re-timed latch

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';

This causes the button press to be latched asynchronously. The latched signal is then clocked along a shift register, and the interrupt is only valid for one cycle, which is the first clock cycle that the latch is seen on the clock domain.