I'm a mostly analog EE who's trying to set up an fpga dev kit (terasic de0-nano) to twiddle the control bits on some pulse control parts I'm doing an evaluation board for. I'm using an external dip switch to change an output pulse width and I want to confirm which pulse width selection I'm in by lighting up the onboard LEDs.
I know very little about FPGAs; I implemented a clocked state machine as it seemed like a good starting place. I'm sure I'm doing lots of bad things in general but I'm having one particular problem - my status LEDs aren't working.
I'm trying to get rid of an inferred latch that "has unsafe behavior". I was getting inferred latches for both txTime and ledOut in some prior code. I followed the advice in
https://stackoverflow.com/questions/15500510/how-can-i-make-this-vhdl-code-synthesizable
and put the different options for the cfgDIP 8 bit dip switch into a case statement. I made sure there was an others case to handle states I didn't explicitly address. This made the txTime latch go away; however, it did not fix the ledOut latch unsafe behavior. And either way the inferred latches are still there so it seems like there's a more fundamental problem.
Questions 1) What's a good way to for someone like me to learn to implement practical vhdl FPGA code very quickly? My old undergrad digital logic books are hard to glean practical coding advice from.
2) How do I fix the ledOut latch unsafe behavior?
3) How do I eliminate the inferred latches altogether? There are inferred latches for triggerOut, rxTime, ledOut, clampToRxTime and clampToTxTime. I don't understand why there isn't a txTime inferred latch since it's also used in two states.
My VHDL Code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.all;
ENTITY pulserLogic IS
PORT( clk, reset_n : IN STD_LOGIC;
cfgDIP, stIn, maxIn : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
stOut, maxOut : OUT STD_LOGIC_VECTOR (15 DOWNTO 0);
ledOut : OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
triggerOut : OUT STD_LOGIC);
END pulserLogic;
ARCHITECTURE logic OF pulserLogic IS
SIGNAL timeCounter : INTEGER RANGE 0 TO 300_000; --timing counter
TYPE state IS (state_init,state_TxVPP,state_clampToRx,state_Rx,state_clampToTx);
SIGNAL pr_state, nx_state: state;
BEGIN
--reset and clocked state machine controller process
PROCESS (clk,reset_n)
VARIABLE count : INTEGER RANGE 0 to 300_000;
BEGIN
IF(reset_n = '0') THEN --asynchronous reset
pr_state <= state_init;
count := 0;
ELSIF(RISING_EDGE(clk)) THEN --stay in current state for set number of clock cycles then move to next state
count := count + 1;
IF (count = timeCounter) THEN
pr_state <= nx_state;
count := 0;
END IF;
END IF;
END PROCESS;
--state declaration process
PROCESS (pr_state,timeCounter,cfgDIP,stIn,maxIn)
VARIABLE txTime : INTEGER RANGE 0 to 50;
VARIABLE rxTime : INTEGER RANGE 0 to 250000000; --at 250MHz clock 1hz= 250000000 and 2khz = 125000,
VARIABLE clampToRxTime : INTEGER RANGE 0 to 250000000; --at 250MHz clock 1hz= 250000000 and 2khz = 125000
VARIABLE clampToTxTime : INTEGER RANGE 0 to 250000000; --at 250MHz clock 1hz= 250000000 and 2khz = 125000
Variable ledOutVar : STD_LOGIC_VECTOR (7 DOWNTO 0);
BEGIN
CASE pr_state IS
WHEN state_init => -- initialize
triggerOut <= '0';
txTime := 5; -- set to nominal 20ns pulse width (4ns clock * 5)
rxTime := 10000; -- set to nominal 40us rx time
ledOut <= "01000010";
clampToRxTime := 200; -- time between end of Tx and start of Rx, default 800ns (200 *4)
clampToTxTime := 2500000-txTime-clampToRxTime-rxTime; -- time between end of Rx and start of Tx, default to 100Hz PRF
stOut <= "0000000000000000"; -- clamp all outputs
maxOut <= "0000000000000000";
timeCounter <= 10; -- nominal num of cycles in the init state
nx_state <= state_TxVPP;
WHEN state_TxVPP =>
stOut <= "1010101010101010";
maxOut <= "1010101010101010";
case cfgDIP is
when "00000001" =>
txTime := 15;
ledOut <= "00000001";
when "00000011" =>
txTime := 20;
ledOut <= "00000011";
when "00000111" =>
txTime := 25;
ledOut <= "00000111";
when others =>
txTime := 10;
ledOut <= "00001111";
end case;
timeCounter <= txTime;
nx_state <= state_clampToRx;
WHEN state_clampToRx =>
stOut <= "0000000000000000";
maxOut <= "0000000000000000";
timeCounter <= clampToRxTime;
nx_state <= state_Rx;
WHEN state_Rx =>
stOut <= "1111111111111111";
maxOut <= "1111111111111111";
timeCounter <= rxTime;
nx_state <= state_clampToTx;
WHEN state_clampToTx =>
stOut <= "0000000000000000";
maxOut <= "0000000000000000";
timeCounter <= clampToTxTime;
nx_state <= state_TxVPP;
END CASE;
END PROCESS;
END logic;
Quartus Output:
Info (12021): Found 1 design units, including 1 entities, in source file pulserevalboardcontroller.bdf
Info (12023): Found entity 1: pulserEvalBoardController
Info (12021): Found 2 design units, including 1 entities, in source file pulserlogic.vhd
Info (12022): Found design unit 1: pulserLogic-logic
Info (12023): Found entity 1: pulserLogic
Info (12021): Found 2 design units, including 1 entities, in source file pulserpll.vhd
Info (12022): Found design unit 1: pulserpll-SYN
Info (12023): Found entity 1: pulserPLL
Info (12021): Found 2 design units, including 1 entities, in source file pulsepll.vhd
Info (12022): Found design unit 1: pulsepll-SYN
Info (12023): Found entity 1: pulsePLL
Info (12127): Elaborating entity "pulserEvalBoardController" for the top level hierarchy
Info (12128): Elaborating entity "pulserLogic" for hierarchy "pulserLogic:inst"
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "triggerOut", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "rxTime", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "ledOut", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "clampToRxTime", which holds its previous value in one or more paths through the process
Warning (10631): VHDL Process Statement warning at pulserLogic.vhd(38): inferring latch(es) for signal or variable "clampToTxTime", which holds its previous value in one or more paths through the process
Info (10041): Inferred latch for "clampToTxTime[0]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[1]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[2]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[3]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[4]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[5]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[6]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[7]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[8]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[9]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[10]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[11]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[12]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[13]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[14]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[15]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[16]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[17]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToTxTime[18]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[0]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[1]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[2]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[3]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[4]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[5]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[6]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[7]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[8]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[9]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[10]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[11]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[12]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[13]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[14]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[15]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[16]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[17]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "clampToRxTime[18]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[0]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[1]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[2]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[3]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[4]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[5]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[6]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "ledOut[7]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[0]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[1]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[2]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[3]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[4]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[5]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[6]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[7]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[8]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[9]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[10]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[11]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[12]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[13]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[14]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[15]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[16]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[17]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "rxTime[18]" at pulserLogic.vhd(38)
Info (10041): Inferred latch for "triggerOut" at pulserLogic.vhd(38)
Info (12128): Elaborating entity "pulsePLL" for hierarchy "pulsePLL:inst1"
Info (12128): Elaborating entity "altpll" for hierarchy "pulsePLL:inst1|altpll:altpll_component"
Info (12130): Elaborated megafunction instantiation "pulsePLL:inst1|altpll:altpll_component"
Info (12133): Instantiated megafunction "pulsePLL:inst1|altpll:altpll_component" with the following parameter:
Info (12134): Parameter "bandwidth_type" = "AUTO"
Info (12134): Parameter "clk0_divide_by" = "1"
Info (12134): Parameter "clk0_duty_cycle" = "50"
Info (12134): Parameter "clk0_multiply_by" = "5"
Info (12134): Parameter "clk0_phase_shift" = "0"
Info (12134): Parameter "compensate_clock" = "CLK0"
Info (12134): Parameter "inclk0_input_frequency" = "20000"
Info (12134): Parameter "intended_device_family" = "Cyclone IV E"
Info (12134): Parameter "lpm_hint" = "CBX_MODULE_PREFIX=pulsePLL"
Info (12134): Parameter "lpm_type" = "altpll"
Info (12134): Parameter "operation_mode" = "NORMAL"
Info (12134): Parameter "pll_type" = "AUTO"
Info (12134): Parameter "port_activeclock" = "PORT_UNUSED"
Info (12134): Parameter "port_areset" = "PORT_UNUSED"
Info (12134): Parameter "port_clkbad0" = "PORT_UNUSED"
Info (12134): Parameter "port_clkbad1" = "PORT_UNUSED"
Info (12134): Parameter "port_clkloss" = "PORT_UNUSED"
Info (12134): Parameter "port_clkswitch" = "PORT_UNUSED"
Info (12134): Parameter "port_configupdate" = "PORT_UNUSED"
Info (12134): Parameter "port_fbin" = "PORT_UNUSED"
Info (12134): Parameter "port_inclk0" = "PORT_USED"
Info (12134): Parameter "port_inclk1" = "PORT_UNUSED"
Info (12134): Parameter "port_locked" = "PORT_UNUSED"
Info (12134): Parameter "port_pfdena" = "PORT_UNUSED"
Info (12134): Parameter "port_phasecounterselect" = "PORT_UNUSED"
Info (12134): Parameter "port_phasedone" = "PORT_UNUSED"
Info (12134): Parameter "port_phasestep" = "PORT_UNUSED"
Info (12134): Parameter "port_phaseupdown" = "PORT_UNUSED"
Info (12134): Parameter "port_pllena" = "PORT_UNUSED"
Info (12134): Parameter "port_scanaclr" = "PORT_UNUSED"
Info (12134): Parameter "port_scanclk" = "PORT_UNUSED"
Info (12134): Parameter "port_scanclkena" = "PORT_UNUSED"
Info (12134): Parameter "port_scandata" = "PORT_UNUSED"
Info (12134): Parameter "port_scandataout" = "PORT_UNUSED"
Info (12134): Parameter "port_scandone" = "PORT_UNUSED"
Info (12134): Parameter "port_scanread" = "PORT_UNUSED"
Info (12134): Parameter "port_scanwrite" = "PORT_UNUSED"
Info (12134): Parameter "port_clk0" = "PORT_USED"
Info (12134): Parameter "port_clk1" = "PORT_UNUSED"
Info (12134): Parameter "port_clk2" = "PORT_UNUSED"
Info (12134): Parameter "port_clk3" = "PORT_UNUSED"
Info (12134): Parameter "port_clk4" = "PORT_UNUSED"
Info (12134): Parameter "port_clk5" = "PORT_UNUSED"
Info (12134): Parameter "port_clkena0" = "PORT_UNUSED"
Info (12134): Parameter "port_clkena1" = "PORT_UNUSED"
Info (12134): Parameter "port_clkena2" = "PORT_UNUSED"
Info (12134): Parameter "port_clkena3" = "PORT_UNUSED"
Info (12134): Parameter "port_clkena4" = "PORT_UNUSED"
Info (12134): Parameter "port_clkena5" = "PORT_UNUSED"
Info (12134): Parameter "port_extclk0" = "PORT_UNUSED"
Info (12134): Parameter "port_extclk1" = "PORT_UNUSED"
Info (12134): Parameter "port_extclk2" = "PORT_UNUSED"
Info (12134): Parameter "port_extclk3" = "PORT_UNUSED"
Info (12134): Parameter "width_clock" = "5"
Info (12021): Found 1 design units, including 1 entities, in source file db/pulsepll_altpll.v
Info (12023): Found entity 1: pulsePLL_altpll
Info (12128): Elaborating entity "pulsePLL_altpll" for hierarchy "pulsePLL:inst1|altpll:altpll_component|pulsePLL_altpll:auto_generated"
Warning (13012): Latch pulserLogic:inst|ledOut[6] has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13012): Latch pulserLogic:inst|ledOut[3] has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13012): Latch pulserLogic:inst|ledOut[2] has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13012): Latch pulserLogic:inst|ledOut[1] has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13012): Latch pulserLogic:inst|ledOut[0] has unsafe behavior
Warning (13013): Ports D and ENA on the latch are fed by the same signal pulserLogic:inst|pr_state.state_TxVPP
Warning (13024): Output pins are stuck at VCC or GND
Warning (13410): Pin "triggerOut" is stuck at GND
Warning (13410): Pin "ledOut[7]" is stuck at GND
Warning (13410): Pin "ledOut[5]" is stuck at GND
Warning (13410): Pin "ledOut[4]" is stuck at GND
Info (286030): Timing-Driven Synthesis is running
USE ieee.std_logic_unsigned.all;
. See stackoverflow.com/a/45707415/4090959 \$\endgroup\$