Reputation: 4768
This code should be (and is) very simple, and I don't know what I am doing wrong. Here is description of what it should do:
It should display a number on one 7-segment display. That number should be increased by one every time someone presses the push button. There is also reset button which sets the number to 0. That's it. Here is VHDL code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PWM is
Port ( cp_in : in STD_LOGIC;
inc : in STD_LOGIC;
rst: in std_logic;
AN : out STD_LOGIC_VECTOR (3 downto 0);
segments : out STD_LOGIC_VECTOR (6 downto 0));
end PWM;
architecture Behavioral of PWM is
signal cp: std_logic;
signal CurrentPWMState: integer range 0 to 10;
signal inco: std_logic;
signal temp: std_logic_vector (3 downto 0);
begin
--cp = 100 Hz
counter: entity djelitelj generic map (CountTo => 250000) port map (cp_in, cp);
debounce: entity debounce port map (inc, cp, inco);
temp <= conv_std_logic_vector(CurrentPWMState, 4);
ss: entity decoder7seg port map (temp, segments);
process (inco, rst)
begin
if inco = '1' then
CurrentPWMState <= CurrentPWMState + 1;
elsif rst='1' then
CurrentPWMState <= 0;
end if;
end process;
AN <= "1110";
end Behavioral;
Entity djelitelj (the counter used to divide 50MHz clock):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity PWM is
Port ( cp_in : in STD_LOGIC;
inc : in STD_LOGIC;
rst: in std_logic;
AN : out STD_LOGIC_VECTOR (3 downto 0);
segments : out STD_LOGIC_VECTOR (6 downto 0));
end PWM;
architecture Behavioral of PWM is
signal cp: std_logic;
signal CurrentPWMState: integer range 0 to 10;
signal inco: std_logic;
signal temp: std_logic_vector (3 downto 0);
begin
--cp = 100 Hz
counter: entity djelitelj generic map (CountTo => 250000) port map (cp_in, cp);
debounce: entity debounce port map (inc, cp, inco);
temp <= conv_std_logic_vector(CurrentPWMState, 4);
ss: entity decoder7seg port map (temp, segments);
process (inco, rst)
begin
if inco = '1' then
CurrentPWMState <= CurrentPWMState + 1;
elsif rst='1' then
CurrentPWMState <= 0;
end if;
end process;
AN <= "1110";
end Behavioral;
Debouncing entity:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
ENTITY debounce IS
PORT(pb, clock_100Hz : IN STD_LOGIC;
pb_debounced : OUT STD_LOGIC);
END debounce;
ARCHITECTURE a OF debounce IS
SIGNAL SHIFT_PB : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
-- Debounce Button: Filters out mechanical switch bounce for around 40Ms.
-- Debounce clock should be approximately 10ms
process
begin
wait until (clock_100Hz'EVENT) AND (clock_100Hz = '1');
SHIFT_PB(2 Downto 0) <= SHIFT_PB(3 Downto 1);
SHIFT_PB(3) <= NOT PB;
If SHIFT_PB(3 Downto 0)="0000" THEN
PB_DEBOUNCED <= '1';
ELSE
PB_DEBOUNCED <= '0';
End if;
end process;
end a;
And here is BCD to 7-segment decoder:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity decoder7seg is
port (
bcd: in std_logic_vector (3 downto 0);
segm: out std_logic_vector (6 downto 0));
end decoder7seg;
architecture Behavioral of decoder7seg is
begin
with bcd select
segm<= "0000001" when "0000", -- 0
"1001111" when "0001", -- 1
"0010010" when "0010", -- 2
"0000110" when "0011", -- 3
"1001100" when "0100", -- 4
"0100100" when "0101", -- 5
"0100000" when "0110", -- 6
"0001111" when "0111", -- 7
"0000000" when "1000", -- 8
"0000100" when "1001", -- 9
"1111110" when others; -- just - character
end Behavioral;
Does anyone see where I made my mistake(s) ? I've tried that design on Spartan-3 Started board and it isn't working ... Every time I press the push button, I get crazy (random) values. The reset button is working properly. Thanks !!!!
Upvotes: 0
Views: 1306
Reputation: 322
Agree with the previous answer.
A code like this should do the trick:
process (inco, ps, rst)
begin
if rst='1' then
CurrentPWMState <= '0';
prev_inco <= inco; -- This signal captures the previous value of inco
elsif ps'event and ps='1' then
if inco='1' and prev_inco='0' then -- Capture the flank rising.
CurrentPWMState <= CurrentPWMState + 1;
end if;
prev_inco <= inco;
end if;
end process;
I recognize I haven't tried the code (just coded in here) but I think it's ok.
Upvotes: 1
Reputation: 14137
I guess the problem is here:
process (inco, rst)
begin
if inco = '1' then
CurrentPWMState <= CurrentPWMState + 1;
elsif rst='1' then
CurrentPWMState <= 0;
end if;
end process;
When rst='1'
you will reset CurrentPWMState
. But when inco='1'
the you endlessly add 1
to CurrentPWMState
. That's something like an asynchronous feedback loop through a latch. You should do something edge sensitive here. Probably you should capture inco
using your clock signal, detect a 0->1 change and then add 1
.
Upvotes: 2