High precision frequency meter based on FPGA

Keywords: Single-Chip Microcomputer stm32

1, Design requirements
A signal frequency detector is designed with FPGA, which requires:
(1) Measuring pulse signal;
(2) Frequency measurement 1-10MHz and duty cycle 10% - 99%, accurate to 1%;
(3) Display the measured frequency and duty cycle on LCD1602;

2, Design scheme
FPGA design is mainly divided into three modules: 1. Measured signal generation module; 2. Tested signal detection module; 3. Digital display module. The design block diagram is shown in Figure 1.

Fig. 1 design block diagram of signal frequency detector based on FPGA

  1. Measured signal generation module
    The module is mainly used to generate the measured signal. The frequency and duty cycle of the measured signal can be set in the module. The method adopted is to count and divide the system clock to generate the measured signal. This part also uses a PLL to output a 100MHz clock as the sampling clock of the detection module. Module involved in this part: signal_gen module and PLL module.

  2. Tested signal detection module
    The module detects the measured signal by equal precision frequency measurement method:
    (1) Frequency detection of measured signal
    Detect the frequency of the measured signal. When the external enable signal is valid (i.e. within a period of time), count the number of system clock pulses Ns and the number of measured signal pulses nd. If the system clock frequency is Fs and the measured signal frequency is Fd, then Fs/Ns=Fd/Nd, and finally Fd=(Fs/Ns) · nd.
    (2) Duty cycle detection of measured signal:
    Detect the duty cycle of the measured signal, use the system clock, count the positive pulse width Np and negative pulse width Nn of the measured signal when the external enable signal is valid (i.e. within a period of time), then the duty cycle ducy=Np/(Np+Nn)*100%.
    Module involved in this part: signal_detect module.

  3. Digital display module
    The module is mainly divided into two parts: one part is to convert the detected frequency code into Decimal BCD code. Although this method will improve the operation time, it can greatly save FPGA resources (the tradeoff between area and speed); Another part is to drive LCD1602 for display. Here are some steps to convert binary code into Decimal BCD code (taking 8bit binary code as an example): 1. Shift the binary code one bit to the left (or multiply by 2); 2. Find the ten and hundred bits corresponding to the code shifted to the left; 3. Judge whether the code of one digit, ten digit and hundred digit is greater than or equal to 5; 4. Continue to repeat the above three steps until it stops after 8 shifts; 5. If yes, add 3 to this segment. Modules involved in this part: BCD2to10 module and LCD 1602 module.

Finally, the RTL view of FPGA is shown in Figure 2:

//synopsys translate_off
`timescale 1 ns/ 1 ps
//synopsys translate_on
module BCD2to10(
	clk_100M,
	rst_n,
	d_clk_freq,
	qw,
	bw,
	sw,
	w,
	q,
	b,
	s,
	g);
	
	input 			clk_100M;											// Sampling clock 100MHz
	input 			rst_n;												// Reset signal
	input  [31:0] 	d_clk_freq;											// Measured signal frequency
	output [3:0] 	qw;													// Convert and extract tens of millions of bits
	output [3:0] 	bw;													// Convert and extract millions of bits
	output [3:0] 	sw;													// Convert and extract 100000 bits
	output [3:0] 	w;													// Conversion extraction 10000 bits
	output [3:0] 	q;													// Conversion extraction thousands
	output [3:0] 	b;													// Conversion extraction hundredth
	output [3:0] 	s;													// Convert and extract ten bits
	output [3:0] 	g;													// Convert extracted bits
	
	parameter ST0 = 2'b00;
	parameter ST1 = 2'b01;
	parameter ST2 = 2'b10;
	
	//-------------------------------------------------------------------
	// Firstly, several steps of converting binary code into Decimal BCD code are given (taking 8bit binary code as an example)
	// 1. Shift the binary code one bit to the left (or multiply by 2)
	// 2. Find the ten or hundred digits corresponding to the code shifted to the left.?
	// 3. Judge whether the code of one digit, ten digit and hundred digit is greater than or equal to 5
	// 4. Continue to repeat the above three steps until it stops after 8 shifts.
	// 5. If yes, add 3 to this segment.
	//-----------------------------------------------------------------
	
	reg [31:0]  d_clk_shift_reg;
	reg [5:0]	shift_count;
	reg			shift_done;
	reg [31:0] 	bcd_reg;
	reg [3:0] 	qw;
	reg [3:0] 	bw;
	reg [3:0] 	sw;
	reg [3:0] 	w;
	reg [3:0] 	q;
	reg [3:0] 	b;
	reg [3:0] 	s;
	reg [3:0] 	g;
	reg [1:0]	state;
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			d_clk_shift_reg <= #1 32'b0;
		else
		begin
			if(shift_done == 1'b1)
				d_clk_shift_reg <= #1 32'b0;
			else
				d_clk_shift_reg <= #1 d_clk_freq << shift_count;	
		end
	end
		
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			shift_done <= #1 1'b0;
		else
		begin
			if(shift_count == 6'd32)
				shift_done <= #1 1'b1;
			else
				shift_done <= #1 1'b0;
		end
	end

	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
		begin
			bcd_reg <= #1 32'b0;
			shift_count <= #1 6'b0;
			state <= #1 ST0;
		end
		else
		begin
		
			if(shift_done == 1'b0)
			begin
				case(state)
				ST0:begin
						bcd_reg <= #1 {bcd_reg[31:1],d_clk_shift_reg[31]}; // displacement
						state <= #1 ST1;
					end
				ST1:begin	
						if(bcd_reg[31:28] >= 4'd5)   					// qw
							bcd_reg[31:28] <=#1 bcd_reg[31:28] + 4'd3;
						else
							bcd_reg[31:28] <=#1 bcd_reg[31:28];
							
						if(bcd_reg[27:24] >= 4'd5)						// bw
							bcd_reg[27:24] <=#1 bcd_reg[27:24] + 4'd3;
						else
							bcd_reg[27:24] <=#1 bcd_reg[27:24];
						
						if(bcd_reg[23:20] >= 4'd5)						// sw
							bcd_reg[23:20] <=#1 bcd_reg[23:20] + 4'd3;
						else
							bcd_reg[23:20] <=#1 bcd_reg[23:20];
							
						if(bcd_reg[19:16] >= 4'd5)						// w
							bcd_reg[19:16] <=#1 bcd_reg[19:16] + 4'd3;
						else
							bcd_reg[19:16] <=#1 bcd_reg[19:16];	
						
						if(bcd_reg[15:12] >= 4'd5)						// q
							bcd_reg[15:12] <=#1 bcd_reg[15:12] + 4'd3;
						else
							bcd_reg[15:12] <=#1 bcd_reg[15:12];	
						
						if(bcd_reg[11:8] >= 4'd5)						// b
							bcd_reg[11:8] <=#1 bcd_reg[11:8] + 4'd3;
						else
							bcd_reg[11:8] <=#1 bcd_reg[11:8];	
							
						if(bcd_reg[7:4] >= 4'd5)						// s
							bcd_reg[7:4] <=#1 bcd_reg[7:4] + 4'd3;
						else
							bcd_reg[7:4] <=#1 bcd_reg[7:4];	

						if(bcd_reg[3:0] >= 4'd5)						// g
							bcd_reg[3:0] <=#1 bcd_reg[3:0] + 4'd3;
						else
							bcd_reg[3:0] <=#1 bcd_reg[3:0];			
						state <= #1 ST2;							
						end
				ST2:begin
						bcd_reg <= #1 bcd_ reg << 1'b1;  					// displacement
						shift_count <= #1 shift_count + 1'b1;
						state <= #1 ST0;
					end
				
				default:bcd_reg <= #1 bcd_reg;
				endcase
			end
				
			else
			begin
				state <= #1 ST0;
				bcd_reg <= #1 32'b0;
				shift_count <= #1 6'b0;
			end	
		end
	end
	
	reg [31:0] bcd_reg2;
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			bcd_reg2 <= #1 32'b0;
		else
		begin
			if(shift_count == 6'd32)
				bcd_reg2 <= #1 bcd_reg;
			else
				bcd_reg2 <= #1 bcd_reg2;
		end
	end
	
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			qw <= #1 4'b0;
		else
		begin
			if(shift_done == 1'b1)
				qw <= #1 bcd_reg2[31:28];
			else
				qw <= #1 qw; 
		end
	end
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			bw <= #1 4'b0;
		else
		begin
			if(shift_done == 1'b1)
				bw <= #1 bcd_reg2[27:24];
			else
				bw <= #1 bw; 
		end
	end
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			sw <= #1 4'b0;
		else
		begin
			if(shift_done == 1'b1)
				sw <= #1 bcd_reg2[23:20];
			else
				sw <= #1 sw; 
		end
	end
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			w <= #1 4'b0;
		else
		begin
			if(shift_done == 1'b1)
				w <= #1 bcd_reg2[19:16];
			else
				w <= #1 w; 
		end
	end
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			q <= #1 4'b0;
		else
		begin
			if(shift_done == 1'b1)
				q <= #1 bcd_reg2[15:12];
			else
				q <= #1 q; 
		end
	end
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			b <= #1 4'b0;
		else
		begin
			if(shift_done == 1'b1)
				b <= #1 bcd_reg2[11:8];
			else
				b <= #1 b; 
		end
	end
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			s <= #1 4'b0;
		else
		begin
			if(shift_done == 1'b1)
				s <= #1 bcd_reg2[7:4];
			else
				s <= #1 s; 
		end
	end
	
	always@(posedge clk_100M or negedge rst_n)
	begin
		if(rst_n == 1'b0)
			g <= #1 4'b0;
		else
		begin
			if(shift_done == 1'b1)
				g <= #1 bcd_reg2[3:0];
			else
				g <= #1 g; 
		end
	end
	
endmodule

Link: https://pan.baidu.com/s/1AjCw2kyBkggQ5doQ2vNWkg
Extraction code: 1234

Posted by sarun on Wed, 03 Nov 2021 18:13:04 -0700