-2

im in internship and my company wants that i learn vhdl for fpga. I'm using lattice diamond to code and compile my project and questasim for simulation. I also have a little board for training : MachXO3LF by Lattice.

I did a project : when i push a button a led is lighting for 2s and then fade. (works in simulation but but with the card because of the bouncing effect.

My mentor gave me a new project : write a code and a test bench to avoid the boucing effect and when i push the button, the led is lighting for 2s and when i push again the button there is no action for 10s.

I dont know how to avoid the bouncing effect with my starting code.... The bouncing effect is the results of false triggering or multiple triggering like the button is pressed multiple times

Here is my code

use ieee.std_logic_1164.ALL;
use ieee.numeric_std.ALL;


entity bouton_led_debounce is 
    Port    (btn    : in std_logic;
             reset  : in std_logic;
             clock  : in std_logic;
             led    : out std_logic
             );
end bouton_led_debounce;

architecture Behavioral of bouton_led_debounce is

signal m1       : std_logic := '1';
signal m2       : std_logic:= '1';
signal int      : std_logic:= '1';
signal buffer_led   : std_logic := '1';
signal cptr     : std_logic_vector (27 downto 0) := (others => '0');

begin   

    process(clock,reset)
    begin
        if(reset = '0') then
            buffer_led  <= '1';
            m1      <= '1';
            m2      <= '1';
            int     <= '1';
            cptr        <= (others => '0');
        elsif rising_edge(clock) then
        
            buffer_led <= '1';
            
            m1  <= btn;
            m2  <= m1;
            int <= m2;
            
            if( (int = '1') and (m2 = '0') ) then
                cptr <= (others => '0');
                cptr(0) <= '1';
                buffer_led <= '0';
            end if;
                    
            if( unsigned(cptr) /= 0) then
                cptr <= std_logic_vector(unsigned(cptr)+1);
                buffer_led  <= '0';
            end if;

            if( unsigned (cptr) = (24000000-1) )then
                cptr <= (others => '0');
            end if;
        end if;
    end process;
    
    led <= buffer_led;

end Behavioral;

And my test bench :

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity bouton_led_debounce_tb is
end bouton_led_debounce_tb;

architecture Behavioral of bouton_led_debounce_tb is

    component bouton_led_debounce is
        port(   btn     : in STD_LOGIC;
            reset   : in STD_LOGIC;
            clock   : in STD_LOGIC;
            led     : out STD_LOGIC);
    end component;


    signal btn : STD_LOGIC := '1' ;
    signal led : STD_LOGIC;
    signal reset : STD_LOGIC := '1';
    signal clock : STD_LOGIC := '0';

begin
    uut: bouton_led_debounce
        port map(
        btn => btn,
        led => led,
        clock => clock,
        reset => reset);
        

btn_sti : process
begin
    btn <= '1'; 
    wait for 500 ns;
    btn <= '0'; 
    wait for 50 ns;
    btn <= '1'; 
    wait for 30 ns;
    btn <= '0'; 
    wait for 50 ns;
    btn <= '1'; 
    wait for 30 ns;
    btn <= '0'; 
    wait for 30 ns;
    btn <= '1';
    wait;
end process btn_sti;

rst_sti : process
begin
    reset <= '1'; 
    wait for 1 us;
    reset <= '0'; 
    wait for 1 us;
    reset <= '1'; 
    wait;
end process rst_sti;


clock_sti : process
begin
    clock <= '0'; 
    wait for 83.33 ns;
    clock <= '1'; 
    wait for 83.33 ns;
end process clock_sti;
    
end Behavioral;
julien1h
  • 85
  • 7
  • Hi! It would help if you could edit the question to clarify what exactly is meant by "bouncing effect" – scary_jeff Aug 26 '22 at 09:14
  • A common way to debounce a switch when it changes state, is to wait until it has been stable for some time, like 10 or 20 ms, then accept its new value. –  Aug 26 '22 at 13:52
  • @user_1818839, yes, i already did it with an arduino but i dont know how to code this with vhdl – julien1h Aug 26 '22 at 16:19
  • You could for example sample the button only once every 20ms. – the busybee Aug 26 '22 at 16:26
  • @thebusybee for now i set a counter with my 12 Mhz clock, you think i have to divide this to have "another clock" ? – julien1h Aug 26 '22 at 17:01
  • Well, you should do some research on the matter. One possible solution is to use a counter to measure the interval, and if it is reached, reset the counter and sample the button. You should learn about "finite state machine"s, too. It will help you in the long term. -- Don't fall into the trap to create multiple derived clocks. This works in theory, in simulation, and with discrete logic ICs, but rarely with FPGAs. Those are best used with one system clock and "synchronous design" (another keyword to use for research). – the busybee Aug 26 '22 at 18:25
  • @thebusybee thanks for these precious advises – julien1h Aug 26 '22 at 18:41
  • @thebusybee if you have any online lessons or youtube channel with this stuff, im a buyer – julien1h Aug 26 '22 at 18:47
  • No, I don't, I'm doing this just for fun. There are tons of resources already, I could not add substantial stuff. – the busybee Aug 26 '22 at 18:51
  • See the Digi-Key TechForum[Debounce Logic Circuit (VHDL)](https://forum.digikey.com/t/debounce-logic-circuit-vhdl/12573) examples which deal with counter size based on different clock rates. This would work with your 12 MHz clock. – user16145658 Aug 26 '22 at 21:44

1 Answers1

1

A few comments on your design

buffer_led  <= '1';

I assume your LED is active low driven? Still, for who ever reads your code this might not be obvious and should be handled accordingly. In your case, as you don't ever read buffer_led I'd use this signal as a representation of the logical signal and do

led <= not(buffer_led);

instead.

I don't see any button debouncing in your snipped. What you do with

m1  <= btn;
m2  <= m1;
int <= m2;

is input synchronization what is totally fine, but has nothing to do with debouncing. As mentioned in the comments, debouncing comes in different forms, a rather simple one would be to lower the sampling rate of your button. E.g. create an enable pulse with 1kHz frequency and check only when there's an enable, you can do this inside your process.

if clken_1kHz then
  m1 <= btn;
  m2 <= m1;
  if m1 = '1' and m2 = '1' then
    int <= '1';
  else
    int <= '0';
  end if;
end if;

With the above snippet, the int signal would only turn one if the samples m1 and m2 which are 1ms apart both evaluate to 1. Of course this is far from perfect and there are way more sophisticated variations of debouncing, but it should for sure improve your situation. You can also play around with the sampling rate, decrease the 1kHz to e.g. 10Hz to get more debouncing.

Further, use the signal types that make most sense, there's no added value in tons of conversion, if you have a counter, use unsigned directly instead of converting back and forth. With the int signal defined as above, the rest of your code would be something like

if int = '1' and cptr(cptr'left) = '0' then 
  led_buffer <= '1';
  cptr <= cptr-1;
else
  led_buffer <= '0';
  if int = '0' then
    cptr <= to_unsigned(24000000-1, cptr'length);
  end if;
end if;

by counting down instead of up we can simply check for the underflow, note that we need a counter with one additional bit, but the comparison is also just 1 bit instead of full size. So as long as the button is pressed and the counter has not underflow, the led_buffer is set, once the button is released or the counter has elapsed, we turn off the led and if the button has been released as well we can safely reset the counter.

disclaimer: haven't tested it, just mind compiled

po.pe
  • 1,047
  • 1
  • 12
  • 27