I am programming using VHDL, and I am having an issue processing an incoming signal when trying to look at it only for a specific time frame.
Lets say I have an incoming signal, GPIO.
In a process (triggered by 50 MHz clock) an internal signal, A, gets assigned the value of GPIO during a .1 ms window, while it is assigned '0' for all other times during a 2 ms period.
Signal A is then put through an LCELL several times to delay the signal.
Some selected components of this delayed signal (vector A_internal(23 downto 0) ) are put into a mux4to1 with A (A gets NOT-ANDED with a delayed signal to produce a shorter signal, A_s).
A_s is then counted and used to calculate some other data.
My issue is this: when A is constantly reading GPIO (it does not go through the clock 50 process), the code runs correctly. But when I try to use this method to look at GPIO only at certain times, the code will never read GPIO (or at least I am getting counts of 0, always). Is there an error in the way I am approaching this "selection window" method or is there something I and doing wrong in the code itself that is causing this to not be read?
Here is the relevant code (please to tell me if any other information is needed to help answer my question):
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY Project IS
PORT (
Clock_50 : IN STD_LOGIC; -- The 50 MHz clock that is provided on the DE2 Board
SW : IN STD_LOGIC_VECTOR(17 DOWNTO 0); -- The switches 0 through 17 on the DE2 Board
GPIO_0 : IN STD_LOGIC_VECTOR(16 DOWNTO 10); -- The 40 pin expansion header GPIO_0 pins, which can be used as input or output signals
);
END Project;
ARCHITECTURE Behavior OF Project IS
-- This component chooses one of the three delayed pulses, inverts the chosen pulse,
-- then ANDs the inverted, delayed pulse with the original (effectively shortening the original)
COMPONENT mux4to1
PORT (
delayedpulse_0 : IN STD_LOGIC;
delayedpulse_1 : IN STD_LOGIC;
delayedpulse_2 : IN STD_LOGIC;
pulse : IN STD_LOGIC;
SW : IN STD_LOGIC_VECTOR(1 DOWNTO 0);
pulseout : OUT STD_LOGIC
);
END COMPONENT;
COMPONENT LCELL
PORT (
a_in : IN STD_LOGIC;
a_out : OUT STD_LOGIC
);
END COMPONENT;
-- These SIGNALs represent the four input pulse from the detectors
SIGNAL A, B, C, D, AAA, BBB, CCC, DDD: STD_LOGIC;
-- These SIGNALs represent the three shortened versions of the pulse,
-- one of which (along with the original signal) will be chosen by the 4-to-1 mux
SIGNAL A_internal, B_internal, C_internal, D_internal: STD_LOGIC_VECTOR(27 DOWNTO 0);
-- These SIGNALs represent the shortened pulses output by the mux4to1 COMPONENT
SIGNAL A_s, B_s, C_s, D_s: STD_LOGIC;
--The SYN_KEEP attribute preserves the signals through the compiler,
--so that they are not automatically optimized away as redundant logic
ATTRIBUTE SYN_KEEP : BOOLEAN;
ATTRIBUTE SYN_KEEP of A_internal: SIGNAL is TRUE;
ATTRIBUTE SYN_KEEP of B_internal: SIGNAL is TRUE;
ATTRIBUTE SYN_KEEP of C_internal: SIGNAL is TRUE;
ATTRIBUTE SYN_KEEP of D_internal: SIGNAL is TRUE;
-- NOTE: These shared variables are changed and modified in a different process,
-- which was left out of this code. This is why they are shared variables
-- and not regular variables used in the one process.
shared variable PhaseShift : integer := 0; -- multiples of 20 ns
shared variable SelectionWidth : integer := 10000;
Begin
AAA <= GPIO_0(10);
BBB <= GPIO_0(12);
CCC <= GPIO_0(14);
DDD <= GPIO_0(16);
-- This creates, using iteration, a chain of LCELL buffers for each A, B, C, D signal,
-- which act to delay the signals.
LCA_1: LCELL PORT MAP(a_in=> A, a_out=>A_internal(0));
Gen_delay_A : FOR i in 0 to 23 GENERATE
LC : LCELL PORT MAP(a_in => A_internal(i),a_out => A_internal(i+1));
END GENERATE;
LCB_1: LCELL PORT MAP(a_in=> B, a_out=>B_internal(0));
Gen_delay_B : FOR i in 0 to 23 GENERATE
LC : LCELL PORT MAP(a_in => B_internal(i),a_out => B_internal(i+1));
END GENERATE;
LCC_1: LCELL PORT MAP(a_in=> C, a_out => C_internal(0));
Gen_delay_C : FOR i in 0 to 23 GENERATE
LC : LCELL PORT MAP(a_in => C_internal(i),a_out => C_internal(i+1));
END GENERATE;
LCD_1: LCELL PORT MAP(a_in=> D, a_out => D_internal(0));
Gen_delay_D : FOR i in 0 to 23 GENERATE
LC : LCELL PORT MAP(a_in => D_internal(i),a_out => D_internal(i+1));
END GENERATE;
process(Clock_50)
variable Period : integer := 100000;
variable count : integer := 0;
begin
if (rising_edge(Clock_50)) then
-- Increase the count by one every time there is a rising edge on the 50MHz clock
count := count+1;
if (count=0) then
-- Begin by ignoring the GPIO_0 pins
A <= '0';
B <= '0';
C <= '0';
D <= '0';
elsif (count=1+PhaseShift) then
-- Each signal begins to read GPIO_0 once the count reaches a certain time,
-- set by PhaseShift.
A <= GPIO_0(10);
B <= GPIO_0(12);
C <= GPIO_0(14);
D <= GPIO_0(16);
elsif (count=1+PhaseShift+SelectionWidth) then
-- Once the signals have read GPIO_0 for a set amount of time SelectionWidth,
-- the signals are then set back to 0.
A <= '0';
B <= '0';
C <= '0';
D <= '0';
elsif (count=Period) then
-- Once the cycle has finished its period,
-- the count is reset and the process begins again.
count := 0;
end if;
end if;
end process;
MA: mux4to1 PORT MAP(A_internal(8), A_internal(16), A_internal(24), AAA, SW(17 DOWNTO 16), A_s);
MB: mux4to1 PORT MAP(B_internal(8), B_internal(16), B_internal(24), BBB, SW(17 DOWNTO 16), B_s);
MC: mux4to1 PORT MAP(C_internal(8), C_internal(16), C_internal(24), CCC, SW(17 DOWNTO 16), C_s);
MD: mux4to1 PORT MAP(D_internal(8), D_internal(16), D_internal(24), DDD, SW(17 DOWNTO 16), D_s);
END Behavior;
Here is my new code with the suggestions from below:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY Project IS
PORT (
Clock_50 : IN STD_LOGIC; -- The 50 MHz clock that is provided on the DE2 Board
SW : IN STD_LOGIC_VECTOR(17 DOWNTO 0); -- The switches 0 through 17 on the DE2 Board
GPIO_0 : IN STD_LOGIC_VECTOR(16 DOWNTO 10); -- The 40 pin expansion header GPIO_0 pins, which can be used as input or output signals
);
END Project;
ARCHITECTURE Behavior OF Project IS
-- This component chooses one of the three delayed pulses, inverts the chosen pulse,
-- then ANDs the inverted, delayed pulse with the original (effectively shortening the original)
COMPONENT mux4to1
PORT (
delayedpulse_0 : IN STD_LOGIC;
delayedpulse_1 : IN STD_LOGIC;
delayedpulse_2 : IN STD_LOGIC;
pulse : IN STD_LOGIC;
SW : IN STD_LOGIC_VECTOR(1 DOWNTO 0);
pulseout : OUT STD_LOGIC
);
END COMPONENT;
COMPONENT LCELL
PORT (
a_in : IN STD_LOGIC;
a_out : OUT STD_LOGIC
);
END COMPONENT;
CONSTANT Period : positive := 100000; -- number of counts, by multiples of 20 ns (every clock rising edge is 20ns)
CONSTANT SelectionWidth : positive := Period/10; -- number of counts, by multiples of 20 ns
SIGNAL PhaseShift : natural range 0 to Period-SelectionWidth := 0;
SIGNAL count : natural range 0 to Period := 0; -- one count for every rising edge of 50 MHz clock
SIGNAL A, B, C, D, AAA, BBB, CCC, DDD : STD_LOGIC; -- These SIGNALs represent the four input pulse from the photon detectors
SIGNAL A_internal, B_internal, C_internal, D_internal: STD_LOGIC_VECTOR(27 DOWNTO 0); -- These SIGNALs represent the three shortened versions of the pulse, one of which (along with the original signal) will be chosen by the 4-to-1 mux
SIGNAL A_s, B_s, C_s, D_s : STD_LOGIC; -- These SIGNALs represent the shortened pulses output by the mux4to1 COMPONENT
ATTRIBUTE SYN_KEEP : BOOLEAN; --The SYN_KEEP attribute preserves the signals through the compiler, so that they are not automatically optimized away as redundant logic
ATTRIBUTE SYN_KEEP of A_internal: SIGNAL is TRUE;
ATTRIBUTE SYN_KEEP of B_internal: SIGNAL is TRUE;
ATTRIBUTE SYN_KEEP of C_internal: SIGNAL is TRUE;
ATTRIBUTE SYN_KEEP of D_internal: SIGNAL is TRUE;
Begin
AAA <= GPIO_0(10);
BBB <= GPIO_0(12);
CCC <= GPIO_0(14);
DDD <= GPIO_0(16);
clk_count: process(Clock_50)
begin
if (rising_edge(Clock_50)) then
if (count<=(Period-1)) then
count <= count + 1;
else
count <= 0;
end if;
if (count=(0))then -- Begin by setting the output pulse to 0
A <= '0';
B <= '0';
C <= '0';
D <= '0';
elsif ((count>(1+PhaseShift)) and (count<(1+PhaseShift+SelectionWidth)))then -- Each pin is triggered once the count reaches a certain time delay, set by PhaseShift
A <= GPIO_0(10);
B <= GPIO_0(12);
C <= GPIO_0(14);
D <= GPIO_0(16);
elsif (count>=(1+PhaseShift+SelectionWidth))then -- Once the pulse has reached a set amount of time SelectionWidth, the pulse is then turned back to 0.
A <= '0';
B <= '0';
C <= '0';
D <= '0';
end if;
end if;
end process;
LCA_1: LCELL PORT MAP(a_in=> A, a_out=>A_internal(0)); -- This creates, using iteration, a chain of LCELL buffers for each A, B, C, D signal, which act to delay the signals.
Gen_delay_A : FOR i in 0 to 23 GENERATE
LC : LCELL PORT MAP(a_in => A_internal(i),a_out => A_internal(i+1));
END GENERATE;
LCB_1: LCELL PORT MAP(a_in=> B, a_out=>B_internal(0));
Gen_delay_B : FOR i in 0 to 23 GENERATE
LC : LCELL PORT MAP(a_in => B_internal(i),a_out => B_internal(i+1));
END GENERATE;
LCC_1: LCELL PORT MAP(a_in=> C, a_out => C_internal(0));
Gen_delay_C : FOR i in 0 to 23 GENERATE
LC : LCELL PORT MAP(a_in => C_internal(i),a_out => C_internal(i+1));
END GENERATE;
LCD_1: LCELL PORT MAP(a_in=> D, a_out => D_internal(0));
Gen_delay_D : FOR i in 0 to 23 GENERATE
LC : LCELL PORT MAP(a_in => D_internal(i),a_out => D_internal(i+1));
END GENERATE;
MA: mux4to1 PORT MAP(A_internal(8), A_internal(16), A_internal(24), AAA, SW(17 DOWNTO 16), A_s);
MB: mux4to1 PORT MAP(B_internal(8), B_internal(16), B_internal(24), BBB, SW(17 DOWNTO 16), B_s);
MC: mux4to1 PORT MAP(C_internal(8), C_internal(16), C_internal(24), CCC, SW(17 DOWNTO 16), C_s);
MD: mux4to1 PORT MAP(D_internal(8), D_internal(16), D_internal(24), DDD, SW(17 DOWNTO 16), D_s);
END Behavior;
1 Answer 1
The problem lies here:
process(Clock_50)
variable Period : integer := 100000;
variable count : integer := 0;
This means that every time the Clock_50
triggers this process, variable count
is set to 0. Just like it states
That is why I mentioned in the comments about the variables. Only use them if you know what you are doing. You should use signals instead.
constant Period : positive:= 100000;
signal count : natural range 0 to Period-1 := 0;
begin
[...]
clk_proc: process(Clock_50) -- I added a label. easier for debugging.
begin
if (rising_edge(Clock_50)) then
if (count<(Period-1)) then
count <= count + 1;
else
count <= 0;
end if;
-
\$\begingroup\$ Thank you for this help, I did move those two variables to the process recently thinking it would clear up clutter, I didn't think about that! Although I think I was still having the issue before i made the change as well.. I will need to test again on Wednesday and see if that really was the only issue. I have been reading a lot about using signals/variables, and I am going to switch everything to signals and constants in my code like you have suggested. \$\endgroup\$Cody495– Cody4952017年03月28日 13:11:36 +00:00Commented Mar 28, 2017 at 13:11
-
\$\begingroup\$ I do have one more question: what is the difference between using a signal type integer vs natural vs positive? Are there any advantages/disadvantages to using a specific one? \$\endgroup\$Cody495– Cody4952017年03月28日 13:11:49 +00:00Commented Mar 28, 2017 at 13:11
-
\$\begingroup\$ the simulator will warn you when a
natural
becomes negative, or when apositive
becomes less then 1. They are subtypes ofinteger
, just more strict. \$\endgroup\$JHBonarius– JHBonarius2017年03月28日 13:32:38 +00:00Commented Mar 28, 2017 at 13:32 -
\$\begingroup\$ Okay, then natural is the better choice for this situation. In your solution and my original code, we use a process triggered by Clock_50 to increment our count signal. I have some other code (used for rs232 communications; baud counters, etc.) That use an lpm megafunction counter to increment an std_logic_vector instead, then use another process to trigger a clock and rest the vector. Is one of them a preferred or "more standard" method, or does it just depend on the situation and which is more convenient? \$\endgroup\$Cody495– Cody4952017年03月28日 14:57:34 +00:00Commented Mar 28, 2017 at 14:57
-
\$\begingroup\$ It depends on what you want. imho you should aim for readable and maintainable code. I don't consider a number of component instantiations to be readable. The market is even slowly going to C/C++ to HDL compilers (HLS), because more and more developers think VHDL/verilog rtl is not sufficiently high level. \$\endgroup\$JHBonarius– JHBonarius2017年03月28日 16:03:02 +00:00Commented Mar 28, 2017 at 16:03
variable
s and evenshared variable
s in our code. Only use these when you know what you are doing. DO you know what your doing? ;) \$\endgroup\$