I'm a novice in VHDL programming and currently try to execute a program where the LED on the FPGA board should switch on after transmitting every 10 Ethernet packets which I generate from a Linux server. The code I've written is in the following which doesn't work properly. I'm trying to figure out the problem but still undone. Any help would be much appreciated.
---------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
---------------------------------------------
entity notification is
port (clk, reset, qdv: in std_logic;
LED: out std_logic
);
end notification;
architecture behavior of notification is
signal qdv_a: std_logic;
signal qdv_b: std_logic;
signal packet_count: std_logic_vector (3 downto 0);
begin
no_1: process(clk, reset)
begin
if (reset = '1') then
qdv_a <= '0';
elsif rising_edge (clk) then
qdv_a <= qdv;
end if;
end process no_1;
qdv_b <= qdv and (not qdv_a);
no_2: process(clk, reset)
begin
if (reset = '1') then
packet_count <= "0000";
elsif rising_edge (clk) then
if qdv_b = '1' then
if packet_count < "1010" then
packet_count <= packet_count + 1;
LED <= '0';
else
LED <= '1';
packet_count <= (others => '0');
end if;
end if;
end if;
end process no_2;
end behavior;
I am making assumptions based on your code:
1) You are trying to increment packet_count every time you see a rising edge on qdv,
2) The pulse width of qdv is longer than a period of the 25MHz clock (clk_25MHz) - 40ns and
3) You want an asynchronous reset. (Trying to decide which is better - a synchronous or asynchronous reset - is like trying to decide which is a better - a Mac or a PC.)
So,
If (1) and (2) are true, you need a synchronous edge detector:
signal qdv_d : std_logic;
signal qdv_r : std_logic;
...
process (clk_25MHz, reset)
begin
if reset = '1' then
qdv_d <= '0';
elsif rising_edge (clk_25MHz) then
qdv_d <= qdv;
end if;
end process;
qdv_r <= qdv and not qdv_d;
Please draw this out as a schematic so that you can see how it works.
Then, assuming (3), you need to sort out your main process. If you're coding sequential logic, you should stick to a template. Here is the template for sequential logic with an asynchronous reset, which all synthesis tools should understand:
process(clock, async_reset) -- nothing else should go in the sensitivity list
begin
-- never put anything here
if async_reset ='1' then -- or '0' for an active low reset
-- set/reset the flip-flops here
-- ie drive the signals to their initial values
elsif rising_edge(clock) then -- or falling_edge(clock)
-- put the synchronous stuff here
-- ie the stuff that happens on the rising or falling edge of the clock
end if;
-- never put anything here
end process;
Only clock and reset go in the sensitivity list, because the outputs of the sequential process (though they depend on all the inputs) only change when clock and/or reset change. On a real D-type flip-flop, reset takes priority over clock, so we test that first and do the resetting should reset be asserted. If there is a change on clock (when reset is not asserted) and that change is a rising edge, then do all the stuff that should happen on the rising edge of a clock (stuff that will get synthesised to combinational logic driving the D inputs of the flip-flops).
So, using that template, here is how I would write your main process:
process(clk_25MHz, reset)
begin
if reset = '1' then
packet_count <= "0000";
elsif rising_edge (clk_25MHz) then
if qdv_r = '1' then
if packet_count < "1010" then
packet_count <= packet_count + 1;
LED <= '0';
else
LED <= '1';
packet_count <= (others => '0');
end if;
end if;
end if;
end process;
Now we have a synchronous process which increments packet_count and drives the LED output. (What is q bringing to the party?)
Please
bear in mind that I haven't simulated any of this
don't just type it in without trying to understand how it works
Related
I have been trying to implement a UART in order to communicate between my Lattice MachXO3D board and my computer. At the moment I am attempting to implement the transmission from the FPGA.
Upon testing on the hardware, I encountered a very strange issue. If run normally, it will function for a few seconds and then it will suddenly stop functioning (The CH340 connected to my computer will report it is receiving messages containing 0x0). However, if I embed a logic analyzer onto the FPGA through the Lattice Diamond software, and I run the analyzer, it will function perfectly for an extended period of time.
Sadly, I don't have a logic analyzer, so the embedded logic analyzer is my only chance at knowing what is actually being transmitted.
These are the files related to my implementation:
baud_gen
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- Generates 16 ticks per bit
ENTITY baud_gen IS
GENERIC(divider: INTEGER := 13 -- 24M/115200*16
);
PORT(
clk, reset: IN STD_LOGIC;
s_tick: OUT STD_LOGIC
);
END baud_gen;
ARCHITECTURE working OF baud_gen IS
BEGIN
PROCESS(clk)
VARIABLE counter: UNSIGNED(3 DOWNTO 0) := to_unsigned(0,4);
BEGIN
IF clk'EVENT AND clk='1' THEN
IF reset='1' THEN
s_tick <= '0';
counter := to_unsigned(0,4);
ELSIF counter=to_unsigned(divider-1,4) then
s_tick <= '1';
counter:= to_unsigned(0,4);
ELSE
s_tick <= '0';
counter := counter + 1;
END IF;
END IF;
END PROCESS;
END working;
rs232_tx
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY rs232_tx IS
PORT(clk: IN std_logic;
tx: OUT std_logic;
rst: IN std_logic;
fifo_empty: IN std_logic;
fifo_RdEn, fifo_RdClock: OUT std_logic;
fifo_data: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
Q: OUT STD_LOGIC_VECTOR(1 DOWNTO 0));
END rs232_tx;
ARCHITECTURE working OF rs232_tx IS
TYPE state IS (idle,start,data);
SIGNAL tx_pulse: STD_LOGIC := '1';
SIGNAL s_tick: STD_LOGIC;
SIGNAL pr_state, nx_state: state := idle;
SIGNAL data_val: std_logic_vector(7 DOWNTO 0):=(others=>'0');
SIGNAL data_count: unsigned(2 DOWNTO 0):=to_unsigned(0,3);
BEGIN
process(s_tick, rst)
VARIABLE count: unsigned(3 DOWNTO 0):= to_unsigned(0,4);
BEGIN
IF rising_edge(s_tick) THEN
count := count + to_unsigned(1,4);
IF count = to_unsigned(15,4) THEN
tx_pulse <= '1';
ELSE
tx_pulse <='0';
END IF;
END IF;
END PROCESS;
process(tx_pulse,rst)
BEGIN
IF rising_edge(tx_pulse) THEN
IF rst='1' THEN
pr_state <= idle;
data_val <= (others=>'0');
data_count <= to_unsigned(0,3);
ELSE
pr_state <= nx_state;
CASE pr_state IS
WHEN idle =>
data_count <= to_unsigned(0,3);
WHEN data =>
data_count <= data_count + to_unsigned(1,3);
WHEN start =>
data_val <= fifo_data;
WHEN OTHERS =>
END case;
END IF;
END IF;
END process;
process(fifo_empty,rst,data_count,pr_state,data_count)
BEGIN
case pr_state is
when idle =>
Q <= ('1','1');
fifo_RdEn <= '0';
tx <= '1';
IF fifo_empty='0' AND rst='0' THEN
nx_state <= start;
ELSE
nx_state <= idle;
END IF;
WHEN start =>
Q <= ('1','0');
fifo_RdEn <= '1';
tx <= '0';
nx_state <= data;
WHEN data =>
Q <= ('0','1');
fifo_RdEn <= '0';
tx <= data_val(to_integer(data_count));
if data_count=to_unsigned(7,3) then
nx_state <= idle;
ELSE
nx_state <= data;
end if;
end case;
END process;
fifo_RdClock <= tx_pulse;
baud_gen: ENTITY work.baud_gen
PORT MAP(clk,reset=>'0',s_tick=>s_tick);
END working;
testbench
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY rs232_tx_test IS
GENERIC(clk_period: TIME := 41666666.7 fs;
baud_period: TIME := 8680.55556 ns);
END rs232_tx_test;
ARCHITECTURE working OF rs232_tx_test IS
SIGNAL clk: STD_LOGIC := '0';
SIGNAL tx, rst, fifo_empty, fifo_RdEn, fifo_RdClock: STD_LOGIC;
SIGNAL fifo_data: STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
clk <= NOT clk AFTER clk_period/2;
rst <= '1', '0' AFTER 100 ns;
PROCESS
BEGIN
fifo_empty <= '1';
WAIT FOR baud_period;
fifo_empty <= '0';
WAIT FOR baud_period*16;
END PROCESS;
fifo_data <= ('1','1','0','0','1','0','1','1') WHEN fifo_RdEn='1' ELSE (others=>'0');
dut: ENTITY work.rs232_tx
PORT MAP(clk,tx,rst,fifo_empty,fifo_RdEn,fifo_RdClock,fifo_data);
END working;
EDIT
I have tested another UART design I found online # 9600 bps and it fails in the same way. It can send a constant character, in this case 'a', to a terminal on my computer, and then it suddenly stops sending anything. However, if I start listening to the soft logic analyzer I generated in Lattice Diamond, it works without a problem and does not fail.
This smells like a classic timing issue.
In the comments, others have explained where there are weaknesses in the code that could indirectly lead to this. I'm going to concentrate on what is occurring.
As you have stated, in simulation your code works as you expect. However, that is only half the story. To create an FPGA bit stream the build tools take your code and several other files, synthesises, and conducts Place & Route. Your timing issue occurs during P&R. This is why your simulation doesn't pick up on any errors, as I'm assuming it's an RTL (pre-place & route) simulation.
During P&R the tools lay the logic in the best way to fit the timing model of the device so all paths meet their timing requirements. The path timing requirements are derived from explicit statements in a Timing Constraints file and inferred from your code (that's why your coding style matters btw).
Once P&R is complete, the tools will put the build artefact through a static timing analyser (STA) tool and report back whether the build fails to meet the timing requirements.
This leads to two questions:
Does the build report a timing error?
Do you have a Timing Constraints file - if you're unsure, the answer is no.
The way to debug your problem is to use the Timing Report generated by Lattice Diamond to see where the failures are.
If there are no reported failures it means your timing model is wrong because of a lack of appropriate timing constraints. As a minimum, you will need to constrain all IO in the design and describe all the clocks in your design.
Here is a good document to help you out:
https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/RZ/Timing_Closure_Document.ashx?document_id=45588
The reason that your design works when you use the embedded Logic Analyser is that extra logic has been placed in the design, which changes the timing model. The P&R tools lay out the design differently, and by luck have placed the design in such a way as meet the real timing requirements on it.
As I often say to my Software Engineer colleagues, software languages create a set of instructions, HDL creates a set of suggestions.
I have the VHDL implementation that works on board, it detects the sequence 01110 and will raise a flag for 2 clock counts. It detects overlapping sequences as well where 011101110 would raise the flag twice.
I've checked my implementation with a logic analyzer on the board and am fairly confident that it works. I am feeding in a repetition sequence of 0111 at 10 kHz, on the board, it has a clock at 100 MHz where I scale it to 10 kHz with a prescaler.
My problem is, when trying to recreate a similar scenario using a simulation, I do not get any outputs as expected
Image from logic analyzer from board
Image from Test Bench
Test Bench Code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity test_FSM_prac4 is
-- Port ( );
end test_FSM_prac4;
architecture Behavioral of test_FSM_prac4 is
component FSM_prac4 is
port (
inputSignal : in STD_LOGIC;
pushButton : in STD_LOGIC;
clk100mhz : in STD_LOGIC;
logic_analyzer : out STD_LOGIC_VECTOR (7 downto 0);
LEDs: out STD_LOGIC
); end component;
signal inputSignal : std_logic := '0';
signal pushButton: std_logic := '0';
signal clk100mhz: std_logic := '0';
signal logic_analyzer: std_logic_vector(7 downto 0);
signal LEDs : std_logic;
begin
uut : FSM_prac4 port map(
inputSignal => inputSignal,
pushButton => pushButton,
clk100mhz => clk100mhz,
logic_analyzer => logic_analyzer,
LEDs => LEDs
);
--generate clock 100mhz
clock_tic: process begin
loop
clk100mhz <= '0';
wait for 5ns;
clk100mhz <= '1';
wait for 5ns;
end loop;
end process;
input_changes: process begin
loop
inputSignal <= '0';
wait for 100us;
inputSignal <= '1';
wait for 100us;
inputSignal <= '1';
wait for 100us;
inputSignal <= '1';
wait for 100us;
end loop;
end process;
end Behavioral;
To show the mapping for logic Analyzer
logic_analyzer(0) <= masterReset;
logic_analyzer(1) <= newClock -- 10Khz Clock;
logic_analyzer(2) <= outputZ;
--FSM States
logic_analyzer(3) <= '1' when y = A ELSE '0';
logic_analyzer(4) <= '1' when y = B ELSE '0';
logic_analyzer(5) <= '1' when y = C ELSE '0';
logic_analyzer(6) <= '1' when y = D ELSE '0';
logic_analyzer(7) <= '1' when y = E ELSE '0';
If anyone could direct to what I am doing wrong on the test bench and how to replicate to get similar results as the first image as it shows that in simulation, it always stays at state A and the new clock is not toggling meaning that clk100mhz is somehow not connected but I can't figure out why.
Any help is greatly appreciated, thanks guys
edit:
I wrote a simple program to test my scalar clock
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity scaler_clk is
Port (
pushButton : in std_logic;
indicator : out std_logic;
clk100mhz : in STD_LOGIC;
clk10khz: out STD_LOGIC
);
end scaler_clk;
architecture Behavioral of scaler_clk is
signal clockScalers : std_logic_vector (12 downto 0):= (others => '0') ;
signal prescaler: std_logic_vector(12 downto 0) := "1001110001000";
signal newClock: std_logic := '0';
signal masterReset : std_logic;
begin
clk10khz <= newClock;
masterReset <= pushButton;
process (clk100mhz,masterReset) begin
if(masterReset <= '1') then <--- error occurs here
clockScalers <= "0000000000000";
newClock <= '0';
indicator <= '1';
elsif (clk100mhz'event and clk100mhz = '1')then
indicator <= '0';
clockScalers <= clockScalers + 1;
if(clockScalers > prescaler) then
newClock <= not newClock;
clockScalers <= (others => '0');
end if;
end if;
end process;
end Behavioral;
test bench code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity test_scaler_clk is
-- Port ( );
end test_scaler_clk;
architecture Behavioral of test_scaler_clk is
component scaler_clk Port (
pushButton : in std_logic;
indicator : out std_logic;
--input clock
clk100mhz : in STD_LOGIC;
clk10khz: out STD_LOGIC
);end component;
signal clk100mhz: std_logic := '0';
signal clk10khz : std_logic;
signal pushButton: std_logic;
signal indicator : std_logic;
begin
uut: scaler_clk port map(
pushButton => pushButton,
indicator => indicator,
clk100mhz => clk100mhz,
clk10khz => clk10khz
);
pushButton <= '0';
clock_tic: process begin
loop
clk100mhz <= '0';
wait for 5ns;
clk100mhz <= '1';
wait for 5ns;
end loop;
end process;
end Behavioral;
Even though I set pushButton to '0', it is still triggering masterReset, anyone knows why, that's why the 10 kHz clock isn't working
There are several things that you could (should) improve in your code. As Brian already explained, in your Behavioral architecture of scaler_clk, you should have:
if(masterReset = '1') then
instead of:
if(masterReset <= '1') then
Now, let's start with the most likely cause of your initial problem: unbound components. Your test benches instantiate the design to validate as components. VHDL components are kind of prototypes of actual entities. Prototypes are enough to compile because the compiler can perform all necessary syntax and type checking. But they are not enough to simulate because the simulator also needs the implementation behind the prototype. Some tools have a default binding strategy for unbound components: if they find an entity with the same name and if it has only one architecture, they use that. Your simulator apparently does not use such strategy (at least not by default, there is maybe an option for that but it is disabled). Note that most simulators I know issue warnings when they find unbound components. You probably missed these warnings.
Anyway, your component instances are unbound (they have no associated entity/architecture) and the simulator considers them as black boxes. Their outputs are not driven, except by the initial values you declared (1).
How to fix this? Two options:
Use a configuration to specify which entity/architecture pair shall be used for each component instance:
for all: scaler_clk use entity work.scaler_clk(Behavioral);
Use entity instantiations instead of components:
uut: entity work.scaler_clk(Behavioral) port map...
Now, let's go through some other aspects of your code that could be improved:
You are using non-standard packages, that are frequently not even compatible: IEEE.STD_LOGIC_ARITH and IEEE.STD_LOGIC_UNSIGNED. As they are not standard they should not even be in the standard IEEE library. You should use IEEE.NUMERIC_STD instead, and only that one. It declares the SIGNED and UNSIGNED types (with the same declaration as STD_LOGIC_VECTOR) and overloads the arithmetic operators on them.
Your test benches generate the 100MHz clock with:
clock_tic: process begin
loop
clk100mhz <= '0';
wait for 5ns;
clk100mhz <= '1';
wait for 5ns;
end loop;
end process;
The infinite loop is useless: a process is already an infinite loop:
clock_tic: process
begin
clk100mhz <= '0';
wait for 5ns;
clk100mhz <= '1';
wait for 5ns;
end process clock_tic;
would do the same. Same remark for your input_changes process.
Your input_changes process uses wait for <duration> statements. This is not a good idea because you do not know when the inputSignal signal toggles, compared to the clock. Is it just before, just after or exactly at the same time as the rising edge of clk100mhz? And if it is exactly at the same time, what will happen? Of course, you can carefully chose the <durations> to avoid such ambiguities but it is error prone. You should use the wait for <duration> only in the clock generating process. Everywhere else, it is better to synchronize with the clock:
input_changes: process
begin
inputSignal <= '0';
for i in 1 to 10000 loop
wait until rising_edge(clk100mhz);
end loop;
inputSignal <= '1';
for i in 1 to 10000 loop
wait until rising_edge(clk100mhz);
end loop;
inputSignal <= '1';
for i in 1 to 10000 loop
wait until rising_edge(clk100mhz);
end loop;
inputSignal <= '1';
for i in 1 to 10000 loop
wait until rising_edge(clk100mhz);
end loop;
end process input_changes;
This guarantees that inputSignal changes just after the rising edge of the clock. And you could rewrite it in a bit more elegant way (and probably a bit easier to maintain):
input_changes: process
constant values: std_logic_vector(0 to 3) := "0111";
begin
for i in values'range loop
inputSignal <= values(i);
for i in 1 to 10000 loop
wait until rising_edge(clk100mhz);
end loop;
end loop;
end process input_changes;
You are using resolved types (STD_LOGIC and STD_LOGIC_VECTOR). These types allow multiple drive, that is, having a hardware wire (VHDL signal) that is driven by several devices (VHDL processes). Usually you do not want this. Usually you even want to avoid this like the plague because it can cause short-circuits. In most cases it is wiser to use non-resolved types (STD_ULOGIC and STD_ULOGIC_VECTOR) because the compiler and/or the simulator will raise errors if you accidentally create a short circuit in your design.
One last thing: if, as its name suggests, you intend to use the clk10khz signal as a real clock, you should reconsider this decision. It is a signal that you generate with your custom logic. Clocks have very specific electrical and timing constraints that cannot really be fulfilled by regular signals. Before using clk10khz as a clock you must deal with clock skew, clock buffering... Not impossible but tricky. If you did use it as a clock your synthesizer probably issued critical warnings that you also missed (have a look maybe at the timing report). Moreover, this is probably useless in your case: an enable signal generated from clk100mhz could probably be used instead, avoiding all these problems. Instead of:
process (clk100mhz,masterReset) begin
if(masterReset = '1') then
clockScalers <= "0000000000000";
newClock <= '0';
indicator <= '1';
elsif (clk100mhz'event and clk100mhz = '1')then
indicator <= '0';
clockScalers <= clockScalers + 1;
if(clockScalers > prescaler) then
newClock <= not newClock;
clockScalers <= (others => '0');
end if;
end if;
end process;
use:
signal tick10khz: std_ulogic;
...
process(clk100mhz, masterReset) begin
if masterReset = '1') then
clockScalers <= "0000000000000";
tick10khz <= '0';
elsif rising_edge(clk100mhz) then
clockScalers <= clockScalers + 1;
tick10khz <= '0'
if(clockScalers > prescaler) then
tick10khz <= '1';
clockScalers <= (others => '0');
end if;
end if;
end process;
And then, instead of:
process(clk10khz)
begin
if rising_edge(clk10khz) then
register <= register_input;
end if;
end process;
use:
process(clk100mhz)
begin
if rising_edge(clk100mhz) then
if tick10khz = '1' then
register <= register_input;
end if;
end if;
end process;
The result will be the same but with only one single 100MHz clock, which avoids clock skew, clock buffering and clock domain crossing problems.
(1) This illustrates why declaring variables and signals with initial values is usually not a good idea: it hides potential problems. Without this your signals would have been stuck at 'U' (uninitialized) and it would maybe have helped understanding where the problem comes from.
I have created a frequency divider, and I want to test it using a FPGA board. To test it I want to make a led flicker with the divided frequency, if a switch is on. The problem is that I do't know how to change the value of the led if clock is not on rising edge.
Here is the exact error I get:
line 51: Signal led cannot be synthesized, bad synchronous description. The description style you are using to describe a synchronous element (register, memory, etc.) is not supported in the current software release.
-->
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity divizor1 is
Port (clk : in STD_LOGIC;
--clk_out : out STD_LOGIC;
btn : in STD_LOGIC;
led : out STD_LOGIC
);
end entity divizor1;
architecture divizor_frecv of divizor1 is
signal cnt : std_logic_vector (24 downto 0);
signal clock :std_logic;
signal bec : std_logic;
begin
process(clk)
begin
if rising_edge(clk) then
cnt<=cnt +1;
end if;
if (cnt = "1111111111111111111111111") then
--clk_out <= '1';
clock <= '1';
else
-- clk_out <= '0';
clock <= '0';
end if;
end process;
process (clock, btn)
begin
if btn = '1' then
if clock'event and clock = '1' then
led <= '1';
else
led <= '0';
end if;
end if;
end process;
end divizor_frecv;
The error message appears to be complaining that you are using the output of the cnt counter as a clock.
Instead you could use it as a toggle enable and clk as the clock:
--process (clock, btn)
process (clk, btn)
begin
-- if btn = '0' then
if btn = '1' then -- reset led
led <= '0'; -- or '1' which ever turns it off
-- if clock'event and clock = '1' then
elsif clock = '1' and rising_edge(clk) then -- clock as enable
-- led <= '1';
led <= not led;
-- else
-- led <= '0';
end if;
-- end if;
end process;
The state of btn made a convenient reset to provide an initial value for led to be able to use not led. This either requires the port signal led be made mode inout or you need a proxy variable or signal which is assigned to led so the not led works (so led can be read). A default value for cnt would also help simulation.
I cheated and made your counter cnt shorter and set the clock to 4 MHz to illustrate:
The simulation was done using ghdl and gtkwave.
process (clock, btn)
begin
if btn = '1' then
if clock'event and clock = '1' then
led <= '1';
else
led <= '0';
end if;
end if;
end process;
At a first glance, I would have guessed the button was a clock enable here. However, the else part is connected to the clock. So you've asked for led to go high at the rising clock edge and low at all other times; given that the clock edge is an instant, this doesn't make much sense (it would always be low). I expect you want to update led based on some other state on the clock edge, for instance:
process (clock)
begin
if clock'event and clock = '1' then
led <= btn;
end if;
end process;
If all you wanted was for the LED to indicate the clock pulses (which may well be too fast to detect) you could just route clock directly to led. Your divider is already producing very short pulses (usually we aim for 50% duty cycle, this has 0.000003%).
I am having problem with my VHDL code, I hope someone could help. See, the 'q' signal is supposed to detect whether the state has changed or not, but it never does. It is as if the state never gets from 'detecting' to 'idle'. The q signal remains on the '0' value, even though the state changes, while the reset is off and clk signal is on the upper edge. I hope you get to see where the problem is.
P.S. state_reg signal is for state at the moment and the next one is for the next state. qlevel_detected is the signal I used for debugging.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity detector is
port
(
clk, reset : in std_logic;
level : in std_logic;
q : out std_logic;
qlevel_detected : out std_logic
);
end detector;
architecture behavioral of detector is
type state is (idle, detecting);
signal state_reg, state_next : state;
signal level_detected_reg, level_detected_next : std_logic;
begin
process(clk, reset)
begin
if (reset = '1') then
state_reg <= idle;
elsif (clk'event and clk = '1') then
state_reg <= state_next;
level_detected_reg <= level_detected_next;
end if;
end process;
process(state_reg)
begin
state_next <= state_reg;
level_detected_next <= level_detected_reg;
case state_reg is
when idle =>
level_detected_next <= level;
state_next <= detecting;
when detecting =>
if (level /= level_detected_reg) then
state_next <= idle;
end if;
end case;
end process;
-- Output logic
q <= '0' when state_reg = idle else
'1' when state_reg = detecting;
qlevel_detected <= level_detected_reg;
end behavioral;
Your next state process is only sensitive to state_reg. As a combinational process it needs all of its inputs listed in the sensitivity list (or all with VHDL-2008).
process(state_reg, level, level_detected_reg)
begin
...
You are also missing an unconditional else on the assignment to q which will create a latch in synthesis.
I have a little problem with following VHDL code:
process (zbroji)
begin
if rising_edge(zbroji) then
oduzima <= '0';
ucitanPrvi <= '1';
broj1 <= ulaz_broj;
end if;
end process;
process (oduzmi)
begin
if rising_edge(oduzmi) then
oduzima <= '1';
ucitanPrvi <= '1';
broj1 <= ulaz_broj;
end if;
end process;
The problem is that signal ucitanPrvi always has value X. If I don't try to set it's value in two processes, then I don't have any problems ... So I know that I mustn't drive one signal from multiple processes, but I don't know how to write this differently ...
Does anyone have an idea how I could resolve this problem ?
Thanks !
EDIT: Thank you all guys for replying :) Now I understand why I can't drive one signal from multiple processes (at least in the way I wanted it to work).
If you want to synthesize your design for a real FPGA or ASIC, you are going to have to think of VHDL in terms of real hardware (wires, flip flops, gates, etc.). Also, if you want to perform a real rising edge detect in hardware, you will need a system clock that drives a flip flop. Given your original code sample, it doesn't seem that zbroji or oduzmi are system clocks, but just std_logic signals. I wrote this code example assuming basic functionality from your example, hopefully, you can take my code and comments and accomplish what you need.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity example is
port (Reset : in std_logic;
SysClk : in std_logic;
zbroji : in std_logic;
oduzmi : in std_logic;
ulaz_broj : in std_logic;
oduzima : out std_logic;
ucitanPrvi : out std_logic;
broj1 : out std_logic
);
end example;
architecture Behavioral of example is
-- Delayed version of input signals (1 clock cycle delay)
signal zbroji_d : std_logic;
signal oduzmi_d : std_logic;
signal zbrojiRE : std_logic;
signal oduzmiRE : std_logic;
begin
-- Generate 1 clock cycle delayed version of
-- signals we want to detect the rising edge
-- Assumes active high reset
-- Note: You should only use the rising_edge macro
-- on an actual global or regional clock signal. FPGA's and
-- ASICs place timing constraints on defined clock signals
-- that make it possible to use rising_edge, otherwise, we have
-- to generate our own rising edge signals by comparing delayed
-- versions of a signal with the current signal.
-- Also, with any respectable synthesizer / simulator using
-- rising_edge is almos exactly the same as (clk'event and clk='1')
-- except rising_edge only returns a '1' when the clock makes a
-- valid '0' to '1' transition. (see link below)
EdgeDetectProc : process (Reset, SysClk)
begin
if Reset = '1' then
zbroji_d <= '0';
oduzmi_d <= '0';
elsif rising_edge(SysClk) then
zbroji_d <= zbroji;
oduzmi_d <= oduzmi;
end if;
end process EdgeDetectProc;
-- Assert risinge edge signals for one clock cycle
zbrojiRE <= '1' when zbroji = '1' and zbroji_d = '0' else '0';
oduzmiRE <= '1' when oduzmi = '1' and oduzmi_d = '0' else '0';
-- Assumes that you want a single cycle pulse on ucitanPrvi on the
-- rising edege of zbroji or oduzmi;
ucitanPrvi <= zbrojiRE or oduzmiRE;
-- Based on your example, I can't tell what you want to do with the
-- broj1 signal, but this logic will drive broj1 with ulaz_broj on
-- either the zbroji or oduzmi rising edge, otherwise '0'.
broj1 <= ulaz_broj when zbrojiRE = '1' else
ulaz_broj when oduzmiRE = '1' else
'0';
-- Finally, it looks like you want to clear oduzima on the rising
-- edge of zbroji and assert oduzima on the rising edge of
-- oduzmi
LatchProc : process (Reset, SysClk)
begin
if Reset = '1' then
oduzima <= '0';
elsif rising_edge(SysClk) then
if zbrojiRE = '1' then
oduzima <= '0';
elsif oduzmiRE = '1' then
oduzima <= '1';
end if;
end if;
end process LatchProc;
end Behavioral;
The previous code assumes you have a system clock. In a simulator like ModelSim (free student edition), you can generate a 100 MHz clock with non-synthesizable testbench code like this...
ClockProc : process
begin
SysClk <= '0';
wait for 5 ns;
SysClk <= '1';
wait for 5 ns;
end process ClockProc;
In an actual FPGA/ASIC implementation, you will probably want to use an external oscillator that you run into your chip, drive the signal into a DCM (Digital clock manager), which will output a very clean clock signal to all of your VHDL logic, so you can have a glitch free design.
And finally, here is a great explanation on the differences between rising_edge and
(clk'event and clk='1')
http://vhdlguru.blogspot.com/2010/04/difference-between-risingedgeclk-and.html
Hope that helps.
If you drive a std_logic signal from more than one process (and remember that a continuous assignment outside of a process also creates an implied process!) then all but one of them must be driving Z onto the signal. To a first approximation, the resolution function (that decides what the final value should be) will produce Xs unless this happens.
I'm not sure how best to change your code - you need to decide when a particular process should not drive the signal and have it drive a Z at that point.
The full definition of how the multiple drivers are resolved is defined in the ieee.std_logic_1164 package and covers all possibilities, such as a 1 and an L driving etc. The IEEE get shirty about copyright, so I'm not going to post even an excerpt here, but you'll be able to find it in the source libraries of your simulator.
Driving signals from multiple processes is a bad idea unless you really know what you're doing. You can re-write this code in a single process like this.
process (zbroji, oduzmi)
begin
if rising_edge(zbroji) then
oduzima <= '0';
ucitanPrvi <= '1';
broj1 <= ulaz_broj;
end if;
if rising_edge(oduzmi) then
oduzima <= '1';
ucitanPrvi <= '1';
broj1 <= ulaz_broj;
end if;
end process;
Note that if you do this, and you get a rising edge on both zbroji & oduzmi then oduzima will get the value 1 as it happens last in the process. Before you'd have been trying to set it to 0 and 1 at the same time. That would simulate to X, and probably wouldn't synthesize. If it did synthesize you'd be connecting power and ground together in a CMOS design.
An alternative method is to have each process drive it's own version of the signal, and then resolve them externally with what ever function you like (or another process). In this case I used or:
process (zbroji)
begin
if rising_edge(zbroji) then
ucitanPrvi_1 <= '1';
end if;
end process;
process (oduzmi)
begin
if rising_edge(oduzmi) then
ucitanPrvi_2 <= '1';
end if;
end process;
ucitanPrvi <= ucitanPrvi_1 or ucitanPrvi_2;
Unless zbroji and oduzmi are seperate clocks this is my recommended implementation
This registers the zbroji and oduzmi and checks if the value in the register is the opposite of the original signal. This should only occur when zbroji/oduzmi go from 0 to 1 and the register has not yet updated the change in signal.
process (clk)
begin
if rising_edge(clk) then
if zbroji = '1' and zbroji_old = '0' then
oduzima <= '0';
ucitanPrvi <= '1';
broj1 <= ulaz_broj;
elif oduzmi = '1' and oduzmi_old = '0' then
oduzima <= '1';
ucitanPrvi <= '1';
broj1 <= ulaz_broj;
end if;
zbroji_old <= zbroji;
oduzmi_old <= oduzmi;
end if;
end process;
Also it appears that ucitanPrvi and broj1 are always the same thing. Either the signals are useless, this was orignally a typo or you are creating "update" pulses in which case you need the statement
ucitanPrvi <= '0'
broj1 <= (others=>'0') -- assumed reset?
following the if(rising_edge(clk) statement
When you're changing same signal value from multiple process, the simulator will be creating multiple signal drivers for this. The output of them will essentially will be unresolved. Think of it as the output of multiple gates connected together, what do you expect?
To overcome this, what you need to implement is, a resolution function, that drivers the output to signal.
http://www.csee.umbc.edu/portal/help/VHDL/misc.html#resf
If you have any doubts, let me know.