Why does the LCD of a Spartan 3AN is not working? - initialization

This is the subprogram for the LCD:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity VideoTest is
port( LCD_E, LCD_RS, LCD_RW : OUT std_logic;
LCD_DB : OUT std_logic_vector(7 downto 0);
counter: IN integer;
clk: IN std_logic);
end VideoTest;
architecture Behavioral of VideoTest is
signal InitDone: std_logic :='0';
begin
InitAndSet: process (InitDone, counter, clk) is
variable tencounter: integer :=0;
variable tempcounter: integer :=0;
begin
if (clk'event and clk='1') then
if (InitDone = '0') then
-- Enabling
LCD_E <='1';
-- Clear Screen
LCD_RS<='0';
LCD_RW<='0';
LCD_DB(7 downto 1) <= "0000000";
LCD_DB(0) <= '1';
-- Return Cursor Home
LCD_RS<='0';
LCD_RW<='0';
LCD_DB(7 downto 2) <= "000000";
LCD_DB(1) <= '1';
LCD_DB(0) <= '0';
-- Setting incrementation and moving cursor;
LCD_RS<='0';
LCD_RW<='0';
LCD_DB(7 downto 3) <= "00000";
LCD_DB(2) <= '1';
LCD_DB(1) <= '1';
LCD_DB(0) <= '0';
-- Display On, show cursor, blink cursor
LCD_RS<='0';
LCD_RW<='0';
LCD_DB(7 downto 4) <= "0000";
LCD_DB(3) <= '1';
LCD_DB(2) <= '1';
LCD_DB(1) <= '1';
LCD_DB(0) <= '1';
-- Function set
LCD_RS<='0';
LCD_RW<='0';
LCD_DB(7 downto 6) <= "00";
LCD_DB(5) <= '1';
LCD_DB(4) <= '0';
LCD_DB(3) <= '1';
LCD_DB(2) <= '0';
LCD_DB(1) <= '1';
LCD_DB(0) <= '1';
-- Set DD Adress to 0
LCD_RS<='0';
LCD_RW<='0';
LCD_DB(7)<='1';
LCD_DB(6 downto 0) <= "0000000";
InitDone <= '0';
end if;
-- Setting the value (0 to 9 is equal to 00110000 to 00111001)
if (InitDone = '1') then
if (counter < 10) then
LCD_RS<='1';
LCD_RW<='0';
case counter is
when 0 =>
LCD_DB <="00110000";
when 1 =>
LCD_DB <="00110001";
when 2 =>
LCD_DB <="00110010";
when 3 =>
LCD_DB <="00110011";
when 4 =>
LCD_DB <="00110100";
when 5 =>
LCD_DB <="00110101";
when 6 =>
LCD_DB <="00110110";
when 7 =>
LCD_DB <="00110111";
when 8 =>
LCD_DB <="00111000";
when 9 =>
LCD_DB <="00111001";
when others =>
LCD_DB <="00000000";
end case;
-- if counter is greater than 10, then put the number in two addresses.
elsif (counter > 9) then
LCD_DB <="00000000";
tempcounter :=counter;
for i in 0 to 8 loop
if tempcounter > 9 then
tempcounter := tempcounter - 10;
end if;
end loop;
tencounter := counter - tempcounter;
case tencounter is
when 0 =>
LCD_DB <="00110000";
when 1 =>
LCD_DB <="00110001";
when 2 =>
LCD_DB <="00110010";
when 3 =>
LCD_DB <="00110011";
when 4 =>
LCD_DB <="00110100";
when 5 =>
LCD_DB <="00110101";
when 6 =>
LCD_DB <="00110110";
when 7 =>
LCD_DB <="00110111";
when 8 =>
LCD_DB <="00111000";
when 9 =>
LCD_DB <="00111001";
when others =>
LCD_DB <="00000000";
end case;
LCD_RS<='0';
LCD_RW<='0';
LCD_DB(7)<='1';
LCD_DB(6 downto 1) <= "000000";
LCD_DB(0) <='1';
case tempcounter is
when 0 =>
LCD_DB <="00110000";
when 1 =>
LCD_DB <="00110001";
when 2 =>
LCD_DB <="00110010";
when 3 =>
LCD_DB <="00110011";
when 4 =>
LCD_DB <="00110100";
when 5 =>
LCD_DB <="00110101";
when 6 =>
LCD_DB <="00110110";
when 7 =>
LCD_DB <="00110111";
when 8 =>
LCD_DB <="00111000";
when 9 =>
LCD_DB <="00111001";
when others =>
LCD_DB <="00000000";
end case;
end if;
end if;
end if;
end process InitAndSet;
end Behavioral;
Here are the User Constraints:
-- Constraints
NET "LCD_E" LOC = "AB4" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_RS" LOC = "Y14" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_RW" LOC = "W13" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<7>" LOC = "Y15" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<6>" LOC = "AB16" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<5>" LOC = "Y16" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<4>" LOC = "AA12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<3>" LOC = "AB12" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<2>" LOC = "AB17" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<1>" LOC = "AB18" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
NET "LCD_DB<0>" LOC = "Y13" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
As I've seen this program should activate the LCD Display since I've clear all of the old saved things in the memory, I've set the cursor to 0 location and then on specific number that increments (in the main project) it indicates the number on the screen. I've taken the constraints and the encoding directly from the User Manual for the Spartan 3AN - Beginner Kit.
Am I missing something? It acts as it is not powered or something.
Thanks in advance,
Bojan Matovski

if (clk'event and clk='1') then
if (InitDone = '0') then
-- Enabling
LCD_E <='1';
-- Clear Screen
LCD_RS<='0';
LCD_RW<='0';
LCD_DB(7 downto 1) <= "0000000";
LCD_DB(0) <= '1';
etc etc etc.....
One problem: You're missing a state machine in this first part. Check out Case statements and how they work with state machines. What will happen in the code you wrote is that LCD_RD, LCD_RW, etc will just be replaced with the LAST line of code that you have in that if statement. Everything prior to that will be unused.
Another problem: InitDone never gets set to '1'. Ever.
Yet another problem:
for i in 0 to 8 loop
if tempcounter > 9 then
tempcounter := tempcounter - 10;
end if;
end loop;
This for loop doesn't behave the way you think it does. You need to read about for loops in synthesizable code. They do not behave like C for loops.

Related

Button debouncing circuit full count based:

i am trying to practice debouncing on FPGA following the approach (full count based), that introduced in the book from Volnei ("Circuit Design with VHDL third edition").
A very important feature of this circuit is the way the timer is constructed, which eliminates the need for a comparator (a large circuit).
For example, for the numeric values just given, $S = 50,MHz * 20,ms= 10e6$ results, where the number of bits (DFFs) in the counter is $N= log_2(S) = 20$ implying a counter running from zero to $10e6 - 1$ = 1 1 1 1_0100_0010_00 1 1_1 1 1 1, thus requiring a comparator that is at least 12 bits wide (only the s need to be monitored), which is indeed a large circuit. This can be avoided by taking into consideration that the time does not need to be exact in debouncers, so if an extra bit (flip-flop) is included in the counter, its MSB alone can play the role of comparator; when MSB= 1 occurs, it enables the output register, so y is updated, leading subsequently to clear= 1, which zeros the counter (and therefore the MSB too) at the next positive clock edge. In summary, the counter spans a total of $ S = 2^N+ 1$ states, leading to $T{deb} = 2^N/f_{clk (50MHz)} = 21 ms$ for the numeric values given above.
However, testing the code given from this Example not giving the expected result.
Debouncing
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
USE IEEE.math_real.ALL;
ENTITY E13_button_debouncer IS
GENERIC (
T_DEB_MS : NATURAL := 25;
f_clk : NATURAL := 50_000);
PORT (
clk : IN STD_LOGIC;
rst : IN STD_LOGIC;
b_in : IN STD_LOGIC;
b_out : OUT STD_LOGIC
);
END E13_button_debouncer;
ARCHITECTURE single_switch OF E13_button_debouncer IS
CONSTANT COUNTER_BITS : NATURAL := 1 + INTEGER(ceil(log2(real(T_DEB_MS * f_clk))));
-- ! Optional :
SIGNAL x_reg : STD_LOGIC;
BEGIN
proc_name : PROCESS (clk)
VARIABLE count : unsigned(COUNTER_BITS - 1 DOWNTO 0);
BEGIN
IF rising_edge(clk) THEN
IF rst = '0' THEN
count := (OTHERS => '0');
x_reg <= '0';
b_out <= '0';
ELSE
x_reg <= b_in;
IF b_out = x_reg THEN
count := (OTHERS => '0');
ELSE
count := count + 1;
END IF;
END IF;
END IF;
IF falling_edge(clk) THEN
IF count(COUNTER_BITS - 1) THEN
b_out <= NOT b_out;
END IF;
END IF;
END PROCESS proc_name;
END ARCHITECTURE;
Test Bench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY E13_button_debouncer_tb IS
END E13_button_debouncer_tb;
ARCHITECTURE sim OF E13_button_debouncer_tb IS
CONSTANT clk_hz : INTEGER := 50_000;
CONSTANT clk_period : TIME := 1 sec / clk_hz;
CONSTANT T_DEB_MS : NATURAL := 25;
SIGNAL clk : STD_LOGIC := '1';
SIGNAL rst : STD_LOGIC := '0';
SIGNAL b_in : STD_LOGIC := '0';
SIGNAL b_out : STD_LOGIC := '1';
BEGIN
clk <= NOT clk AFTER clk_period / 2;
bu_deboun : ENTITY work.E13_button_debouncer(single_switch)
GENERIC MAP(f_clk => clk_hz, T_DEB_MS => T_DEB_MS)
PORT MAP(
clk => clk,
rst => rst,
b_in => b_in,
b_out => b_out
);
SEQUENCER_PROC : PROCESS
BEGIN
WAIT FOR clk_period * 1;
rst <= '1';
b_in <= '1';
WAIT FOR 1 ms;
b_in <= '0';
WAIT FOR 1 ms;
b_in <= '1';
WAIT FOR 100 ms;
b_in <= '0';
WAIT FOR 1 ms;
b_in <= '1';
WAIT FOR 10 ms;
b_in <= '0';
WAIT FOR 10 ms;
END PROCESS;
END ARCHITECTURE;
Simulation
I expepct that the code work like photo below:
to solve the problem first to avoid errors when synthesize it need the changes to the code thanks to (#thebusybee, #user16145658,#MatthiasSchweikart):
BEGIN
IF rising_edge(clk) THEN
IF rst = '0' THEN
count := (OTHERS => '0');
x_reg <= '0';
ELSE
x_reg <= b_in;
IF b_out = x_reg THEN
count := (OTHERS => '0');
ELSE
count := count + 1;
END IF;
END IF;
END IF;
IF falling_edge(clk) THEN
IF rst = '0' THEN
b_out <= '0';
ELSE
REPORT "we are in falling edge and the counter value : " & INTEGER'image(to_integer(count));
IF count(COUNTER_BITS - 1) THEN
b_out <= NOT b_out;
END IF;
END IF;
END IF;
END PROCESS proc_name;
END ARCHITECTURE;
the problem was here:
GENERIC (
T_DEB_MS : NATURAL := 25;
f_clk : NATURAL := 50_000);
PORT (
clk : IN STD_LOGIC;
rst : IN STD_LOGIC;
b_in : IN STD_LOGIC;
b_out : OUT STD_LOGIC
);
END E13_button_debouncer;
ARCHITECTURE single_switch OF E13_button_debouncer IS
CONSTANT COUNTER_BITS : NATURAL := 1 + INTEGER(ceil(log2(real(T_DEB_MS * f_clk))));
which result in N=21 that mean the debounce time will be 41 Second. so to solve it i should do it like this : 0.025 * fclk = 1250 => result in N= 10 => +1 =11.
then the counter will count till 2048 resulting in debounce time von 40 ms. which is ok for my application.

Why do I get undefined output vectors and an undefined clock when simulating?

I am pretty new to VHDL and am encountering an error with my testbench (at least I believe its only in the testbench).
My programme simulates a stadium with 12 sections. The programme consists of 12 individual counters along with LEDs when 90% of max capacity is reached and a digital 4 digit display that displays the total of all 12 counters.
Whenever I try to compile the code, there is no change in any of the outputs and all of the inputs are undefined.
Any advice would be appreciated.
Architecture:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.Numeric_STD.all;
entity counter is
Port (Clk: in STD_LOGIC;
Enable : in STD_LOGIC_Vector(11 downto 0);
Reset : in STD_LOGIC_Vector(11 downto 0);
Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8,Q9,Q10,Q11,Q12 : out STD_LOGIC_Vector(8 downto 0); -- 9 bits as 300 <2^9
Qt : out STD_LOGIC_Vector(11 downto 0); -- 12 bits as 300 (section) * 12 > 2^12
a,b,c,d,e,f,g : out STD_LOGIC_Vector(3 downto 0); --Individual segments of the display (4 because the number will max out at 3600)
Led0,Led1,Led2,Led3,Led4,Led5,Led6,Led7,Led8,Led9,Led10,Led11 : out STD_LOGIC);
end counter;
Architecture behavioral of counter is
type REG_variable is array(0 to 11) of unsigned(8 downto 0);
type Q_variable is array (0 to 11) of STD_LOGIC_Vector(8 downto 0);
type DIGITS_variable is array (0 to 3) of unsigned (3 downto 0);
signal output_array : Q_variable;
signal LED_Output : STD_LOGIC_Vector(11 downto 0);
component count_comp is
Port(Clk, Reset, Enable : in STD_Logic;
Q : out STD_LOGIC_Vector(8 downto 0);
LED : out STD_LOGIC);
end component;
begin
process (CLK,Reset)
variable LED_lights : STD_LOGIC_Vector(11 downto 0) := (others => '0');
variable REG : REG_variable := (others =>(others => '0'));
variable Total_REG: unsigned(11 downto 0) := (others => '0');
variable Digits : DIGITS_variable := (others => (others => '0'));
begin
Single_Counter : for i in 11 downto 0 loop
if Reset(i) = '1' then
Total_REG := Total_REG - REG(i);
REG(i) := (others => '0');
LED_lights(i) := '0';
elsif rising_edge(CLK) then
if Enable(i) = '1' and (REG(i) <= 300) then
if (REG(i) >= 270) then
LED_lights(i) := '1';
Total_REG := Total_REG + 1;
REG(i) := REG(i)+ 1;
end if;
Digits(0) := to_unsigned(to_integer(Total_REG - Total_REG mod 100),4);
Digits(1) := to_unsigned(to_integer((Total_REG - Total_REG mod 100)/10),4);
Digits(2) := to_unsigned(to_integer((Total_REG - Total_REG mod 100)/100),4);
Digits(3) := to_unsigned(to_integer((Total_REG - Total_REG mod 100)/1000),4);
end if;
end if;
Qt <= STD_LOGIC_Vector(Total_REG);
output_array(i) <= STD_LOGIC_Vector(REG(i));
LED_output(i) <= LED_lights(i);
for x in 3 downto 0 loop
case to_integer(Digits(x)) is
when 0
=> a(x) <= '1'; b(x) <= '1'; c(x) <= '1'; d(x) <= '1'; e(x) <= '1'; f(x) <= '1'; g(x) <= '0';
when 1
=> a(x) <= '0'; b(x) <= '1'; c(x) <= '1'; d(x) <= '0'; e(x) <= '0'; f(x) <= '0'; g(x) <= '0';
when 2
=> a(x) <= '1'; b(x) <= '1'; c(x) <= '0'; d(x) <= '1'; e(x) <= '1'; f(x) <= '0'; g(x) <= '1';
when 3
=> a(x) <= '1'; b(x) <= '1'; c(x) <= '1'; d(x) <= '1'; e(x) <= '0'; f(x) <= '0'; g(x) <= '1';
when 4
=> a(x) <= '0'; b(x) <= '1'; c(x) <= '1'; d(x) <= '0'; e(x) <= '0'; f(x) <= '1'; g(x) <= '1';
when 5
=> a(x) <= '1'; b(x) <= '0'; c(x) <= '1'; d(x) <= '1'; e(x) <= '0'; f(x) <= '1'; g(x) <= '1';
when 6
=> a(x) <= '1'; b(x) <= '0'; c(x) <= '1'; d(x) <= '1'; e(x) <= '1'; f(x) <= '1'; g(x) <= '1';
when 7
=> a(x) <= '1'; b(x) <= '1'; c(x) <= '1'; d(x) <= '0'; e(x) <= '0'; f(x) <= '0'; g(x) <= '0';
when 8
=> a(x) <= '1'; b(x) <= '1'; c(x) <= '1'; d(x) <= '1'; e(x) <= '1'; f(x) <= '1'; g(x) <= '1';
when 9
=> a(x) <= '1'; b(x) <= '1'; c(x) <= '1'; d(x) <= '1'; e(x) <= '0'; f(x) <= '1'; g(x) <= '1';
when others
=> a(x) <= '0'; b(x) <= '0'; c(x) <= '0'; d(x) <= '0'; e(x) <= '0'; f(x) <= '0'; g(x) <= '0';
end case;
end loop;
end loop;
end process;
Counters : for i in 11 downto 0 generate
counter_gen : count_comp
port map (CLK => CLK, Reset => Reset (i), Enable => Enable(i), Q => output_array(i), LED => LED_output(i));
end generate;
Q1 <= output_array(0);
Q2 <= output_array(1);
Q3 <= output_array(2);
Q4 <= output_array(3);
Q5 <= output_array(4);
Q6 <= output_array(5);
Q7 <= output_array(6);
Q8 <= output_array(7);
Q9 <= output_array(8);
Q10 <= output_array(9);
Q11 <= output_array(10);
Q12 <= output_array(11);
Led0 <= LED_output(0);
Led1 <= LED_output(1);
Led2 <= LED_output(2);
Led3 <= LED_output(3);
Led4 <= LED_output(4);
Led5 <= LED_output(5);
Led6 <= LED_output(6);
Led7 <= LED_output(7);
Led8 <= LED_output(8);
Led9 <= LED_output(9);
Led10 <= LED_output(10);
Led11 <= LED_output(11);
end behavioral;
Testbench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Project_Testbench is
end;
architecture TB1 of Project_Testbench is
component count_comp is
Port(Clk: in STD_LOGIC;
Enable : in STD_LOGIC_Vector(11 downto 0);
Reset : in STD_LOGIC_Vector(11 downto 0);
Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8,Q9,Q10,Q11,Q12 : out STD_LOGIC_Vector(8 downto 0);
Qt : out STD_LOGIC_Vector(11 downto 0);
a,b,c,d,e,f,g : out STD_LOGIC_Vector(3 downto 0);
Led0,Led1,Led2,Led3,Led4,Led5,Led6,Led7,Led8,Led9,Led10,Led11 : out STD_LOGIC);
end component count_comp;
signal Clk_TB : std_logic := '0';
signal Enable : std_logic_Vector(11 downto 0) := (others => '0');
signal Reset : std_logic_Vector(11 downto 0) := (others => '0');
begin
Clk_TB <= not Clk_TB after 5ns;
stimuli: process
begin
Enable <= "000000000000"; Reset <= "11111111111";
wait for 100 ns;
Enable <= "11111111111"; Reset <= "00000000000";
wait for 200 ns;
Enable <= "11110011111"; Reset <= "00000000000";
wait for 50 ns;
Enable <= "00011111111"; Reset <= "00000000000";
wait for 20 ns;
Enable <= "11111111111"; Reset <= "11000000000";
wait for 20 ns;
Enable <= "11111111111"; Reset <= "00000000000";
wait for 1000 ns;
wait;
end process;
uut: count_comp port map
(
Clk => Clk_TB,
Enable => Enable,
Reset => Reset);
end;
Here is a screenshot of the output signals.
Output Signals

Debounce Code Correction for a Decimal Counter Project in 1Hz counting Speed

I am completly new for the FPGA and basys3 development board.
I have a project for Counter on the 7 segment displays on the board.
We got 3 different layers as a design.
cntr /
cntr_rtl /
cntr_top /
cntr_top_struc /
io_ctrl /
io_ctrl_rtl /
And in the project it has to diplay on the 7 segment controlled by the switches : count up/count down / hold / reset options:
The priorities for these switches are:
reset
hold
count direction
top level VHDL file cntr_top.vhd
Port Name Direction Description
clk_i In System clock (100 MHz)
reset_i In Asynchronous high active reset
sw_i(15:0) In 16 switches
pb_i(3:0) In 4 buttons
ss_o(7:0) Out Contain the value for all 7-segment digits
ss_sel_o(3:0) Out Select a 7-segment digit
io_ctrl
clk_i In System clock (100 MHz)
reset_i In Asynchronous high active reset
cntr0_i(n:0) In Digit 0 (from internal logic)
cntr1_i(n:0) In Digit 1 (from internal logic)
cntr2_i(n:0) In Digit 2 (from internal logic)
cntr3_i(n:0) In Digit 3 (from internal logic)
sw_i(15:0) In 16 switches (from FPGA board)
pb_i(3:0) In 4 buttons (from FPGA board)
ss_o(7:0) Out to 7-segment displays of the FPGA board
ss_sel_o(3:0) Out Selection of a 7-segment digit
swclean_o(15:0) Out 16 switches (to internal logic)
pbclean_o(3:0) Out 4 buttons (to internal logic)
cntr.vhd
clk_i In System clock (100 MHz)
reset_i In Asynchronous high active reset
cntrup_i In Counts up if signal is ‘1’
cntrdown_i In Counts down if signal is ‘1’
cntrreset_i In Sets counter to 0x0 if signal is ‘1’
cntrhold_i In Holds count value if signal is ‘1’
cntr0_o(n:0) Out Digit 0 (from internal logic)
cntr1_o(n:0) Out Digit 1 (from internal logic)
cntr2_o(n:0) Out Digit 2 (from internal logic)
cntr3_o(n:0) Out Digit 3 (from internal logic)
I will attach also the file to the attachment. Now my code is working and do all the funcitionality correct but there is only one issue which is the DEBOUNCE code part.
I didnt use the clk signal for the code and i have to change it. The certain given clock signal has to be used.
So can any be give me suggestions how i can correct the debounce concept in the code.
io_ctrl_rtl.vhd -code down below:
library IEEE;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
architecture rtl of io_ctrl is
constant COUNTVALUE : std_logic_vector(16 downto 0):= "01100001101010000";
signal s_enctr : std_logic_vector(16 downto 0):="00000000000000000";
signal s_2khzen : std_logic :='0';
signal s_1hzen : std_logic :='0';
signal s_2khzcount : std_logic_vector(3 downto 0) := "0000";
signal swsync0 : std_logic_vector(15 downto 0):="0000000000000000";
signal pbsync0 : std_logic_vector(3 downto 0):="0000";
signal swsync1 : std_logic_vector(15 downto 0):="0000000000000000";
signal pbsync1 : std_logic_vector(3 downto 0):="0000";
signal swtmp : std_logic_vector(15 downto 0):="0000000000000000";
signal pbtmp : std_logic_vector(3 downto 0):="0000";
signal swdebounced : std_logic_vector(15 downto 0):="0000000000000000";
signal pbdebounced : std_logic_vector(3 downto 0):="0000";
signal s_ss_sel : std_logic_vector(3 downto 0) := "0000";
signal s_ss : std_logic_vector(7 downto 0) := "00000000";
begin -- rtl
-----------------------------------------------------------------------------
--
-- Synchronize the inputs
--
-----------------------------------------------------------------------------
p_sync: process (clk_i, reset_i)
begin
if reset_i = '1' then
swsync0 <= (others => '0');
pbsync0 <= (others => '0');
swsync1 <= (others => '0');
pbsync1 <= (others => '0');
elsif clk_i'event and clk_i = '1' then
swsync0 <= sw_i;
pbsync0 <= pb_i;
swsync1 <= swsync0;
pbsync1 <= pbsync0;
else null;
end if;
end process;
-----------------------------------------------------------------------------
--
-- Generate 1 KHz enable signal.
--
-----------------------------------------------------------------------------
p_slowen: process (clk_i, reset_i)
begin
if reset_i = '1' then
s_enctr <= (others => '0');
s_2khzen <= '0';
elsif clk_i'event and clk_i = '1' then
if s_enctr = COUNTVALUE then -- When the terminal counter is reached, set the release flag and reset the counter
s_enctr <= (others => '0');
s_2khzen <= '1';
s_2khzcount <= std_logic_vector(to_unsigned(to_integer(unsigned( s_2khzcount )) + 1, 4));
else
s_enctr <= std_logic_vector(to_unsigned(to_integer(unsigned( s_enctr )) + 1, 17)); -- As long as the terminal count is not reached: increment the counter.
if s_2khzen = '1' then
s_2khzen <= '0';
end if;
end if;
if s_2khzcount = "1010" then
s_1hzen <= not s_1hzen;
s_2khzcount <= "0000";
end if;
end if;
end process p_slowen;
-----------------------------------------------------------------------------
--
-- Debounce buttons and switches
--
-----------------------------------------------------------------------------
p_debounce: process (s_1hzen, reset_i)
variable dbouncecntr : integer:=0;
begin
if reset_i = '1' then
swdebounced <= "0000000000000000";
pbdebounced <= "0000";
dbouncecntr :=0; -- Change clocking the process with signal from sens list.
else
if (dbouncecntr = 0) then
swtmp <= swsync1;
pbtmp <= pbsync1;
dbouncecntr := dbouncecntr + 1;
elsif (dbouncecntr = 1) then
if (swtmp = swsync1) then
swdebounced <= swsync1;
end if;
if (pbtmp = pbsync1) then
pbdebounced <= pbsync1;
end if;
dbouncecntr := 0;
end if;
end if;
end process p_debounce;
swclean_o <= swdebounced;
pbclean_o <= pbdebounced;
-----------------------------------------------------------------------------
--
-- Display controller for the 7-segment display
--
-----------------------------------------------------------------------------
p_displaycontrol: process (clk_i, reset_i)
variable v_scancnt : std_logic_vector(1 downto 0):= "00";
variable v_output : std_logic_vector(3 downto 0):="0000";
begin
if reset_i = '1' then
v_scancnt := "00";
s_ss <= "00000000";
elsif clk_i'event and clk_i = '1' then
if s_2khzen = '1' then
case v_scancnt is
when "00" =>
v_output := cntr0_i;
s_ss_sel <= "0001";
when "01" =>
v_output := cntr1_i;
s_ss_sel <= "0010";
when "10" =>
v_output := cntr2_i;
s_ss_sel <= "0100";
when "11" =>
v_output := cntr3_i;
s_ss_sel <= "1000";
when others =>
v_output := "1111";
s_ss_sel <= "0001";
end case;
case v_output is --ABCDEFG,
when "0000" => s_ss <= "11111100"; --0
when "0001" => s_ss <= "01100000"; --1
when "0010" => s_ss <= "11011010"; --2
when "0011" => s_ss <= "11110010"; --3
when "0100" => s_ss <= "01100110"; --4
when "0101" => s_ss <= "10110110"; --5
when "0110" => s_ss <= "10111110"; --6
when "0111" => s_ss <= "11100000"; --7
when "1000" => s_ss <= "11111110"; --8
when "1001" => s_ss <= "11110110"; --9
when others => s_ss <= v_scancnt & "000000";
end case;
if v_scancnt = "11" then
v_scancnt := "00";
else
v_scancnt := std_logic_vector(to_unsigned(to_integer(unsigned( v_scancnt )) + 1, 2));
end if;
else null;
end if;
else null;
end if;
end process p_displaycontrol;
ss_o <= not s_ss;
ss_sel_o <= not s_ss_sel;
end rtl;
The code for : cntr_top_struc.vhd
library IEEE;
use IEEE.std_logic_1164.all;
architecture rtl of cntr_top is
component cntr -- component of cntr
port (clk_i: in std_logic; -- 100 MHz system clock
reset_i: in std_logic; -- async high active reset
cntrup_i : in std_logic; --counts up if signal is '1'
cntrdown_i : in std_logic; --counts down if signal is '1'
cntrreset_i : in std_logic; --sets counter to 0x0 if signal is '1'
cntrhold_i : in std_logic; --holds count value if signal is '1'
cntr0_o: out std_logic_vector(3 downto 0); -- Digit 0 (from internal logic)
cntr1_o: out std_logic_vector(3 downto 0); -- Digit 1 (from internal logic)
cntr2_o: out std_logic_vector(3 downto 0); -- Digit 2 (from internal logic)
cntr3_o: out std_logic_vector(3 downto 0)); -- Digit 3 (from internal logic)
end component;
component io_ctrl ---- component io_crtl
port (clk_i: in std_logic; -- 100 MHz system clock
reset_i: in std_logic; -- async high active reset
cntr0_i: in std_logic_vector(3 downto 0); -- Digit 0 (from internal logic)
cntr1_i: in std_logic_vector(3 downto 0); -- Digit 1 (from internal logic)
cntr2_i: in std_logic_vector(3 downto 0); -- Digit 2 (from internal logic)
cntr3_i: in std_logic_vector(3 downto 0); -- Digit 3 (from internal logic)
swclean_o: out std_logic_vector(15 downto 0);
pbclean_o: out std_logic_vector(3 downto 0);
ss_o: out std_logic_vector(7 downto 0); -- Contain the Value for All 7-Segment Digits
ss_sel_o: out std_logic_vector(3 downto 0); -- Select a 7-segment digits
pb_i: in std_logic_vector(3 downto 0); --4 Buttons
sw_i: in std_logic_vector(15 downto 0) ); --16 Switches
end component;
-- Declare the signals that are used to connect the submodules.
signal s_cntr0 : std_logic_vector(3 downto 0);
signal s_cntr1 : std_logic_vector(3 downto 0);
signal s_cntr2 : std_logic_vector(3 downto 0);
signal s_cntr3 : std_logic_vector(3 downto 0);
signal s_cntrup : std_logic;
signal s_cntrdown : std_logic;
signal s_cntrreset : std_logic;
signal s_cntrhold : std_logic;
signal s_overflow : std_logic_vector(11 downto 0);
begin
--Instantiate the counter that is connected to the IO-Control
i_cntr_top1 : cntr
port map
(clk_i => clk_i,
reset_i => reset_i,
-- cntrdir_i => s_cntrdir, --swsync_o(13);
cntrup_i => s_cntrup, --swsync_o(13);
cntrdown_i => s_cntrdown, --swsync_o(12);
cntrreset_i => s_cntrreset, --swsync_o(15),
cntrhold_i => s_cntrhold, --swsync_o(14),
cntr0_o => s_cntr0,
cntr1_o => s_cntr1,
cntr2_o => s_cntr2,
cntr3_o => s_cntr3);
--Instantiate the IO control to which it is connected
i_io_ctrl : io_ctrl
port map
(clk_i => clk_i,
reset_i => reset_i,
swclean_o(12) => s_cntrdown,
swclean_o(13) => s_cntrup,
swclean_o(15) => s_cntrreset,
swclean_o(14) => s_cntrhold,
swclean_o(11 downto 0) => s_overflow(11 downto 0),
cntr0_i => s_cntr0,
cntr1_i => s_cntr1,
cntr2_i => s_cntr2,
cntr3_i => s_cntr3,
ss_o => ss_o,
ss_sel_o => ss_sel_o,
sw_i => sw_i,
pb_i => pb_i);
end rtl;
cntr_top.vhd
library IEEE;
use IEEE.std_logic_1164.all;
entity cntr_top is
port (clk_i : in std_logic; -- First Data Bit
reset_i : in std_logic; -- Second Data Bit
sw_i : in std_logic_vector (15 downto 0); -- 16 Switches Input
pb_i : in std_logic_vector(3 downto 0); -- 4 Buttons Input
ss_o : out std_logic_vector(7 downto 0); -- Contain the Value for All 7-Segment Digits
ss_sel_o : out std_logic_vector(3 downto 0)); -- Select a 7-segment digits
end cntr_top;
io_ctrl.vhd
library IEEE;
use IEEE.std_logic_1164.all;
entity io_ctrl is
port (clk_i : in std_logic; -- System clock (100 MHZ)
reset_i : in std_logic; -- Asynchronous high active reset
cntr0_i : in std_logic_vector(3 downto 0); -- Digit 0 from internal logic
cntr1_i : in std_logic_vector(3 downto 0); -- Digit 1 from internal logic
cntr2_i : in std_logic_vector(3 downto 0); -- Digit 2 from internal logic
cntr3_i : in std_logic_vector(3 downto 0); -- Digit 3 from internal logic
sw_i : in std_logic_vector(15 downto 0); -- 16 switches (from FPGA board)
pb_i : in std_logic_vector(3 downto 0); -- 4 buttons (from FPGA board)
ss_o : out std_logic_vector(7 downto 0); -- to 7 segment displays of the FPGA board
ss_sel_o : out std_logic_vector(3 downto 0); -- Selection of a 7 segment digit
swclean_o: out std_logic_vector(15 downto 0); -- 16 switches (to internal logic)
pbclean_o : out std_logic_vector(3 downto 0)); -- 4 buttons
end io_ctrl;
cntr_rtl.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
architecture rtl of cntr is
constant COUNTVALUE : std_logic_vector(26 downto 0):= "000000000000000001111101000";
--constant COUNTVALUE : std_logic_vector(26 downto 0):= "101111101011110000100000000";
signal s_enctr : std_logic_vector(26 downto 0) := "000000000000000000000000000";
signal s_1hzen : std_logic :='0';
signal s_cntr0 : std_logic_vector(3 downto 0) :="0000"; -- All digits set to zero.
signal s_cntr1 : std_logic_vector(3 downto 0) :="0000";
signal s_cntr2 : std_logic_vector(3 downto 0) :="0000";
signal s_cntr3 : std_logic_vector(3 downto 0) :="0000";
type s_state is (reset, hold, up, down);
signal s_present_state : s_state;
signal s_next_state : s_state;
begin
p_cntr: process(clk_i, reset_i)
variable v_digit0 : std_logic_vector(3 downto 0):= "0000";
variable v_digit1 : std_logic_vector(3 downto 0):= "0000";
variable v_digit2 : std_logic_vector(3 downto 0):= "0000";
variable v_digit3 : std_logic_vector(3 downto 0):= "0000";
begin
if reset_i = '1' then
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := "0000";
v_digit3 := "0000";
s_enctr <= (others => '0');
elsif (clk_i'event and clk_i = '1') then
s_present_state <= s_next_state;
if s_enctr = COUNTVALUE then --When the number of terminals is reached, set the release flag and reset the counter
s_enctr <= (others => '0');
s_1hzen <= '1';
case s_present_state is
when up => --counting up.
if v_digit0 /= "1001" then
v_digit0 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit0 )) + 1, 4)); -- incrementing the bits.
elsif v_digit0 = "1001" and v_digit1 /= "1001" then
v_digit0 := "0000";
v_digit1 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit1 )) + 1, 4));
elsif v_digit0 = "1001" and v_digit1 = "1001" and v_digit2 /= "1001" then
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit2 )) + 1, 4));
elsif v_digit0 = "1001" and v_digit1 = "1001" and v_digit2 = "1001" and v_digit3 /= "1001"then
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := "0000";
v_digit3 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit3 )) + 1, 4));
else
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := "0000";
v_digit3 := "0000";
end if;
when down => --counting down.
if v_digit0 /= "0000" then
v_digit0 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit0 )) - 1, 4)); -- decrementing the bits.
elsif v_digit0 = "0000" and v_digit1 /= "0000" then
v_digit0 := "1001";
v_digit1 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit1 )) - 1, 4));
elsif v_digit0 = "0000" and v_digit1 = "0000" and v_digit2 /= "0000" then
v_digit0 := "1001";
v_digit1 := "1001";
v_digit2 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit2 )) - 1, 4));
elsif v_digit0 = "0000" and v_digit1 = "0000" and v_digit2 = "0000" and v_digit3 /= "0000"then
v_digit0 := "1001";
v_digit1 := "1001";
v_digit2 := "1001";
v_digit3 := std_logic_vector(to_unsigned(to_integer(unsigned( v_digit3 )) - 1, 4));
else
v_digit0 := "1001";
v_digit1 := "1001";
v_digit2 := "1001";
v_digit3 := "1001";
end if;
when hold => null; -- holding the counting.
when reset => -- reset all the values to zero.
v_digit0 := "0000";
v_digit1 := "0000";
v_digit2 := "0000";
v_digit3 := "0000";
end case;
else
s_enctr <=std_logic_vector(to_unsigned(to_integer(unsigned( s_enctr )) + 1, 27));
if s_1hzen = '1' then
s_1hzen <= '0';
end if;
end if;
s_cntr0 <= v_digit0;
s_cntr1 <= v_digit1;
s_cntr2 <= v_digit2;
s_cntr3 <= v_digit3;
end if;
end process p_cntr;
cntr0_o <= s_cntr0;
cntr1_o <= s_cntr1;
cntr2_o <= s_cntr2;
cntr3_o <= s_cntr3;
----------------------------------------------------------------------------------------------------------------
-- State machine
----------------------------------------------------------------------------------------------------------------
p_states: process(s_present_state, cntrup_i, cntrdown_i, cntrreset_i, cntrhold_i,reset_i)
begin
case s_present_state is
when reset => -- reset state conditions
if cntrreset_i = '1' then
s_next_state <= reset;
elsif cntrhold_i = '1' then
s_next_state <= hold;
elsif cntrup_i = '1' then
s_next_state <= up;
elsif cntrdown_i = '1' then
s_next_state <= down;
else s_next_state <= hold;
end if;
when hold => -- hold state conditions
if cntrreset_i = '1' then
s_next_state <= reset;
elsif cntrhold_i = '1' then
s_next_state <= hold;
elsif cntrup_i = '1' then
s_next_state <= up;
elsif cntrdown_i = '1' then
s_next_state <= down;
else s_next_state <= hold;
end if;
when up => -- up count state conditions
if cntrreset_i = '1' then
s_next_state <= reset;
elsif cntrhold_i = '1' then
s_next_state <= hold;
elsif cntrup_i = '1' then
s_next_state <= up;
elsif cntrdown_i = '1' then
s_next_state <= down;
else s_next_state <= hold;
end if;
when down => -- down count conditions
if cntrreset_i = '1' then
s_next_state <= reset;
elsif cntrhold_i = '1' then
s_next_state <= hold;
elsif cntrup_i = '1' then
s_next_state <= up;
elsif cntrdown_i = '1' then
s_next_state <= down;
else s_next_state <= hold;
end if;
when others => s_next_state <= reset;
end case;
end process p_states;
end rtl;
cntr.vhd
library IEEE;
use IEEE.std_logic_1164.all;
entity cntr is
port (clk_i : in std_logic; -- System clock (100 MHZ)
reset_i : in std_logic; -- Asysnchronous high active reset
cntrup_i : in std_logic; --counts up if signal is '1'
cntrdown_i : in std_logic; --counts down if signal is '1'
cntrreset_i : in std_logic; --sets counter to 0x0 if signal is '1'
cntrhold_i : in std_logic; --holds count value if signal is '1'
cntr0_o : out std_logic_vector(3 downto 0); -- Digit 0 (from internal logic)
cntr1_o : out std_logic_vector(3 downto 0); -- Digit 1 (from internal logic)
cntr2_o : out std_logic_vector(3 downto 0); -- Digit 2 (from internal logic)
cntr3_o : out std_logic_vector(3 downto 0)); -- Digit 3 (from internal logic)
end cntr;
Please waiting for your suggestions.
Any help would be great appricated thanks for all.
here down below example for debounce but couldnt find to way to implement.
-----------------------------------------------------------------------------
--
-- Debounce buttons and switches
--
-----------------------------------------------------------------------------
p_debounce: process (clk_i, reset_i)
begin -- process debounce
if reset_i = '1' then -- asynchronous reset (active high)
elsif clk_i'event and clk_i = '1' then -- rising clock edge
end if;
end process p_debounce;
swsync_o <= swsync;
pbsync_o <= pbsync;
------------------------------------------------------------
You're on the right track in that you need to synchronise the asynchronous inputs and debounce them.
But your debounce code needs to use a separate debouncer for each input with a timeout value of around 100 for a 1 kHz clock.
Here is a generic synchroniser and debouncer which uses parameters to specify the bus width, number of sync registers and timeout value.
Synchroniser.vhd
--
-- Synchronise an asynchronous bus input to avoid metastability problems
--
--
-- Signal Synchroniser (1 bit)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SynchroniserBit is
generic
(
reg_size: integer := 3 -- Default number of bits in sync register.
);
port
(
clock: in std_logic;
async_in: in std_logic := '0';
sync_out: out std_logic := '0';
rise: out std_logic := '0';
fall: out std_logic := '0'
);
end;
architecture V1 of SynchroniserBit is
constant MSB: integer := reg_size - 1;
signal sync_reg: std_logic_vector(MSB downto 0) := (others => '0');
begin
process (clock)
begin
if rising_edge(clock) then
rise <= not sync_reg(MSB) and sync_reg(MSB - 1);
fall <= sync_reg(MSB) and not sync_reg(MSB - 1);
sync_reg <= sync_reg(MSB - 1 downto 0) & async_in;
end if;
end process;
sync_out <= sync_reg(MSB);
end;
--
-- Bus Synchroniser (many bits)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Synchroniser is
generic
(
reg_size: integer := 3; -- Default number of bits in sync register.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
sync_bus_out: out std_logic_vector(bus_size - 1 downto 0);
rise_bus_out: out std_logic_vector(bus_size - 1 downto 0);
fall_bus_out: out std_logic_vector(bus_size - 1 downto 0)
);
end;
architecture V1 of Synchroniser is
component SynchroniserBit is
generic
(
reg_size: integer := 3 -- Default number of bits in sync register.
);
port
(
clock: in std_logic;
async_in: in std_logic;
sync_out: out std_logic;
rise: out std_logic;
fall: out std_logic
);
end component;
begin
SyncGen: for i in 0 to bus_size - 1 generate
begin
Sync: SynchroniserBit
generic map
(
reg_size => reg_size
)
port map
(
clock => clock,
async_in => async_bus_in(i),
sync_out => sync_bus_out(i),
rise => rise_bus_out(i),
fall => fall_bus_out(i)
);
end generate;
end;
Debouncer.vhd
--
-- Debounce a bus.
--
--
-- Signal Debouncer (1 bit)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity DebouncerBit is
port
(
clock: in std_logic;
counter: in integer;
input: in std_logic;
output: out std_logic := '0'
);
end;
architecture V1 of DebouncerBit is
begin
process(clock)
variable counter_snapshot: integer := 0;
variable previous_input: std_logic := '0';
begin
if rising_edge(clock) then
-- If counter wraps around to counter_snapshot,
-- a full debounce period has elapsed without a change in input,
-- so output the debounced value.
if counter_snapshot = counter then
output <= previous_input;
end if;
-- If the input has changed, save a snapshot of the counter.
if not(input = previous_input) then
counter_snapshot := counter;
end if;
previous_input := input;
end if;
end process;
end;
--
-- Bus Debouncer (many bits)
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Debouncer is
generic
(
timeout: integer := 100; -- Default timeout value.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
bus_in: in std_logic_vector(bus_size - 1 downto 0);
bus_out: out std_logic_vector(bus_size - 1 downto 0)
);
end;
architecture V1 of Debouncer is
component DebouncerBit is
port
(
clock: in std_logic;
counter: in integer;
input: in std_logic;
output: out std_logic
);
end component;
-- One counter to be shared by all debouncers.
-- Each debouncer takes a snapshot of the count value when its input changes value.
signal counter: integer := 0;
begin
-- Create the debounce period.
process(clock)
begin
if rising_edge(clock) then
if counter = timeout then
counter <= 0;
else
counter <= counter + 1;
end if;
end if;
end process;
DebouncerGen: for i in 0 to bus_size - 1 generate
begin
Debounce: DebouncerBit
port map
(
clock => clock,
counter => counter,
input => bus_in(i),
output => bus_out(i)
);
end generate;
end;
SynchroniseDebounce.vhd
--
-- SynchroniseDebounce
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SynchroniseDebounce is
generic
(
reg_size: integer := 3; -- Default number of bits in sync register.
timeout: integer := 100; -- Default timeout value.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
db_sync_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0')
);
end;
architecture V1 of SynchroniseDebounce is
component Synchroniser is
generic
(
reg_size: integer := 3; -- Default number of bits in sync register.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
sync_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0');
rise_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0');
fall_bus_out: out std_logic_vector(bus_size - 1 downto 0) := (others => '0')
);
end component;
component Debouncer is
generic
(
timeout: integer := 100; -- Default timeout value.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
bus_in: in std_logic_vector(bus_size - 1 downto 0);
bus_out: out std_logic_vector(bus_size - 1 downto 0)
);
end component;
signal sync_bus_out: std_logic_vector(bus_size - 1 downto 0);
signal rise_bus_out: std_logic_vector(bus_size - 1 downto 0);
signal fall_bus_out: std_logic_vector(bus_size - 1 downto 0);
begin
Synchroniser_Inst: Synchroniser
generic map
(
reg_size => REG_SIZE, -- Override default value.
bus_size => BUS_SIZE -- Override default value.
)
port map
(
clock => clock,
async_bus_in => async_bus_in,
sync_bus_out => sync_bus_out, -- Goes to Debouncer_Inst
rise_bus_out => rise_bus_out,
fall_bus_out => fall_bus_out
);
Debouncer_Inst: Debouncer
generic map
(
timeout => TIMEOUT, -- Override default value.
bus_size => BUS_SIZE -- Override default value.
)
port map
(
clock => clock,
bus_in => sync_bus_out, -- From Synchroniser_Inst
bus_out => db_sync_bus_out
);
end;
Testbench.vhd
--
-- Test Bench
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity testbench is
end;
architecture V1 of testbench is
component SynchroniseDebounce is
generic
(
reg_size: integer := 3; -- Default number of bits in sync register.
timeout: integer := 100; -- Default timeout value.
bus_size: integer := 8 -- Default bus width.
);
port
(
clock: in std_logic;
async_bus_in: in std_logic_vector(bus_size - 1 downto 0);
db_sync_bus_out: out std_logic_vector(bus_size - 1 downto 0)
);
end component;
constant NUM_SWITCHES: integer := 16;
constant NUM_PUSH_BUTTONS: integer := 4;
signal switches_async, switches_db_sync: std_logic_vector(NUM_SWITCHES - 1 downto 0) := (others => '0');
signal push_buttons_async, push_buttons_db_sync: std_logic_vector(NUM_PUSH_BUTTONS - 1 downto 0) := (others => '0');
constant REG_SIZE: integer := 3;
constant BUS_SIZE: integer := NUM_SWITCHES + NUM_PUSH_BUTTONS;
signal async_bus_in, db_sync_bus_out, rise_bus_out, fall_bus_out: std_logic_vector(BUS_SIZE - 1 downto 0) := (others => '0');
constant TIMEOUT: integer := 10; -- Number of clock cycles in debounce period.
signal clock: std_logic;
constant PERIOD: time := 10 ns; -- System clock frequency.
signal stop_clock: boolean := false;
begin
ClockGenerator: process
begin
while not stop_clock loop
clock <= '0';
wait for PERIOD / 2;
clock <= '1';
wait for PERIOD / 2;
end loop;
wait;
end process ClockGenerator;
Stimulus: process
variable seed1, seed2: positive;
variable rrand: real;
variable irand: integer;
begin
switches_async <= (others => '0');
push_buttons_async <= (others => '0');
wait for 23 ns;
-- Some noisy inputs.
seed1 := 1;
seed2 := 1;
for n in 1 to 500 loop
for i in 0 to NUM_PUSH_BUTTONS - 1 loop
uniform(seed1, seed2, rrand);
irand := integer(round(rrand));
if irand = 0 then
push_buttons_async(i) <= '0';
else
push_buttons_async(i) <= '1';
end if;
end loop;
for i in 0 to NUM_SWITCHES - 1 loop
uniform(seed1, seed2, rrand);
irand := integer(round(rrand));
if irand = 0 then
switches_async(i) <= '0';
else
switches_async(i) <= '1';
end if;
end loop;
wait for 1 ns;
end loop;
-- Pulse the push buttons.
for i in 0 to NUM_PUSH_BUTTONS - 1 loop
push_buttons_async(i) <= '1';
wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
push_buttons_async(i) <= '0';
end loop;
-- Pulse the switches.
for i in 0 to NUM_SWITCHES - 1 loop
switches_async(i) <= '1';
wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
switches_async(i) <= '0';
end loop;
wait for (REG_SIZE + TIMEOUT + 1) * PERIOD;
stop_clock <= true;
wait;
end process Stimulus;
DUT: SynchroniseDebounce
generic map
(
reg_size => REG_SIZE, -- Override default value.
timeout => TIMEOUT, -- Override default value.
bus_size => BUS_SIZE -- Override default value.
)
port map
(
clock => clock,
async_bus_in => async_bus_in,
db_sync_bus_out => db_sync_bus_out
);
-- Connect the input switches and input push buttons to the asynchronous bus input.
async_bus_in <= switches_async & push_buttons_async;
-- Connect the debounced and synchronised output bus to the debounced synchronised switches and push buttons.
switches_db_sync <= db_sync_bus_out(NUM_SWITCHES + NUM_PUSH_BUTTONS - 1 downto NUM_PUSH_BUTTONS);
push_buttons_db_sync <= db_sync_bus_out(NUM_PUSH_BUTTONS - 1 downto 0);
end;
Testbench Waveforms
Bit 2 of the debounced synchronous bus (db_sync_bus_out) goes high only when a long enough pulse is applied to the input (async_bus_in).

Continuous sequence in VHDL

This is what i am required to do. - Show the following repeating sequence on the onboard LEDs (Leftmost LED is MSB):
o 0x00 -> 0x03 -> 0x40 -> 0xE8 -> 0x00 -> …
- LED transitions must be visible
- Command the sequence to start/pause upon pressing BTN0
- Upon power up the sequence is paused
This is what i have so far:
entity vhdl_primer is
port ( clk, rst_n, btn0: in std_logic;
LED: out std_logic_vector (7 downto 0)
);
end vhdl_primer;
architecture behavior of vhdl_primer is
type statetype is (S0, S1, S2, S3);
signal currentstate, nextstate: statetype;
begin
statereg: process(clk, rst)
begin
if (rst='0') then
currentstate <= S0; --initial state
elsif rising_edge(clk) then
currentstate <= nextstate;
end if;
end process;
comblogic: process(currentstate, btn0)
begin
LED <= '0';
case currentstate is
when S0 =>
LED <= '0'; -- led off
nextstate <= S1;
when S1 =>
if (btn0='1') then
nextstate <= S2;
else
nextstate <= S1;
end if;
when S2 =>
LED <= '1'; -- led 0x40
nextstate <= S3;
when S3 =>
LED <= '1'; -- led 0xE8
if (btn0='1') then
nextstate <= S0;
else
nextstate <= S3;
end if;
when others =>
end case;
end process;
end behavior;

std_logic vector (15 downto 0) value doesn't get assigned

So, long story short, I'm trying to make a processor of sorts ('of sorts' is put there for a reason, but let's not go into details), and I'm running into one problem which pretty much ruins the whole thing.
Namely, in this piece of code :
programmProcess: process (clk,rst) is
variable counter : natural;
begin
if (rst = '1') then
counter := 0;
elsif (clk'event and clk = '1' and pm_nEn= '1') then
RAM(counter) <= data; --This is where the issue is
counter := counter + 1;
if (counter = 1024) then
counter := 0;
end if;
end if;
data <= "ZZZZZZZZZZZZZZZZ";
end process programmProcess;
... and this is the testbench process :
stim_proc1: process
begin
rst <= '1';
pm_nEn <= '1';
wait for clk_period;
rst <= '0' ;
data <="0000111110111001";
wait for clk_period;
data <="0000111010111001";
wait for clk_period;
data <= "ZZZZZZZZZZZZZZZZ";
pm_nEn <= '0';
wait for 10*clk_period;
wait;
end process;
... where RAM is an array of 1024 vectors of 16 bits, data is a 16 bit inout vector and pm_nEn is a single bit which basically allows the RAM to be filled with values.
The idea is that RAM(counter) gets values from the data vector, which is manually fed values in the testbench, but this doesn't happen. Namely, all of RAM's values just stay "UUUUUUUUUUUUUUUU", despite data having the required values. Even when it's first evaluated and counter is 0, RAM(0) is undefined.
I'm using the ISE suite, and I tried simulating, and then just tracing through all the steps, and the step where RAM(counter) should get assigned a value is shown, the data vector does have the value which is added manually from the testbench, but RAM still doesn't get any values.
So, the question is basically - why does this happen? Why doesn't RAM get its values assigned?
Also, here's the full VHDL and testbench (which was conveniently generated by ISE) in google doc form -
VHDL
Testbench
Assigning "zzzz" to Data within the main process should do no harm (although in the current code fragment, it is redundant).
One thing that may lead to problems in synthesis is:
elsif (clk'event and clk = '1' and pm_nEn= '1') then
... actions
end if;
To match the pattern a synthesis tool expects for a clocked process, it is better to write
elsif clk'event and clk = '1' then
if pm_nEn= '1' then
... actions
end if;
end if;
though I would expect the two versions to be equivalent in simulation.
There isn't another driver on RAM in another process, is there?
EDIT: apparently there IS a separate driver setting RAM in another process.
Now from a software perspective, you might think that is OK because one process drives when en = '0' and the other when en = '1'. However you can't make the driver hardware appear and disappear at the flick of a boolean; there are always two drivers on the RAM signal. And the one you aren't explicitly using is holding the value as "UUUU".
The best thing to do is to eliminate one of them. Make one process or the other responsible for writing to RAM. I'll use this process; you may find the design is cleaner and tidier using the other process; that's OK too.
It's easy : just reorganise this process along these lines:
elsif clk'event and clk = '1' then
if pm_nEn= '1' then
... actions
else -- or elsif external_enable then
RAM(external_address) <= external_data;
end if;
end if;
Incidentally, when you see an expression like RAM(to_integer(unsigned(R(to_integer(unsigned(IR(5 downto 3))))))) <= std_logic_vector(signed(OP1) + signed(OP2));
it's usually a clue that some things have been declared as the wrong types in the first place : for example, OP1 and OP2 should possibly be signed, R should be an array of integers, and so on. If you can't eliminate all the ugliness, you can at least stop it interfering with the main program flow using helper functions (possibly in a package):
function gen_reg_addr(IR : Register) return natural is ...
RAM(gen_reg_addr(IR)) <= ...
I imagine that the problem is with the multitude of places where you write to data. It wouldn't surprise me if you are having multiple statements write to the same variable, and that should cause the simulator to give it a value of Z.
For example, one of your processes looks like this:
glavenProcess: process (clk,rst) is
begin
data <= "ZZZZZZZZZZZZZZZZ";
...
end process;
Sorry for the delay, i found your problem, change RAM to variable instead of Signal, check VHDL manual to see the differences between Signals and variables:
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
entity mp is
port(
clk, rst, pm_nEn : in std_logic;
data : inout std_logic_vector(15 downto 0);
adr : out std_logic_vector(15 downto 0);
rd_nwr : out std_logic
);
end entity mp;
architecture beh of mp is
signal PC, IR, OP1, OP2 : std_logic_vector(15 downto 0);
type csignals is array(7 downto 0) of std_logic_vector(15 downto 0);
signal R: csignals;
type memory_array is array(1024 downto 0) of std_logic_vector(15 downto 0);
shared variable RAM: memory_array;
begin
glavenProcess: process (clk,rst) is
begin
data <= "ZZZZZZZZZZZZZZZZ";
if (rst = '1') then
PC <= "0000000000000000";
R(0) <= "0000000000000000";
R(1) <= "0000000000000000";
R(2) <= "0000000000000000";
R(3) <= "0000000000000000";
R(4) <= "0000000000000000";
R(5) <= "0000000000000000";
R(6) <= "0000000000000000";
R(7) <= "0000000000000001";
elsif (clk'event and clk = '1' and pm_nEn= '0') then
IR <= RAM(to_integer(unsigned(PC)));
if (IR(15) = '0') then
if (IR(14) = '0') then
OP1 <= R(to_integer(unsigned(IR(11 downto 9))));
else
OP1 <= RAM(to_integer(unsigned(R(to_integer(unsigned(IR(11 downto 9)))))));
end if;
if (IR(13) = '0') then
OP2 <= R(to_integer(unsigned(IR(8 downto 6))));
else
if (IR(0) = '0') then
adr <= R(to_integer(unsigned(IR(8 downto 6))));
OP2 <= data;
rd_nwr <= '1' ;
else
OP2 <= RAM(to_integer(unsigned(R(to_integer(unsigned(IR(8 downto 6)))))));
end if;
end if;
if (IR(2) = '1') then OP2 <= not OP2 ; end if;
if (IR(1) = '1') then OP1 <= not OP1 ; end if;
if (IR(0) = '0') then
if (IR(12) = '0') then
R(to_integer(unsigned(IR(5 downto 3)))) <= std_logic_vector(signed(OP1) + signed(OP2));
else
RAM(to_integer(unsigned(R(to_integer(unsigned(IR(5 downto 3))))))) := std_logic_vector(signed(OP1) + signed(OP2));
end if;
else
if (IR(12) = '0') then
adr <= R(to_integer(unsigned(IR(5 downto 3))));
else
adr <= RAM(to_integer(unsigned(R(to_integer(unsigned(IR(5 downto 3)))))));
end if;
data <= std_logic_vector(signed(OP1) + signed(OP2));
rd_nwr <= '0' ;
end if;
PC <= std_logic_vector(unsigned(PC) + 1);
else
if (IR(8 downto 7) = "00") then
if (R(to_integer(unsigned(IR(11 downto 9)))) = R(to_integer(unsigned(IR(6 downto 4))))) then
PC <= R(to_integer(unsigned(IR(14 downto 12))));
end if;
elsif (IR(8 downto 7) = "01") then
if (R(to_integer(signed(IR(11 downto 9)))) > R(to_integer(signed(IR(6 downto 4))))) then
PC <= R(to_integer(unsigned(IR(14 downto 12))));
end if;
elsif (IR(8 downto 7) = "10") then
if (R(to_integer(signed(IR(11 downto 9)))) < R(to_integer(signed(IR(6 downto 4))))) then
PC <= R(to_integer(unsigned(IR(14 downto 12))));
end if;
elsif (IR(8 downto 7) = "11") then
if ( not R(to_integer(signed(IR(11 downto 9)))) = R(to_integer(signed(IR(6 downto 4))))) then
PC <= R(to_integer(unsigned(IR(14 downto 12))));
end if;
end if;
end if;
end if;
end process glavenProcess;
programmProcess: process (clk,rst) is
variable counter : natural;
begin
if (rst = '1') then
counter := 0;
else
if (clk'event and clk = '1' and pm_nEn= '1') then
RAM(counter) := data;
counter := counter + 1;
if (counter = 1024) then counter := 0; end if;
end if;
end if;
end process programmProcess;
end architecture beh;
Testbench:
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
-- Add your library and packages declaration here ...
entity mp_tb is
end mp_tb;
architecture TB_ARCHITECTURE of mp_tb is
-- Component declaration of the tested unit
component mp
port(
clk : in STD_LOGIC;
rst : in STD_LOGIC;
pm_nEn : in STD_LOGIC;
data : inout STD_LOGIC_VECTOR(15 downto 0);
adr : out STD_LOGIC_VECTOR(15 downto 0);
rd_nwr : out STD_LOGIC );
end component;
-- Stimulus signals - signals mapped to the input and inout ports of tested entity
signal clk : STD_LOGIC;
signal rst : STD_LOGIC;
signal pm_nEn : STD_LOGIC;
signal data : STD_LOGIC_VECTOR(15 downto 0);
-- Observed signals - signals mapped to the output ports of tested entity
signal adr : STD_LOGIC_VECTOR(15 downto 0);
signal rd_nwr : STD_LOGIC;
-- Add your code here ...
begin
-- Unit Under Test port map
UUT : mp
port map (
clk => clk,
rst => rst,
pm_nEn => pm_nEn,
data => data,
adr => adr,
rd_nwr => rd_nwr
);
clock:process is
begin
clk<='0';
wait for 10 ns;
clk<='1';
wait for 10 ns;
end process;
process is
begin
rst <= '1';
pm_nEn <= '1';
wait for 25 ns;
rst <= '0' ;
data <="0000111110111001";
wait for 45 ns;
data <="0000111010111001";
wait for 55 ns;
data <= "ZZZZZZZZZZZZZZZZ";
pm_nEn <= '0';
wait;
end process;
end TB_ARCHITECTURE;
configuration TESTBENCH_FOR_mp of mp_tb is
for TB_ARCHITECTURE
for UUT : mp
use entity work.mp(beh);
end for;
end for;
end TESTBENCH_FOR_mp;

Resources