Problem with buttons - sounds old, but...

Discussion in 'VHDL' started by Pleg, Mar 14, 2006.

  1. Pleg

    Pleg Guest

    Hi everybody, I was trying to play with the push buttons of a proto board,
    to see if I'm able to get the buttons work correctly --- I'm not ^__^;
    I've already looked to some old answers, but still I can't figure out the
    solution.

    What I wanted to do is: I've a 7 segments display, and I want to show a
    digit on it, starrting with 0. Button A increases the digit, button B
    decreases it. My first attempt gave me the "bad synchronous description
    error", because I wrote


    count_up_down: process(debounced_button_A,debounced_button_B)
    begin
    if(debounced_button_A'event and debounced_button_A='0') then
    case current_state_1 is
    when zero => next_state_1 <= one;
    ...
    end case;
    elsif(debounced_button_B'event and debounced_button_B='0') then
    case current_state_1 is
    when zero => next_state_1 <= nine;
    ...
    end case;
    end if;
    end process count_up_down;


    Now, I understand the error, and I've already found some answers in a mex of
    one year ago, suggesting to use synchronous description (using the clock),
    something like

    if clk'event and clk = '1' then
    if debounced_button_A = '0' then
    ...
    elsif debounced_button_B = '0' then
    ...

    but I don't think it's the same: I want to be sensitive to edges in the
    buttons state, not the clock! I mean, I've a clock at 100 MHz, if I use the
    above code, when I push button A (for example) it'll stay down for a lot of
    clock cycles, my display will increase the digit one million times, right?

    I tried then with


    flag <= debounced_button_A and debounced_button_B;
    process(flag,debounced_button_A,debounced_button_B)
    begin
    if(flag'event and flag='0') then
    if(debounced_button_A='0') then
    case current_state_1 is
    when zero => next_state_1 <= one;
    ...
    end case;
    elsif(debounced_button_B='0') then
    case current_state_1 is
    when zero => next_state_1 <= nine;
    ...
    end case;
    else null;
    end if;
    end if;
    end process;


    In my mind, now the process is sensitive to the edge of only one signal (the
    "flag", which "summarize" both buttons), and then in the if clause I see
    which one of the buttons was pushed. I simulated it with modelsim and it
    works correctly, but once loaded on the FPGA it doesn't work! The display
    never changes :-(


    BTW, also the display is a little mistery: I want to initialize the display
    state to 0, and so I write

    signal current_state_1, next_state_1: display_state := zero;

    where "type display_state is (zero, one, two, three, four, five, six, seven,
    eight, nine);"

    But the display starts with an invalid state... there's no number on it,
    just a "-", that is what I want it to show when something's wrong. Why
    doesn't it intialize correctly?

    I've tried with just one button (it counts only forward), and, though it
    doesn't initialize, it works (I've added a clause that says that when the
    state is unknown, it has to go to five at the push of the button. So, it
    starts with "-", then when I push the button it goes to 5, and then counts
    correctly).


    I hope somebody was patient enough to read all this and can help me :)




    Pleg
    Pleg, Mar 14, 2006
    #1
    1. Advertising

  2. You have to make a circuit that debounces your button, and then detects a
    rising edge... And you have to do this synchronously. You have to have one
    clock, one reset, and everything has to be synchronous to the clock. and
    only ever reset once, asynchronously.

    So anyways, I think if you go back to basics you'll get this working in no
    time, firstly forget the state machine, it's too complicated at this stage.

    Try something like this.

    Button_A_Debounce: process (clock, reset)
    begin
    if reset = RESET_ACTIVE then
    button_a_debounced <= '0';
    elsif rising_edge (clock) then
    -- some code to make button_a_debounced & not show glitches (filter for
    10ms)
    end if;
    end process

    do the same for Button_B

    Then you want to detect the rising_edge of a and b...
    Detect_A_Rising_Edge : process (clock, reset)
    begin
    if reset = RESET_ACTIVE then
    button_a_delayed <= '0';
    elsif rising_edge (clock) then
    button_a_delayed <= button_a_debounced;
    end if;
    button_a_rising_edge <= button_a_debounced AND NOT button_a_delayed

    Same for B

    Then you want a process to control a counter, it is reset with RESET,and
    changed only when one of the rising edges is true (think synchronous enable)

    Then finally a process which converts your internal counter value to the
    seven segemt display value.

    My help stops here, but this should get you going. =)
    HTH
    Ben





    "Pleg" <> wrote in message
    news:%eBRf.10079$...
    > Hi everybody, I was trying to play with the push buttons of a proto board,
    > to see if I'm able to get the buttons work correctly --- I'm not ^__^;
    > I've already looked to some old answers, but still I can't figure out the
    > solution.
    >
    > What I wanted to do is: I've a 7 segments display, and I want to show a
    > digit on it, starrting with 0. Button A increases the digit, button B
    > decreases it. My first attempt gave me the "bad synchronous description
    > error", because I wrote
    >
    >
    > count_up_down: process(debounced_button_A,debounced_button_B)
    > begin
    > if(debounced_button_A'event and debounced_button_A='0') then
    > case current_state_1 is
    > when zero => next_state_1 <= one;
    > ...
    > end case;
    > elsif(debounced_button_B'event and debounced_button_B='0') then
    > case current_state_1 is
    > when zero => next_state_1 <= nine;
    > ...
    > end case;
    > end if;
    > end process count_up_down;
    >
    >
    > Now, I understand the error, and I've already found some answers in a mex
    > of
    > one year ago, suggesting to use synchronous description (using the clock),
    > something like
    >
    > if clk'event and clk = '1' then
    > if debounced_button_A = '0' then
    > ...
    > elsif debounced_button_B = '0' then
    > ...
    >
    > but I don't think it's the same: I want to be sensitive to edges in the
    > buttons state, not the clock! I mean, I've a clock at 100 MHz, if I use
    > the
    > above code, when I push button A (for example) it'll stay down for a lot
    > of
    > clock cycles, my display will increase the digit one million times, right?
    >
    > I tried then with
    >
    >
    > flag <= debounced_button_A and debounced_button_B;
    > process(flag,debounced_button_A,debounced_button_B)
    > begin
    > if(flag'event and flag='0') then
    > if(debounced_button_A='0') then
    > case current_state_1 is
    > when zero => next_state_1 <= one;
    > ...
    > end case;
    > elsif(debounced_button_B='0') then
    > case current_state_1 is
    > when zero => next_state_1 <= nine;
    > ...
    > end case;
    > else null;
    > end if;
    > end if;
    > end process;
    >
    >
    > In my mind, now the process is sensitive to the edge of only one signal
    > (the
    > "flag", which "summarize" both buttons), and then in the if clause I see
    > which one of the buttons was pushed. I simulated it with modelsim and it
    > works correctly, but once loaded on the FPGA it doesn't work! The display
    > never changes :-(
    >
    >
    > BTW, also the display is a little mistery: I want to initialize the
    > display
    > state to 0, and so I write
    >
    > signal current_state_1, next_state_1: display_state := zero;
    >
    > where "type display_state is (zero, one, two, three, four, five, six,
    > seven,
    > eight, nine);"
    >
    > But the display starts with an invalid state... there's no number on it,
    > just a "-", that is what I want it to show when something's wrong. Why
    > doesn't it intialize correctly?
    >
    > I've tried with just one button (it counts only forward), and, though it
    > doesn't initialize, it works (I've added a clause that says that when the
    > state is unknown, it has to go to five at the push of the button. So, it
    > starts with "-", then when I push the button it goes to 5, and then counts
    > correctly).
    >
    >
    > I hope somebody was patient enough to read all this and can help me :)
    >
    >
    >
    >
    > Pleg
    >
    >
    Benjamin Todd, Mar 14, 2006
    #2
    1. Advertising

  3. Pleg

    mk Guest

    On Tue, 14 Mar 2006 16:24:00 +0100, "Pleg" <> wrote:

    >Hi everybody, I was trying to play with the push buttons of a proto board,
    >to see if I'm able to get the buttons work correctly --- I'm not ^__^;
    >I've already looked to some old answers, but still I can't figure out the
    >solution.
    >
    >What I wanted to do is: I've a 7 segments display, and I want to show a
    >digit on it, starrting with 0. Button A increases the digit, button B
    >decreases it.


    Let me try to make some general comments. About the buttons: when you
    push the button it usually bounces many times till it gets to a stable
    value so when you read it with a high speed clock you need to filter
    out all those small bounces. A robust way of doing it is to use
    several synchronizing flops to the button inputs to get rid of
    metastable sampling cases (basically a shift register which samples
    the button) and then use a small counter to filter all 1-0-1 changes
    and wait for it to be stable. When you see a stable 1-0 change (or
    vice versa) you generate a valid flag and a value.
    As to the LED, you need to generate a power on reset value for the
    display state. Your registers are waking up in a state you don't
    control. You need to apply a reset or figure out what the reset value
    of the registers are for your fpga and assign a valid display for that
    configuration.
    HTH.
    mk, Mar 14, 2006
    #3
  4. > flag <= debounced_button_A and debounced_button_B;
    > process(flag,debounced_button_A,debounced_button_B)
    > begin
    > if(flag'event and flag='0') then
    > if(debounced_button_A='0') then
    > case current_state_1 is
    > when zero => next_state_1 <= one;
    > ...
    > end case;
    > elsif(debounced_button_B='0') then
    > case current_state_1 is
    > when zero => next_state_1 <= nine;
    > ...
    > end case;
    > else null;
    > end if;
    > end if;
    > end process;


    Have you considered deleting the two buttons from the sensitivity list ? I'm
    not an expert in VHDL but as far as i can tell, you only want the process to
    trigger when flag changes, and then look at the buttons, but the buttons
    themselves should not trigger the process directly.
    Thomas Thorsen, Mar 14, 2006
    #4
  5. Pleg wrote:

    > but I don't think it's the same: I want to be sensitive to edges in the
    > buttons state, not the clock!


    Read this whole thread, then for a related example,
    see the rising level counter source here:
    http://home.comcast.net/~mike_treseler/

    -- Mike Treseler
    Mike Treseler, Mar 14, 2006
    #5
  6. Pleg

    radarman Guest

    Having dealt with buttons in designs for 7 years now, both in
    microprocessors and FPGA's, there are a few general things you should
    know. One, not all buttons are alike. Some have relatively short bounce
    periods, while others seem to ring forever. Most protoboards use
    pushbutton microswitches, which are generally fairly good about bounce
    - but if you have a scope, you should try to measure it. Otherwise, you
    are trying to fix a problem you can't see.

    Generally speaking, you should sample the input at a rate approximately
    the same as your expected bounce period (which is why you need to know
    what it is). If you see three or more samples in a row, then you can be
    relatively sure that you are seeing the final state - and not a glitch.

    For example, I have a breadboard project using standard pushbutton
    microswitches. They tend to bounce for approximately 250-500us. So, I
    set up a clock divider to bring my tick rate down to about 500us, and
    feed the samples into a register pipeline. If all three registers are
    high, then I indicate a high for the button. This means that it takes
    1.5ms to indicate a button press - which is more than fast enough for a
    user interface. If you are especially conservative, you can make the
    tick period longer - but you will begin to notice the delay in pressing
    the button and seeing something happen at about 100-150ms. (I have a
    commercial programmable thermostat with this problem)

    Note, you can use the "tick" pulse for multiple debouncers to save on
    gates. I actually wrote a "generic" debounce circuit which takes the
    number of switches as a generic, so I can handle them all at once. This
    way, each additional button only costs three FF's and a LUT.

    Typically, buttons will also bounce when you release them, but this is
    less of a problem as you typically only care when the button is
    pressed, not when it is released. If you need reasonably precise timing
    of both events, then use the same method to detect lows as well.

    The other alternative is to use a RC low-pass filter and feed the
    output into a Schmitt trigger. Again, you need to know the approximate
    bounce period to properly size your filter components, but you are
    reasonably guaranteed a "clean" input to your FPGA.
    radarman, Mar 15, 2006
    #6
  7. Pleg

    Pleg Guest

    > You have to make a circuit that debounces your button, and then detects a
    > rising edge...


    And that's what I did (or, at least, what I intended to do). That's why, for
    example, the signals from the buttons were named "debounced_button_A" and
    not "button_A".


    > Then you want a process to control a counter, it is reset with RESET,and
    > changed only when one of the rising edges is true (think synchronous

    enable)
    >
    > Then finally a process which converts your internal counter value to the
    > seven segemt display value.


    And that's what I had in mind, the problem was to make it synchronous with
    the clock and not with the buttons (which looked more natural to me... I
    want the transitions when I push the buttons).



    Pleg
    Pleg, Mar 16, 2006
    #7
  8. Pleg

    Pleg Guest

    > As to the LED, you need to generate a power on reset value for the
    > display state. Your registers are waking up in a state you don't
    > control.


    Yes, that's what I don't understand completely. I thought that when I write,
    for example,

    signal pin_counter: std_logic_vector(15 downto 0) := X"0000";

    my signal gets initialized at that value (in the case, all zeroes). It
    doesn't happen, right? Never, for no signal, right? I never noticed before.
    Anyway, I added a reset process (on the push of a button), and now
    everything seems to work fine.
    Thank you for the suggestion!


    Pleg
    Pleg, Mar 16, 2006
    #8
  9. Pleg

    Pleg Guest

    > Have you considered deleting the two buttons from the sensitivity list ?

    Yes I tried, but nothing changed :) And reading the rest of this thread I
    guess I understand why.


    Pleg
    Pleg, Mar 16, 2006
    #9
  10. Pleg

    Pleg Guest

    [cut]
    Thanks for the long explanation... makes me feel a little less stupid :)
    What I ended up doing is probably not efficient, but at least it works in
    the way I intended to: both buttons work :) without glitches or bouncing,
    and if I keep one of them pressed the numbers go up (or down) in a fast but
    controllable way.
    I just wait for the first transition in any button, and when it occurs, I
    stop monitoring the buttons for about 200 ms; after that, I come back
    monitoring the buttons. This is it:


    process(slow_clk,reset)
    begin
    if(reset='1') then
    next_state_1 <= zero;
    elsif(slow_clk'event and slow_clk='1') then
    case push_buttons_state is
    when waiting =>
    push_buttons_counter <= push_buttons_counter+1;
    if(push_buttons_counter=DEBOUNCE_PUSH_BUTTON_TIME) then
    push_buttons_state <= idle;
    end if;

    when idle =>
    if(button_B='0') then
    case current_state_1 is
    when zero => next_state_1 <= one;
    ....
    when nine => next_state_1 <= zero;
    end case;
    push_buttons_counter <= B"0_0000_0000";
    push_buttons_state <= waiting;
    elsif(button_A='0') then
    case current_state_1 is
    when zero => next_state_1 <= nine;
    ....
    when nine => next_state_1 <= eight;
    end case;
    push_buttons_counter <= B"0_0000_0000";
    push_buttons_state <= waiting;
    end if;

    when others => push_buttons_state <= idle;
    end case;
    end if;
    end process;




    > The other alternative is to use a RC low-pass filter and feed the
    > output into a Schmitt trigger. Again, you need to know the approximate
    > bounce period to properly size your filter components, but you are
    > reasonably guaranteed a "clean" input to your FPGA.



    Yes, that's what I prefer doing. Unfortunately, I'm working on a proto
    board, with buttons and everything already integrated in it.


    Thank you for the help!


    Pleg
    Pleg, Mar 16, 2006
    #10
  11. Initial conditions like this are not taken into account for synthesis...
    (when they're in the signal declaration line)

    "Pleg" <> wrote in message
    news:qSdSf.14049$...
    >> As to the LED, you need to generate a power on reset value for the
    >> display state. Your registers are waking up in a state you don't
    >> control.

    >
    > Yes, that's what I don't understand completely. I thought that when I
    > write,
    > for example,
    >
    > signal pin_counter: std_logic_vector(15 downto 0) := X"0000";
    >
    > my signal gets initialized at that value (in the case, all zeroes). It
    > doesn't happen, right? Never, for no signal, right? I never noticed
    > before.
    > Anyway, I added a reset process (on the push of a button), and now
    > everything seems to work fine.
    > Thank you for the suggestion!
    >
    >
    > Pleg
    >
    >
    Benjamin Todd, Mar 23, 2006
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roger
    Replies:
    1
    Views:
    613
    GreggTB
    May 20, 2005
  2. =?Utf-8?B?SGVyYg==?=

    Playing Sounds

    =?Utf-8?B?SGVyYg==?=, Nov 13, 2005, in forum: ASP .Net
    Replies:
    3
    Views:
    386
    Jason Gogela
    Nov 15, 2005
  3. Jim Hill
    Replies:
    3
    Views:
    388
    Jim Hill
    Feb 12, 2007
  4. *Prot3anThr3ad*

    old repository for old C++ source code

    *Prot3anThr3ad*, Sep 29, 2006, in forum: C++
    Replies:
    6
    Views:
    365
    *Prot3anThr3ad*
    Oct 2, 2006
  5. John Henry
    Replies:
    24
    Views:
    990
    alex23
    May 30, 2008
Loading...

Share This Page