FPGA study notes _UART serial port protocol and serial port transmitter designTwo

FPGA study notes

1. UART serial port protocol and serial port sender design 2

  • Send multiple bytes

1.1 Serial port protocol transmitter design_multi-byte

(1). Overall block diagram of the serial port protocol transmitter

Insert picture description here

Goal: key-press control serial port to send "HELLO" string

Knowledge points:

  1. wait function call
  2. Method of sending character string: control the input data, send each byte (8bits) once, and send multiple times in a row
  3. Hierarchical reference: call the signal name after instantiation. Variable (in test_bench)

(3). Verilog code

//----top---------------------------------------
module uart_tx_multbyte#(
	parameter byte1 = "H",
	parameter byte2 = "E",
	parameter byte3 = "L",
	parameter byte4 = "L",
	parameter byte5 = "O",
	parameter byte6 = "\n"
)
(
	input clk,
	input rst_n,
	input key0,
	output led,
	output rs232_tx
);
	reg send_en;
	reg [7:0] data_byte;
	wire key_state0;
	wire key_flag0;
	reg [2:0] cnt_byte;
	wire tx_done;
	
	uart_tx_r0 uut_uart(
		.clk(clk),
		.rst_n(rst_n),
		.send_en(send_en),
		.baud_set(3'd4),
		.tx_done(tx_done),
		.data_byte(data_byte),
		.uart_state(led),
		.rs232_tx(rs232_tx)
	);
	
	fsm_key_filter uut_key(
			.clk(clk),
			.rst_n(rst_n),
			.key(key0),
			.key_state(key_state0),
			.key_flag(key_flag0)
);

//----counter--------------------------------------	
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			cnt_byte <= 0;
		else if(tx_done)
			cnt_byte <= cnt_byte + 3'd1;
		else if(key_flag0 & ! key_state0)
			cnt_byte <= 3'd0;
//---------send_en---------------------------------			
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			send_en <= 0;
		else if(key_flag0 & ! key_state0)//press key
			send_en <= 1;
		else if(tx_done &(cnt_byte <= 3'd5))
			send_en <= 1;
		else
			send_en <= 0;
			
//----data----------------------------------------
	always@(*)
		case(cnt_byte )
			3'd0: data_byte <= byte1;
			3'd1: data_byte <= byte2;
			3'd2: data_byte <= byte3;
			3'd3: data_byte <= byte4;
			3'd4: data_byte <= byte5;
			3'd5:	data_byte <= byte6;	
			default: data_byte <= 0;
		endcase
endmodule
//----按键以及抖动滤除----------------------------
module fsm_key_filter#(
	parameter IDLE = 4'b0001,
	parameter FILTER1 = 4'b0010,
	parameter DOWN = 4'b0100,
	parameter FILTER2 = 4'b1000
)
(
	input clk, //50MHz 20us
	input rst_n,
	input key,
	
	output  key_flag,
	output reg  key_state
);
	reg		cnt_en;
	reg		cnt_full;
	reg [19:0] cnt1;
	//reg [19:0] cnt2;
	reg [3:0] state;
	reg		key_syn1;
	reg		key_syn2;
	reg 		key_reg1;
	reg		key_reg2;
	wire 		pos_edge;
	wire 		neg_edge;
	
	always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
			state <= IDLE;
			cnt_en <= 1'b0;
		end else 
		begin
			case(state)
				IDLE:
					begin
						if(neg_edge)begin
							state <= FILTER1;
							cnt_en <= 1'b1;
						end else
						begin
							state <=	IDLE;	
							cnt_en <= 1'b0;
						end
					end
					
				FILTER1:
					begin
							if(cnt_full)//20ms
							begin
								state <= DOWN;
								cnt_en <= 1'b0;
							end 
							else if(pos_edge)
							begin
								state <= IDLE;
								cnt_en <= 1'b0;
							end else
							begin
								state <= FILTER1;
								cnt_en <= cnt_en;
							end
					end
					
				DOWN:
					begin
						if(pos_edge)begin
							cnt_en <= 1'b1;
							state <= FILTER2;
						end else 
						begin
							cnt_en <= 1'b0;
							state <= DOWN;
						end
					end
					
				FILTER2:
					begin
							if(cnt_full)
								state <=	IDLE;	
							else if(neg_edge)begin
								cnt_en <= 1'b0;
								state <= DOWN;
							end 
							else
								state <= FILTER2;
					end
				default: begin
					state <= IDLE;
					cnt_en <= 1'b0;
				end
			endcase
		end
//----cnt--------------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt1 <= 20'd0;
		else if(cnt_en)
			cnt1 <= cnt1 + 20'd1;
			else 
			cnt1 <= 20'd0;
	end
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt_full <= 1'b0;
		else if(cnt1 == 20'd999_999)
			cnt_full <= 1'b1;
			else 
			cnt_full <= 1'b0;
	end
//----asyn_key-->syn---------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			key_syn1 <= 1'b0;
			key_syn2 <= 1'b0;
		end else
		begin
			key_syn1 <= key;
			key_syn2 <= key_syn1;
		end	
	end
//----key edge detect--------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			key_reg1 <= 1'b0;
			key_reg2 <= 1'b0;
		end else
		begin
			key_reg1 <= key_syn2;
			key_reg2 <= key_reg1;
		end	
	end
	assign neg_edge = (!key_reg1) & key_reg2;
	assign pos_edge = key_reg1 & (!key_reg2);
	
//----key_flag---------------------------------------
	assign key_flag = (cnt1 == 20'd999_999)? 1'b1:1'b0;
//----key_state--------------------------------------
		always@(posedge clk or negedge rst_n)
			if(!rst_n)
				key_state <= 1;
			else if(cnt_full)
				key_state <= ~key_state;
			else
				key_state <= key_state;	
endmodule
//----单一字节串口发送----------------------------
//请看UART串口协议以及串口发送端设计1
//------------------------------------------------
//----testbench-----------------------------------
`timescale 1ns/1ns
`define clk_period 20

module uart_tx_multbyte_tb;
	reg     clk;
	reg     rst_n;
	wire    key0;	
	wire	rs232_tx;
	reg     press;
	wire    led;
	
	uart_tx_multbyte uut(
		.clk(clk),
		.rst_n(rst_n),
		.key0(key0),
		.led(led),
		.rs232_tx(rs232_tx)
	);
	key0_model uut_model(
		.press(press),
	   .key(key0)
);
	initial 
		clk = 1;
	always begin #(`clk_period/2) clk = ~clk;end
	
	initial begin
		rst_n = 0;
		press = 0;
	#(`clk_period*20+1)
		rst_n = 1;
	#(`clk_period*20+1);
		press = 1;
	#(`clk_period*20+1);
		press = 0;
		
	wait(uut.tx_done &(uut.cnt_byte == 3'd5));
	
	#(`clk_period*200+1);
	$stop;
	end
endmodule
//----key0_model-------------------------------
`timescale 1ns/1ns
module key0_model(
	input		press,
	output      reg key
);
	reg [15:0] myrand;
	
	initial begin
		key = 1;//before press
	end
	always@(posedge press)
		press_key;
		
task press_key;
	begin
		repeat(50)begin
		myrand = {
    
    $random}%65536;//{$random}%6553(0~65535);{random}%65536:(-65535~65535)
		#myrand; key = ~key;			
	   end
	   key = 0;
		#50000000;
		
		repeat(50)begin
		myrand = {
    
    $random}%65536;//0~65535;
		#myrand; key = ~key;			
	   end
	   key = 1;
		#25_000_000;
	   	
	end
	endtask
endmodule

(3). Modelsim simulation

Insert picture description here
(4). FPGA board-level verification
Insert picture description here
Insert picture description here


----The learning content comes from the video of Xiaomei's FPGA [Note]: Personal study notes, if there are mistakes, please
feel free to enlighten me, this is polite~~~


Guess you like

Origin blog.csdn.net/weixin_50722839/article/details/109731724