I have a keypad circuit, when I press and hold a key, the signal "key_pressed" is always high, as long as I keep the key pressed, which is normal, when I leave it, it gets low again. But I don't want this signal to be constantly high, no matter how long I press the key, I would like to be detected as a single short press. In other means I should find a way to set this key_pressed to low after lets say 10ms. I'm doing everything in VHDL, no resistors capacitors… I also can't wait for a falling edge then it makes no sense, no key will be displayed on the LCD until the key is released which does not make sense.
Electronic – Set a constant high signal to low
state-machinesvhdl
Related Solutions
Your FPGA design is using the fall signal to clock out data on MISO. But its probably using rise to clock data in from MOSI. The microcontroller will do the same thing. It knows the falling edge of SCLK is telling the slave to change the MISO line, so it won't clock that data in until the rising edge of SCLK. You have to be sure that your FPGA clock is fast enough that even with two clocks delay on detecting the falling edge, it will be presenting valid data to the microcontroller by the time of the rising edge.
This arrangement not only gives your slave device some leeway in how quickly it responds to SCLK, it also allows for some uncertainty about whether the SCLK or the MISO traces or cables are the same length. By sampling MISO in the middle of its valid period, you allow the SCLK transmission delay to be either longer or shorter than the MISO transmission delay. Another way to say this is that the SPI receiver is designed with balanced set-up and hold times.
This is different from the way you normally arrange data transfer between gates in your FPGA. There, your flip-flops generally have zero hold time. That is, they clock old data in on the same edge when the upstream flip-flop is changing its output state. They can do this by delaying their data inputs just a little bit more than their clock inputs, and its an arrangement that generally gives the best possible maximum clock rates while still being relatively easy to guarantee the timing with automated tools.
The balanced set-up and hold arrangement on SPI can't achieve the same high clock rates as the interfaces within the FPGA, but it also doesn't require anywhere near as careful management of the propagation delays between the sender and receiver.
What you can do is create an idle state, and when you detect a button press you switch straight to the idle. Then you can have a counter in idle which waits for a while before you start scanning buttons again.
For example:
-- include numeric std
signal idle_counter : unsigned(31 downto 0);
...
when state3 =>
case bcd_val is
when "01" =>
Send <= '1';
scannel_val <= "0101";
fsm_state <= idle; -- switch to idle
when "10" =>
Send <= '1';
scannel_val <= "0110";
fsm_state <= idle; -- switch to idle
when others =>
scannel_val <= "0000";
Send <= '0';
fsm_state <= state1; -- carry on scanning
end case;
idle_counter <= (others => '0');
...
when idle =>
if (idle_counter < some_timeout) then -- some_timeout is how long you want to wait (in clock cycles)
idle_counter <= idle_counter + "1"; -- increment counter
fsm_state <= idle; -- stay here
else
idle_counter <= (others => '0'); -- reset counter
fsm_state <= state1; -- go back into checking
end
--scannel_val is valid here, so you can do something with it if you'd like.
...
when others => scannel_val <= "0000";
There is one process in this code you've posted.
It starts with
scan_fsm : process (reset, clk) <= Sensitivity list
begin -- process key_scanner
and ends with
end process scan_fsm;
The clock and reset are part of the sensitivity list. That means that this code is only going to be triggered when either clock changes or reset changes.
De-bouncing can be done in a separate process. Basically, you want to make sure that the button was pressed for a number of microseconds before it triggers. What we want to do is save the value of the input for a number of clock cycles. Then only register a 1 when the history has been constantly 1 for for the past 32 clock cycles.
Example:
-- these are our row inputs (to become bdc_val)
signal row1 : in std_logic;
signal row2 : in std_logic;
...
-- this is our history vector
signal row1_z : std_logic_vector(31 downto 0);
signal row2_z : std_logic_vector(31 downto 0);
-- debounced signal
signal bcd_val : std_logic_vector(1 downto 0);
-- a whole vector of ones for convenience
signal ones : std_logic_vector(31 downto 0);
...
ones <= (others => '1');
-- generate our histories
gen_z : process (reset, clk)
begin
if (reset = '1') then
row1_z <= (others => '0');
row2_z <= (others => '0');
bcd_val <= (others => '0');
elsif (rising_edge(clk)) then
row1_z(31 downto 1) <= row1_z(30 downto 0); -- shift everything up 1
row1_z(0) <= row1; -- save the most recent input
row2_z(31 downto 1) <= row2_z(30 downto 0); -- shift everything up 1
row2_z(0) <= row2; -- save the most recent input
-- we only want bcd_val to be 1 when the entire row history for the past 32 cc is 1
if (row1_z = ones) then
bcd_val(0) <= '1';
else
bcd_val(0) <= '0';
end
if (row2_z = ones) then
bcd_val(1) <= '1';
else
bcd_val(1) <= '0';
end
end
end
Related Topic
- Electronic – Pressing same key rows at the same time
- Key press/Key release
- Electronic – Implementing a counter in VHLD with edge triggered clear
- Electronic – cannot fix: warning signal clk IBUF has no load please help!
- Keypad Scanner Verilog code problem with state machine and column input
- Electrical – Bug in the SPI implementation (VHDL)
- Electronic – VHDL: How to only update register at rising edge of the clock
Best Answer
You need a rising edge detector. This is done by generating a delayed input that is 1 clock cycle later than the actual input.
For example:
The delayed input is generated as follows:
Now you want to detect your rising edge:
But now our edge detect is only one clock cycle:
To modify that, add in a counter which only makes edge detect fall after a certain number of clock cycles:
Now it's doing what we want: