verilogadcanalog-digital-converter

Verilog Peak detection


I am new to Verilog. I am trying to detect peak to peak voltage of an input signal to ADC on FPGA. Before that I wanted to test a simple but similar code which finds the minimum and maximum of set of 4 bit parallel inputs.

Initially I assigned pk_low and pk_high as first input, depending on the upcoming inputs pk_low and pk_high should change or stay the same. But in the simulations I see that pk_low value is always 0. pk_high and pp_voltage(peak to peak voltage) are unknown(X).

What is the problem?

module peak_voltage (clk, parallel_in, pk_high, pk_low, pp_voltage);

input clk;
input wire [3:0] parallel_in;
output reg [3:0] pk_high;
output reg [3:0] pk_low;
output wire [3:0] pp_voltage;

reg state;

parameter st0 = 'd0;
parameter st1 = 'd1;
parameter st2 = 'd2;

initial begin
    state = st0;
    pk_high <= parallel_in;
    pk_low <= parallel_in;
end


always @ (posedge clk) begin

    if (parallel_in > pk_high)begin
        state = st1;
    end else if (parallel_in < pk_low) begin
        state = st2;
    end else begin
        state = st0;
    end

end

always @(*) begin

    case (state)

        st0: begin
            pk_low <= pk_low;
            pk_high <= pk_high;
        end

        st1: begin
            pk_low <= pk_low;
            pk_high <= parallel_in;
        end

        st2: begin
            pk_low <= parallel_in;
            pk_high <= pk_high;     
        end
    endcase
end

assign pp_voltage = pk_high - pk_low;

endmodule

Solution

  • You have coded this like a state machine, where you should instead have a continuous assignment for your case selector. Assign 3 bits to make a one-hot vector maybe.

    You have non-blocking assignments in this logic - you need to use blocking for the combinatorial logic.

    You are missing any explicit storage for the peak high/low values. Maybe you could infer some latches in this style, but it would not be clear quite what you meant.

    Define some flops, clocked by clk, with non-blocking assignments. Capture the updated results in these every cycle.

    Remember that verilog executes all the statements in parallel, you shouldn't be thinking about execution order. Think instead about explicitly capturing your results, and calculating the 'next' values for these results.

    You could view your code as:

    1. Check update of high or low
    2. Calculate new values
    3. Capture new values

    You have done (1) wrong, and missed (3) altogether. It might make sense to code (1) and (2) together, but that is down to how you want to express the functions.

    assign new_level = (in > level) ? in : level;