VHDL code for metal detector - vhdl

I am working on a metal detector at the moment but can't figure out how to implement it my VHDL code.
ENTITY sensor IS
port ( metaldetector : in std_logic;
metal : out std_logic;
);
END ENTITY sensor;
As long as there isn't any metal close to the sensor 'metaldetector' gets pulses on a 6.1kHz frequency. So as long as the 'metaldetector' keeps getting pulses the out port 'metal' should be '0'.
When there is a pulse missing (or multiple pulses) 'metal' should become '1' until the next pulse.
It shouldn't be that hard to make a code that can do that, but i just can't figure it out. Any help would really be great!

We managed to solve the problem with some help of other students, and a lot of trying.
I'll post our solution down here, hopefully it can be usefull to others. :)
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY sensor IS
port ( metaldetector : in std_logic;
clk : in std_logic;
metal : out std_logic
);
END ENTITY sensor;
ARCHITECTURE sensorbehav OF sensor IS
signal new_count, count: unsigned(20 downto 0);
begin
process (clk, metaldetector)
begin
if (rising_edge (clk)) then
if (metaldetector = '1') then
count <= (others => '0');
else
count <= new_count;
end if;
end if;
end process;
process (count)
begin
new_count <= count + 1;
end process;
process (count)
begin
if (count > 9000) then
metal <= '1';
else
metal <= '0';
end if;
end process;
END ARCHITECTURE;

Related

Why is my debouncing/counter not working in VHDL?

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

I’m new to coding in VHDL and don’t understand why my code will not show an output when simulating on a VWF file

My code will not simulate an output when running the VWF file.
I have tried changing the code several different time and don't really understand what I'm doing wrong.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Counter_JM is
Port (
up_down : in std_logic;
LED : out std_logic;
Q : Buffer integer Range 0 to 7);
end Counter_JM;
architecture archi of Counter_JM is
Begin
-- up/down counter
process (up_down)
begin
if (Q=7) then
Q<=0;
end if;
if (up_down = '1') then
Q <= Q + 1;
else
Q<=0;
end if;
if (Q=0 or Q=1) then
LED <= '0';
else
LED <= '1';
end if;
end process;
end archi;
The LED output should show high for 4 cycles and low for 2 on the VWF file
I don't know why you use up_down. But as Oldfart said, you don't have a clock. I have simplified and modified your code (it works for me (in modelsim):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Counter_JM is
Port (
clk: in std_logic;
up_down : in std_logic;
LED : out std_logic
);
end Counter_JM;
architecture archi of Counter_JM is
Begin
process (clk)
variable Q: integer range 0 to 7;
begin
if rising_edge(clk) then
-- up/down counter
Q := Q + 1;
if Q=1 or Q=2 then
LED <= '0';
else
LED <= '1';
end if;
if Q = 7 then
Q := 0;
end if;
end if;
end process;
end archi;
and also created/generated a simple testbench here :
`-- Testbench automatically generated online
-- at http://vhdl.lapinoo.net
-- Generation date : 7.6.2019 11:22:53 GMT
library ieee;
use ieee.std_logic_1164.all;
entity tb_Counter_JM is
end tb_Counter_JM;
architecture tb of tb_Counter_JM is
component Counter_JM
port (clk : in std_logic;
up_down : in std_logic;
LED : out std_logic);
end component;
signal clk : std_logic;
signal up_down : std_logic;
signal LED : std_logic;
constant TbPeriod : time := 1000 ns; -- EDIT Put right period here
signal TbClock : std_logic := '0';
signal TbSimEnded : std_logic := '0';
begin
dut : Counter_JM
port map (clk => clk,
up_down => up_down,
LED => LED);
-- Clock generation
TbClock <= not TbClock after TbPeriod/2 when TbSimEnded /= '1' else '0';
-- EDIT: Check that clk is really your main clock signal
clk <= TbClock;
stimuli : process
begin
-- EDIT Adapt initialization as needed
up_down <= '0';
-- EDIT Add stimuli here
wait for 100 * TbPeriod;
-- Stop the clock and hence terminate the simulation
TbSimEnded <= '1';
wait;
end process;
end tb;
-- Configuration block below is required by some simulators. Usually no need to edit.
configuration cfg_tb_Counter_JM of tb_Counter_JM is
for tb
end for;
end cfg_tb_Counter_JM;`

VHDL state machine testbench - works when on board but not on simulation

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.

Synthesis: Implementing a delay signal using a counter on power-up of FPGA

I am trying to have a delay of 20 seconds on power-up of the FPGA.
There is a clock input of 100Hz, so if a counter gets to 20,000, that should be 20 seconds worth of delay. After the delay, it should set an output pin high. However, for some reason, this out pin is going high immediately and never goes low at all on powerup. It's almost as if it is skipping the s_count <= 20000 completely.
Here is the code I have:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity delay is
port
(
pi_Clock : in std_logic;
po_Delay_Done : out std_logic
);
end entity;
architecture behavioral of delay is
begin
process(pi_Clock)
variable s_count : integer := 0;
begin
if rising_edge(pi_Clock) then
if s_count <= 20000 then
s_count := s_count + 1;
po_Delay_Done <= '0';
else
po_Delay_Done <= '1';
end if;
end if;
end process;
end architecture;
I have increased the 20000 to the max integer value, just to see if my clock was incorrect but the same result.
There is no other driver of this signal on the top level file.
Anyone see what I'm doing wrong?
For some reason, setting the initial values by the declarations seems to be the problem with this FPGA/toolset (synopsis Synplify and the FPGA is Actel A3PN250) even if it works in modelsim simulation.
The following code does what I want -- Set an output high after the FPGA is turned on for 20 seconds:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity delay is
port
(
pi_Clock : in std_logic;
pi_Reset : in std_logic;
po_Delay_Done : out std_logic
);
end entity;
architecture behavioral of delay is
begin
process(pi_Clock)
variable s_count: integer;
begin
if rising_edge(pi_Clock) then
if pi_Reset = '1' then
s_count := 0;
po_Delay_Done <= '0';
else
if s_count < 2000 then
s_count := s_count + 1;
else
po_Delay_Done <= '1';
end if;
end if;
end if;
end process;
end architecture;
The catch is that the microcontroller is now sending a reset signal (pi_Reset = '1') to the FPGA after it has been started.
Hope this helps anyone in the future, thanks to Quantum Ripple and Brian especially for suggesting the hard reset. If you had an answer I would accept it.
The code you typed has no simulation or synthesis errors and has a correct result in modelsim simulation software. (according to the above first comment "fru1tbat")
With respect to the above comments, I think if you synthesized the FPGA board correctly and the design doesn't worked (with applying a reset port to reset the output and variable parameters), the problem is related to the clock generator. Be sure about the clock generator and find the correct frequency.

VHDL code for turning 50MHz into 38KHz doesn't work

I'm having an issue with this code. Theoretically it should turn my 50MHz sign into 36KHz but as i run the simulation it turns out that the ir_38khz doesn't get any value it is unassigned.
Can you help me where i slip?
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.all;
entity orajelKonverter is
Port ( clk50 : in STD_LOGIC;
rst : in STD_LOGIC;
ir_38khz : out STD_LOGIC);
end orajelKonverter;
architecture Behavioral of orajelKonverter is
signal hz38_ctr : STD_LOGIC_VECTOR(9 downto 0);
signal s38 : std_logic;
begin
clk_generator : process (clk50, rst)
begin
if rst = '1' then
s38 <= '0';
hz38_ctr <= (others => '0');
elsif clk50='1' then
if hz38_ctr = "1010010010" then
hz38_ctr <= (others => '0');
s38 <= not s38;
else
hz38_ctr <= hz38_ctr + "1";
end if;
end if;
end process clk_generator;
ir_38khz <= s38;
end Behavioral;
Here is the picture from the simulation:
You need to initialize your signals to some value OR assert your reset to initialize them in simulation. I personally prefer #1, since signal initial conditions are synthesizable, despite the relatively common misconception that they are not. As a matter of fact, I avoid resets in my designs unless I absolutely need to use them. This is actually recommended by Xilinx. So for example you can do:
signal s38 : std_logic := '0';
This will guarantee that when your simulation starts it knows what to do with the line:
s38 <= not s38;
Previously the simulator was trying to do not U which is U.

Resources