Hello there,
I am designing a simple debounce mechanism in VHDL. I have the following problem. An internal counter (a variable) should be initially set to 0 or some value (ie. 100), depending on either the input is high or low at power up. I have no idea how to implement this. Is it even possible? At the moment my internal "key" state is initialized with input value, but for some reason this doesnt work. The first transition always fails (no debounce). I am using additional boolean generic's in order to enable the debounce for either up or low transitions.
Code:
-- Libraries -------------------------------------------------------------------
--! Main library
library ieee;
--! std logic components
use ieee.std_logic_1164.all;
-- Entity ----------------------------------------------------------------------
--! bouncer signals
entity entity_debounce is
generic
(
--! Stores the maximum hysteresis value.
max : natural;
--! Disables the up counting hysteresis when true
hystup_dis : boolean;
--! Disables the down counting hysteresis when true
hystdown_dis : boolean
);
port
(
--! Clock signal. Rising edge triggers the counter.
clk : in std_logic;
--! Input signal that needs debouncing
input : in std_logic;
--! clean, debounced output
output : out std_logic
);
end entity_debounce;
-- Architecture ----------------------------------------------------------------
--! Debounce hysteresis mechanism implementation
architecture arch_debounce of entity_debounce is
--! internal key memory state
signal key : std_logic := input;
begin
process_debounce : process(clk)
--! Hysteresis counter
variable cnt : natural := 0;
begin
if (rising_edge(clk)) then
if (input = '1') then
if ((cnt < max) and (hystup_dis = false)) then
cnt := cnt + 1;
elsif (key = '0') then
key <= '1';
cnt := max;
end if;
else
if ((cnt > 0) and (hystdown_dis = false)) then
cnt := cnt - 1;
elsif (key = '1') then
key <= '0';
cnt := 0;
end if;
end if;
end if;
end process;
output <= key;
end arch_debounce;
.
.
.
In the top vhd file:
Code:
--! Debouncer instance 20 ms hysteresis debounce time
debounce_ledbtn20ms : entity_debounce
generic map
(
max => 656,
hystup_dis => true,
hystdown_dis => false
)
port map
(
clk => clk_32k,
input => pin_ledbtn,
output => pins_led(0)
);
On the scope one can see that 1st transition is not correct, since falling edge should have debounce added (hystdown_dis => false). There should never be debounce added on rising edges and that is OK (hystup_dis => true).
An initial value is either synthesized as constant or power-on-reset value, depending on the logic, in your case the latter.
POR value can't depend on input, instead you'll need an explicit reset that stores the initial value. Simple, straightforward.
You should consider that some logic families don't support asynchronous set function and need to emulate it by a logic loop latch, e.g. all newer Intel FPGA. As a drawback, the POR value of this latch will be undetermined.
I tried doing just that- it did not help as well. I think in my situation (MachXO2 from Lattice) it is somewhat not possible to initialize the values this way. For example, when I created a separate bolean variable that is initialy false, and then in the behavioral code I check either it is false and set it to true forever, the synthesizer gave me a warning that my variable will always be true. So, its like it was never initialized with false. Also, the code didnt work so this had to be the case...
You are right, but the thing is to make the input being read only once. Please take a look at this MWE:
Code:
--! Debounce hysteresis mechanism implementation
architecture arch_debounce of entity_debounce is
begin
process_debounce : process(clk)
variable test : bolean := false;
begin
if (test = false)
test = true; -- this code is never run
end if;
end process;
The problem lies in the test variable. The if statement was designed to run some portion of code only once per whole device reset. Why doesnt it work?
This is just an example. In the if statement part I had another statement that sets the counter variable, depending on the input signal. That did not work as well. How else can I create a 1 time execution situation?
I see... But the problem here is that the mentioned reset signal is probably a signal entering the component. This design would require a physical reset to be performed a startup, this is not automatic, do I understand correctly?
I'm not sure wheter I understand the problem correctly.
I assume you have one input and one output...and at powerup you want the output to have the same logic state as the input, but as soon as possible.
The dilemma is, that the usual timing is:
* Power up (FPGA signals are not initiated yet, thus high impedance)
* time to load the FPGA configuration (FPGA signals are not initiated yet, thus high impedance)
* FPGA is initiated and thus the output only can be configured as fix HIGH, LOW or Z (but you don't want fix H or L here)
* FPGA is operating and now can react an output a signal depending on an input (but now it's too late for your idea)
If my assumptions above are correct, then the only solution I see is to use an external resistor between input and output.
This makes the "output" to get the same state as the "input" as long as the "output" is in Z state.
As soon as you switch the "output" to H or L the FPGA controls the state (overriding the resistor)
External hardware reset is the preferred method and should be always provided in a good design. Problems arise particularly, if the input clock is already present when the internal power on reset is released.
It's nevertheless possible to generate an internal reset, although it can't be guaranteed to be completely free of metastable events.