Electronic – Eliminate VHDL inferred latch in case statement

fpgahdllatchquartusvhdl

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

Best Answer

The reason for the latches is due to the fact that the outputs of your case statement are not assigned for every possible case selection. So you have created a storage element without a clock - which is the definition of a latch.

What is ledOut when pr_state is state_Rx? It's not specified by your case statement, so the synthesizer assumes it needs to hold ledOut to whatever its previous value was - which requires a storage element (memory).

  • For example, the following design will infer a latch:
entity inferred_latch is
  Port ( a  : in std_logic;
         b  : in std_logic;
         c  : out std_logic );
end inferred_latch;

architecture Behavioral of inferred_latch is begin process (a,b) begin case a is when '0' => c <= b; when others => end case; end process; end Behavioral;

inferred latch

However, if we assign a signal level to c for all possible states of a, no memory is necessary:

architecture Behavioral of no_latch is
begin
    process (a,b)
    begin
        case a is
            when '0'    => c <= b;
            when others => c <= '0'
        end case;
    end process;
end Behavioral;

no latch

For question 1: The question is a little off-topic since it is opinion based, but I will say that I remember getting a lot of use from the book Circuit Design with VHDL by Pedroni (ISBN 0262162245).

Hope this helps.


edit in response to comment:
I think the design below is equivalent to your original. I can't say that it correctly behaves as you expect. In fact, there is definitely a problem with the range of the timeCounter signal. In your state_init state, you assign a value to clampToTxTime which is much too large to fit into the declared range of timeCounter, but later in the state_clampToTx state, you assign it anyway.

I'll leave you to iron out these details. But, I believe this code is equivalent to your original - but without the latches:


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;

    signal pre_led : std_logic_vector (7 downto 0);
    signal cur_led : std_logic_vector (7 downto 0);

BEGIN

    ledOut     <= cur_led;
    triggerOut <= '0';

--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;
                pre_led  <= cur_led;
                count := 0;
            END IF;
        END IF;
    END PROCESS;

--state declaration process
    PROCESS (pr_state, cfgDIP, pre_led)
        VARIABLE txTime : INTEGER RANGE 0 to 50;
        VARIABLE st_max_out : STD_LOGIC_VECTOR (15 DOWNTO 0) := "0000000000000000";
    BEGIN

        stOut      <= st_max_out;
        maxOut     <= st_max_out;

        CASE cfgDIP IS
            WHEN "00000001" => 
                txTime := 15;
            WHEN "00000011" =>
                txTime := 20;
            WHEN "00000111" =>
                txTime := 25;   
            WHEN others =>
                txTime := 10;
        end case;

        CASE pr_state IS
            WHEN state_init =>                  -- initialize   
                cur_led <= "01000010";
                st_max_out := "0000000000000000";    -- clamp all outputs
                timeCounter <= 10;              -- nominal num of cycles in the init state
                nx_state <= state_TxVPP;  

            WHEN state_TxVPP =>
                cur_led <= cfgDIP;
                st_max_out := "1010101010101010";
                timeCounter <= txTime;  
                nx_state <= state_clampToRx;    

            WHEN state_clampToRx =>
                cur_led <= pre_led;
                st_max_out := "0000000000000000";
                timeCounter <= 200;             -- time between end of Tx and start of Rx, default 800ns (200 *4)
                nx_state <= state_Rx;

            WHEN state_Rx =>
                cur_led <= pre_led;
                st_max_out := "1111111111111111";
                timeCounter <= 10000;           -- set to nominal 40us rx time 
                nx_state <= state_clampToTx;    

            WHEN state_clampToTx =>
                cur_led <= pre_led;
                st_max_out := "0000000000000000";
                timeCounter <= 2489795;         -- time between end of Rx and start of Tx, default to 100Hz PRF
                nx_state <= state_TxVPP;
        END CASE;
    END PROCESS;    
END logic;
Related Topic