xx77aBs
xx77aBs

Reputation: 4768

Can anyone help me with this VHDL code (currently malfunctioning)?

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

Answers (2)

eSedano
eSedano

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

bmk
bmk

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

Related Questions