Up/Down counter with push button - fpga

I'm writing a timer using FPGA.
I will use seven segment display to show the numbers, but I also must be able to set a specific time by increasing/decreasing and then once it is set, with another button the clock will start to go down.
signal lock is for preventing the count increases at the speed of the
manual is a button,
I guess the count up is okay, but the problem is when I want it to go down. In the simulation when I put the sentido HIGH then I do not get anything and does not work.
library ieee;
use ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity counter is
port( clck, reset : in std_logic;
limit : in integer range 0 to 10;
manual: inout std_logic;
sentido: in std_logic;
bitcount : out std_logic_vector(3 downto 0);
clckout : out std_logic);
end counter;
architecture behavior of counter is
signal Cs : std_logic_vector(3 downto 0):="0000";
signal lock: std_logic;
begin
Count : process(clck,reset,manual,lock,sentido)
begin
if(rising_edge(clck))then
if (manual='0' and lock ='0') then
Cs<=Cs+1;
lock<='1';
elsif(manual='1' and lock='1' ) then
lock<='1';
else
lock<='0';
end if;
end if;
if sentido = '1' then
Cs<=Cs-1;
end if;
if (reset = '1') then
Cs <="0000";
end if;
if (Cs = "1010") then
Cs <= "0000";
end if;
end process Count;
bitcount <=Cs;
end behavior;

Your
if sentido = '1'
clause is asycnronous, it works completely independent from clock. This is not synhtesizable in most tools, but might pass thru a simulator checks.
Same goes about all the conditions below.
To fix this, you should fuse them all into your if(rising_edge(clck)) clause like this:
if(rising_edge(clck))then
if (reset = '1') then
Cs <="0000";
elsif (manual='0' and lock ='0') then
if sentido = '1' then
Cs<=Cs-1;
if (Cs = "0000") then --using previous state
Cs <= "1010";
end if;
else
Cs<=Cs+1;
if (Cs = "1001") then --using previous state
Cs <= "0000";
end if;
end if;
lock<='1';
elsif(manual='1' and lock='1' ) then
lock<='1';
else
lock<='0';
end if;
end if;
Oh, and one more thing. You should not include anything but clock in sync process sensitivity list, it will change anything only on clock anyway.

Related

Why is my debouncing/counter not working in VHDL?

i am currently trying to display a counter state on a 7-Segment.
If i push a button (physically) it should increase this counter state.
But in my case its displaying a random number, i think its a wrong debouncing/counter method.
I searched the web but i canĀ“t fix this behaviour.
I would be very thankful if someone could help me!
EDIT: The 7-Segment-Display is working well i did a test with all numbers (0-9)
So it is definetly failing in my debounce or counter method.
//debouncer.vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity Debounce is
Port ( CLK100MHZ : in STD_LOGIC;
BTNU : in STD_LOGIC;
BTNU_I : out STD_LOGIC);
end Debounce;
architecture Behavioral of Debounce is
signal keydeb : std_logic := '0';
signal debcnt : integer range 0 to 63 := 0;
begin
process begin
wait until rising_edge(CLK100MHZ);
-- XOR
if (BTNU=keydeb) then debcnt <= 0;
else debcnt <= debcnt+1;
end if;
-- Latch
if (debcnt=63) then keydeb <= BTNU;
end if;
end process;
BTNU_I <= keydeb;
end Behavioral;
//main.vhdl
//declared ports
Port (
BTNU: in std_logic; //button
CPU_RESETN: in std_logic;
CLK100MHZ: in std_logic;
);
//declared signals
signal Qint10m: std_logic_vector(3 downto 0); //number which holds the number to display
signal BTNU_I: std_logic; //button debounced
signal testC: integer range 9 downto 0; //counter
BTNU_debounce: entity Work.Debounce port map(
CLK100MHZ => CLK100MHZ,
BTNU => BTNU,
BTNU_I => BTNU_I);
bcd_counttest: process(CPU_RESETN, CLK100MHZ, BTNU_I)
begin
if(CPU_RESETN='0') then
testC <= 0;
elsif( CLK100MHZ'event and CLK100MHZ = '1') then
if(BTNU_I = '1') then
if(testC = 8) then
testC <= 0;
else
testC <= testC+1 ;
end if;
end if;
end if;
end process bcd_counttest;
Qint10m <= std_logic_vector(to_unsigned(testC, Qint10m'length));
I did not check your code very well, but noticed a de-bounce counter of 63 on a 100MHz clock. That is 630 ns.
A button can easily bounces for several milliseconds (depending on the button type) . So I suggest you start with using a bigger counter.
p.s. I am not very familiar with VHDL but this:
wait until rising_edge(CLK100MHZ);
can not be synthesized in Verilog.
I suggest you have a good look at your whole debounce process as I also see no sensitivity list and a latch!

Error(10820) and (10822) VHDL

i am trying to write a code but i get error, i dont understand that, i am new to vhdl, any help would be appreciated.
code:
entity counter is
port
(
upp_down : in std_logic;
rst : in std_logic;
pressed : in std_logic;
count : out std_logic_vector(3 downto 0)
);
end entity;
architecture rtl of counter is
signal count_value: std_logic_vector(3 downto 0);
begin
process (rst,pressed,upp_down)
begin
if(rst'event and rst = '0') then
count <= "0000";
else
if(pressed'event and pressed = '0' ) then
if(upp_down = '1') then
count_value <= count_value + 1;
elsif(upp_down = '0') then
count_value <= count_value - 1;
end if;
end if;
end if;
end process;
count <= count_value;
end rtl;
Errors:
Error (10820): Netlist error at counter.vhd(28): can't infer register for count_value[1] because its behavior depends on the edges of multiple distinct clocks
Error (10822): HDL error at counter.vhd(28): couldn't implement registers for assignments on this clock edge
The first problem is that you're trying to use the edge of two different 'clocks' in one process. A particular process can only respond to one clock.
The second problem is that your code does not translate into any real-world hardware. There's nothing in the FPGA that can respond to there not being an edge of a clock, which is what you have described with your if(rst'event and rst = '0') then else structure.
Nicolas pointed out another problem (which your compiler didn't get as far as), which is that you're assigning count both inside and outside a process; this is not allowed, as signals can only be assigned in one process.
Generally the type of reset it looks like you're trying to implement would be written as in the example below:
process (rst,pressed,upp_down)
begin
if(rst = '0') then
count_value <= "0000";
elsif(pressed'event and pressed = '0' ) then
if(upp_down = '1') then
count_value <= count_value + 1;
elsif(upp_down = '0') then
count_value <= count_value - 1;
end if;
end if;
end process;
count <= count_value;
The reason for changing the reset to affect count_value, is that without this, the effect of your reset would only last one clock cycle, after which the count would resume from where it left off (Thanks #Jim Lewis for this suggestion).
In addition to your compile errors, you should try to use the rising_edge() or falling_edge() functions for edge detection, as they behave better than the 'event style.
The reset can be more easily implemented using count_value <= (others => '0'); this makes all elements '0', no matter how long count is.
Lastly, it looks like you're using the std_logic_arith package. There are many other answers discouraging the use of this package. Instead, you should use the numeric_std package, and have your counter of type unsigned. If your output must be of type std_logic_vector, you can convert to this using a cast: count <= std_logic_vector(count_value);.
One more thing, I just noticed that your counter is not initialised; this can be done in the same way as I suggested for the reset function, using the others syntax.
"count" can't be assigned inside and outside a process.
count <= "0000"; <-- inside process
count <= count_value; <-- outside process.
You should do "count <= count_value;" inside your process :
entity counter is
port
(
upp_down : in std_logic;
rst : in std_logic;
pressed : in std_logic;
count : out std_logic_vector(3 downto 0)
);
end entity;
architecture rtl of counter is
signal count_value: std_logic_vector(3 downto 0);
begin
process (rst,pressed,upp_down)
begin
if(rst'event and rst = '0') then
count <= "0000";
else
if(pressed'event and pressed = '0' ) then
if(upp_down = '1') then
count_value <= count_value + 1;
elsif(upp_down = '0') then
count_value <= count_value - 1;
end if;
count <= count_value;
end if;
end if;
end process;
end rtl;

Random LED turning on and off in VHDL

I want to implement a random-number game on BASYS2. In this game there would be five LEDs chosen out of which one would turn on at random for a second or two (this time can be changed to increase or decrease the difficulty level of the game). Then the user is required to respond to this LED event by pressing the switch button behind it within the time that it is on. If he or she is able to do so successfully a point would be scored and it would be showed on the Seven Segment Display. If he or she fails no point would be scored. There would be 9 such events after which the game can be replayed.
Now following is my code (only for the random LED turning on). However, I am unable to fix it. Please somebody help. The FPGA I am using is BASYS2 SPARTAN 3E-100.
Thanks in advance to everyone.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.STD_LOGIC_arith.ALL;
entity random_number is
generic ( width : integer := 4 );
port (
clk : in std_logic;
reset : in std_logic;
random_num : out std_logic_vector (width-1 downto 0) --output vector
);
end random_number;
architecture Behavioral of random_number is
signal q: std_logic_vector(23 downto 0);
signal divided_clock: std_logic;
begin
process(clk, reset)
begin
if (reset = '1')then
q <= X"000000";
elsif(rising_edge(clk)) then
q <= q + 1;
end if;
end process;
divided_clock <= q(22);
process (divided_clock)
variable rand_temp : std_logic_vector(width-1 downto 0):=("1000");
variable temp : std_logic := '0';
begin
if(rising_edge(divided_clock)) then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
end if;
random_num <= rand_temp;
end process;
end Behavioral;
I think the second process should even run with the main clk and the devided clock should be an enable.
signal divided_enable: std_logic;
process(clk, reset)
begin
if (reset = '1')then
q <= X"000000";
elsif(rising_edge(clk)) then
q <= q + 1;
end if;
if (q(22) = '1') then
--short pulse wenn q bit 22 is high
divided_enable <= '1';
q <= (others => '0');
end if;
end process;
process (clk)
variable rand_temp : std_logic_vector(width-1 downto 0):=("1000");
variable temp : std_logic := '0';
begin
if(rising_edge(clk)) then
if(divided_enable = '1') then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
end if;
end if;
random_num <= rand_temp;
end process;
I don't know if this will fix all your problems. Please discribe compiler errors or errors in the behavior.

VHDL variable check in clk cycle

I am trying to compare two values in a clk cycle
eg:
if(riding_edge(clk)) then
if (some signal = other) then
other<=other+1;
else other<=other;
if(other=3)then
flag=1;
end if;
end if;
The code compiles and runs fine but when I am seeing the simulation window, the flag gets set no matter what is the value of other. Am I doing something wrong or the value of other is fluctuating.
The above is a pseudo code and everything is correct syntactically.
Please Help
Thanks in advance
Without a minimal working example, I could only guess that you're inferring a latch by not specifying what happens to flag when other is not 3. To prevent this, you would specify all cases of any decision tree.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY example IS
PORT (some_signal : IN STD_LOGIC;
other : IN STD_LOGIC;
clk : IN STD_LOGIC;
flag : OUT STD_LOGIC;
);
END example;
ARCHITECTURE minimal OF example IS
BEGIN
minexample:PROCESS(clk)
BEGIN
IF (clk'EVENT and clk='1') THEN
IF some_signal = other THEN
other <= other + '1';
ELSE other <= other;
END IF;
IF(other = '1') THEN
flag <= '1';
ELSE flag <= '0'; -- always specify all cases
END IF;
END IF;
END PROCESS minexample;
END minimal;
I use the code of N8TRO and add an reset to set the signal to zero at the startup and change the signal other to integer (because you like to check on the value 3) and check on rising_edge (should be the better way).
Now the signal flag should raise to high after 4 clocks after the Reset is set to low. Is this the behavior you expect?
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY example IS
PORT (some_signal : IN STD_LOGIC;
other : IN integer range 0 to 3; --this should be an integer 2 bit widht
clk : IN STD_LOGIC;
reset : IN STD_LOGIC;
flag : OUT STD_LOGIC;
);
END example;
ARCHITECTURE minimal OF example IS
BEGIN
minexample:PROCESS(clk,reset)
BEGIN
IF (reset = '1') then --i think a reset is a good idea
flag <= '0';
other <= 0;
ELSIF (rising_edge(clk)) THEN
IF some_signal = other THEN
other <= other + 1;
ELSE
other <= other;
END IF;
IF(other = 3) THEN --other is now an integer, so you can check on 3
flag <= '1';
ELSE
flag <= '0'; -- always specify all cases
END IF;
END IF;
END PROCESS minexample;
END minimal;

VHDL shift register with enable

I am newbie to VHDL. I am implementing serial in serial out 72 bit shift register using VHDL. When the enable signal is high, I want the shift register to shift 72 times, irrespective of whether enable continues to be high or low. I have written the following code which is working only when the enable is high. Can anyone please help me to shift data once enable is high and then does not depend on enable to shift the data?
library ieee;
use ieee.std_logic_1164.all;
entity SR is
port(clk, din, rst, enable : in std_logic;
sr_out : inout std_logic_vector(71 downto 0));
end SR;
architecture behavioral of SR is
signal shift_reg: std_logic_vector(71 downto 0);
begin
process (clk, rst)
begin
if (rst = '0') then
shift_reg <= (others => '0');
elsif (clk'event and clk = '1') then
if enable= '1' then
shift_reg(70 downto 0) <= shift_reg(71 downto 1);
shift_reg(71) <= din;
end if;
end if;
end process;
sr_out <= shift_reg;
end behavioral;
Thanks a lot!
I think you need an RS-FlipFlop which is set by a start signal. Its output is your enable signal. The start signal also starts a 72 clock cycle counter. When the counter rolls over (or reaches zero, depending on its direction) you reset the FlipFlop which results in a disabled shift register.
edit: In addition you can add a gate to the start signal which blocks new start impulses while the counter is active. So you can be sure your data is only shifted with a multiple of 72 bits.
You need a two states machine to do so. Here's a very good idea of how to do it. I'm pretty sure it does what you need or is very close to.
library ieee;
use ieee.std_logic_1164.all;
entity SR is
port(
clk : in std_logic;
din : in std_logic;
rst : in std_logic;
enable : in std_logic;
sr_out : inout std_logic_vector(71 downto 0)
);
end SR;
architecture behavioral of SR is
signal shift_reg : std_logic_vector(71 downto 0);
signal shift_cnt : integer range 0 to 72 := 0;
type T_STATE_TYPE is (IDLE, COUNTING);
signal current_state : T_STATE_TYPE;
begin
p_shift_counter : process(clk,rst)
begin
if rst = '1' then
current_state <= IDLE;
shift_cnt <= 0;
elsif rising_edge(clk) then
if (current_state = IDLE) then --no enable detected yet
shift_cnt <= 0;
if enable = '1' then
current_state <= COUNTING;
end if;
elsif (current_state = COUNTING) then --will stay in that state until it finishes counting
if (shift_cnt < 72) then
shift_reg(0) <= din;
for i in 0 to 71 loop shift_reg(i+1) <= shift_reg(i); end loop; --shifting register
shift_cnt <= shift_cnt + 1;
else
current_state <= IDLE; --finished counting
end if;
end if;
end if;
end process;
sr_out <= shift_reg;
end behavioral;

Resources