1
\$\begingroup\$

I am trying to learn how to use Vivado's IP core generator. I came up with a simple project where I want to use a counter that measures the width of an incoming pulse, writes the measurement into a FIFO and then reads the value out of the FIFO.

What I am having trouble with is figuring out how to generate an internal pulse for the write and read enable signals. I need these enable signals to trigger the FIFO for one clock cycle so only one piece of data is written into the FIFO. All my attempts so far have created enable signals that stay high for too long and cause the FIFO to become entirely filled by the same pulse measurement, rather than each FIFO entry being a new measurement.

Here is the code I have so far. Please ignore variables okUH, okHU, okUHU, okAA, okHE and okEH. They are needed for the FPGA to send data to my PC and I haven't instantiated them yet since my design isn't complete. Also, in this design I am using a 200MHz clock on the FPGA to write data into the FIFO and a 48MHz clock (from the USB controller) to read the data.

`timescale 1ns / 1ps

module Pulse_counter(
input in_1  ,                     // input signal

input [4:0] okUH,      // Input from Opal Kelly USB controller (from PC)
output [2:0] okHU,     // Outputs to Opal Kelly USB Controller (to PC)
inout [31:0] okUHU,    // Bidirectionals to USB Controller
inout okAA
);

    wire okClk;            // Clock used synchronize FPGA to the Opal Kelly modules (?)
    wire [112:0] okHE;     // Opal Kelly module address and control bus
    wire [64:0] okEH;      // Outputs from the various OK modules back to the okHost core
    reg reset; 
    reg [15:0] counter;
    reg rd_en; 
    reg wr_en;
    wire empty; 
    wire full; 
    wire [15:0] dout; 
    reg [15:0] count_out;
    wire wr_ack;
    
initial reset = 1'b0; 
initial counter = 16'b0; 
initial wr_en = 1'b0;
initial rd_en = 1'b0;

fifo_generator_0 myfifo (
  .wr_clk(okClk),      // input wire wr_clk connnected to the Opal Kelly FPGA clock
  .rd_clk(ti_clk),     // input wire rd_clk connected to the USB's clock
  .din(count_out),     // input wire [15 : 0] din connected to the pulse measurement 
  .wr_en(wr_en),    // input wire wr_en
  .rd_en(rd_en),    // input wire rd_en
  .dout(dout),      // output wire [15 : 0] dout
  .full(full),      // output wire full
  .empty(empty),    // output wire empty
  .wr_ack(wr_ack),  // output wire wr_ack confirms that a write request succeeded during the last write clock
  .valid()    // output wire valid indicates valid data is available on output bus (dout)
);


always @(posedge okClk) begin
    if (reset || counter==16'hFFFF) begin
        counter <= 16'b0 ;        
    end
    else if (in_1) begin
        counter <= counter + 1;   // As long as input is high keep counting
    end
    else if (in_1 == 16'b0) begin 
        if (counter !== 16'b0) begin    
            count_out <= 5*counter;     // Convert the counter output to the pulse measurement by multiplying by its period (200MHz clock has a period of 5ns) 
        end
        counter <= 16'b0;           // reset counter once the input signal returns back to zero
    end
// If the FIFO ever becomes full or empty stop writing or reading 
    if (empty) begin 
        rd_en <= 1'b0; 
    end 
    else if (full) begin 
        wr_en <=1'b0;
    end 
end

endmodule

Here is my simulation output so far where two input pulses are being measured by the 16 bit counter and then multiplied by the clock period to given the pulse width.

enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ wr_en never becomes 1 in your code so it never writes anything to the FIFO \$\endgroup\$
    – user253751
    Nov 5, 2021 at 10:28

1 Answer 1

1
\$\begingroup\$

Since you are using the falling edge of the in_1 signal to determine when to capture the counter value, you can create an edge detector for this signal.

This entails delaying the signal by one clock cycle, then comparing the original versus the delayed version to determine when the signal went low. This creates a new signal which is high for one clock cycle. You can use this for your FIFO write-enable.

reg in_1_del;
wire in_1_ne = !in_1 & in_1_del; // Negative edge of in_1

always @(posedge okClk) begin
    if (reset) begin
        in_1_del <= 1'b0;        
    end else begin
        in_1_del <= in_1;        
    end
end

always @(posedge okClk) begin
    if (reset || full) begin
        wr_en <= 1'b0;        
    end else begin
        wr_en <= in_1_ne;        
    end
end

This is obviously untested since you did not provide a runnable example. Judging from your waveforms, I believe the timing of the wr_en signal will line up with when the count_out has a new value.

Here is a schematic of the edge detector:

schematic

simulate this circuit – Schematic created using CircuitLab

\$\endgroup\$
4
  • \$\begingroup\$ I'm not sure I understand how you are creating in_1_del. By assigning in_1_del to in_1 in another always block won't in_1 already be 0 meaning in_1_delay would also be zero and no delayed falling edge would occur? \$\endgroup\$ Nov 5, 2021 at 18:05
  • \$\begingroup\$ @PrematureCorn: No, as the answer states, in_1_del is in_1 delayed by one cycle. Run a simulation to prove this to yourself. \$\endgroup\$
    – toolic
    Nov 5, 2021 at 18:17
  • \$\begingroup\$ Yes I see it in the simulation but I'm not sure I understand how this is working. \$\endgroup\$ Nov 5, 2021 at 18:41
  • \$\begingroup\$ @PrematureCorn: Added a schematic \$\endgroup\$
    – toolic
    Nov 5, 2021 at 18:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.