FPGA study notes _UART serial port protocol and serial port receiver design

FPGA study notes

1. UART serial port protocol and serial port receiver design

1 原理图
2 Verilog 代码
3 Modelsim仿真
4. FPGA板级验证

1.1 Serial port protocol receiver design

  • Goal: FPGA receives data from other devices via UART.
  • Experimental phenomenon: In Quartusz II, call the in system sources and probes
    editor tool to view the data received by the UART receiving module. The data is sent by the PC.
  • Knowledge points:
    1. The principle of uart's communication protocol and the realization of data acceptance in an industrial environment
    2. Use of debugging tools in system sources and probes editor (ISSP)

1. Schematic

Insert picture description here

  • Module composition:
    1. Input signal synchronization module
    2. Start data detection module
    3. Baud rate generation module
    4. Data receiving process

(1). Sequence diagram of data collection in the sending end laboratory

Insert picture description here

  • Laboratory environment: sample the midpoint of a data

(2). Timing diagram of industrial data collection at the sender
Insert picture description here

  • Industrial environment: The electromagnetic interference in the industrial environment is serious, the noise signal is easy to cause errors, and the data sampled only once is not accurate.
  • Method: Take the results of the middle 6 times of each bit of data sampling, and determine the final result according to the number of occurrences of the level (0,1) of the 6 results.
    Insert picture description here

2. Verilog code

//----top---------------------------------------
module uart_rx_r0
(
	input 				clk,
	input 				rst_n,
	input 				rs232_rx,
	input [2:0]			baud_set,
	
	output 	reg		rx_done,
//	output 			rx_state,
	output reg  [7:0]   data_byte
);

	reg rs232_rx_reg1;
	reg rs232_rx_reg2;
	reg rs232_rx_syn1;
	reg rs232_rx_syn2;
	
	reg uart_state;
	reg [8:0] div_cnt;
	reg [8:0] cnt_max;//div_cnt max value
	reg baud_clk;
	reg [7:0] baud_cnt;
	reg [3:0] reg_data_byte [7:0];
	reg [2:0] START;
	reg [2:0] STOP;	
//	wire pos_edge;
	wire neg_edge;
	
//----asynch rs232_rx--> synch-----------
	always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
			rs232_rx_syn1 <= 0;
			rs232_rx_syn2 <= 0;
		end else begin
			rs232_rx_syn1 <= rs232_rx;
			rs232_rx_syn2 <= rs232_rx_syn1;
		end
//----start bit detect------------------
	always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
			rs232_rx_reg1 <= 0;
			rs232_rx_reg2 <= 0;
		end else begin
			rs232_rx_reg1 <= rs232_rx_syn2;
			rs232_rx_reg2 <= rs232_rx_reg1;
		end
//	assign pos_edge = (rs232_rx_reg1 & !rs232_rx_reg2);
	assign neg_edge = (!rs232_rx_reg1 & rs232_rx_reg2); 
	
//------baud_set------------------------
	always@(*)
		case(baud_set)
			3'd0: cnt_max <= 9'd325;
			3'd1: cnt_max <= 9'd163;
			3'd2: cnt_max <= 9'd81;
			3'd3: cnt_max <= 9'd54;
			3'd4: cnt_max <= 9'd27;
		default: cnt_max <= 9'd325;
		endcase
//----uart_state-------------------------
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			uart_state <= 0;
		else if(neg_edge)
			uart_state <= 1;
		else if(rx_done || (baud_cnt==12 && (START > 2))) 
			uart_state <= 0;
		else
			uart_state <= uart_state;
//----frequence div-->baud_clk-----------
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			div_cnt <= 0;
		else if(uart_state)begin
			if(div_cnt == cnt_max)
				div_cnt <= 0;
			else
				div_cnt <= div_cnt + 9'd1;
		end else
				div_cnt <= 0;
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			baud_clk <= 1'd0;
		else if(div_cnt == 9'd1)
			baud_clk <= 1'd1;
		else
			baud_clk <= 1'd0;
//----baud_cnt--------------------------
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			baud_cnt <= 0;
		else if(rx_done || (baud_cnt==12 && (START > 2)))
			baud_cnt <= 0;
		else if(baud_clk)
				baud_cnt <= baud_cnt + 8'd1;
		else
				baud_cnt <= baud_cnt;
			
//----rx_done----------------------------
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			rx_done <= 1'b0;
		else if(baud_cnt == 8'd159)
			rx_done <= 1'b1;
		else 
			rx_done <= 1'b0;
			
//----data_byte--------------------------
	always@(posedge clk or negedge rst_n) // asynchronos transimiter, reg_data_byte is used to keep input data stable 
		if(!rst_n)
			data_byte <= 8'd0;
		else if(baud_cnt == 8'd159)begin
			data_byte[0] <= reg_data_byte[0][2];
			data_byte[1] <= reg_data_byte[1][2];
			data_byte[2] <= reg_data_byte[2][2];
			data_byte[3] <= reg_data_byte[3][2];
			data_byte[4] <= reg_data_byte[4][2];
			data_byte[5] <= reg_data_byte[5][2];
			data_byte[6] <= reg_data_byte[6][2];
			data_byte[7] <= reg_data_byte[7][2];
		end

//----reg_data_byte----------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			START <= 3'd0;
			reg_data_byte[0] <= 3'd0; 
			reg_data_byte[1] <= 3'd0;
			reg_data_byte[2] <= 3'd0;
			reg_data_byte[3] <= 3'd0;
			reg_data_byte[4] <= 3'd0;
			reg_data_byte[5] <= 3'd0;
			reg_data_byte[6] <= 3'd0;
			reg_data_byte[7] <= 3'd0;
			STOP <= 3'd0;
		end 
		else if(baud_clk)begin
			case(baud_cnt) //0:initial baud_cnt=0 --> after sending data, rs232_tx always be 0; 
				0: begin
						START <= 3'd0;
						reg_data_byte[0] <= 3'd0; 
						reg_data_byte[1] <= 3'd0;
						reg_data_byte[2] <= 3'd0;
						reg_data_byte[3] <= 3'd0;
						reg_data_byte[4] <= 3'd0;
						reg_data_byte[5] <= 3'd0;
						reg_data_byte[6] <= 3'd0;
						reg_data_byte[7] <= 3'd0;
						STOP <= 3'd0;
					end
				6,7,8,9,10,11: START <= START + rs232_rx_reg2;
				22,23,24,25,26,27:       reg_data_byte[0] <= reg_data_byte[0] + rs232_rx_reg2;
				38,39,40,41,42,43:       reg_data_byte[1] <= reg_data_byte[1] + rs232_rx_reg2;
			   54,55,56,57,58,59:       reg_data_byte[2] <= reg_data_byte[2] + rs232_rx_reg2;
				70,71,72,73,74,75:       reg_data_byte[3] <= reg_data_byte[3] + rs232_rx_reg2;
				86,87,88,89,90,91:       reg_data_byte[4] <= reg_data_byte[4] + rs232_rx_reg2;
				102,103,104,105,106,107: reg_data_byte[5] <= reg_data_byte[5] + rs232_rx_reg2;
				118,119,120,121,122,123: reg_data_byte[6] <= reg_data_byte[6] + rs232_rx_reg2;
				130,131,132,133,134,135: reg_data_byte[7] <= reg_data_byte[7] + rs232_rx_reg2;
				148,149,150,151,152,153: STOP <= STOP + rs232_rx_reg2;
				default begin
						START <= START;
						reg_data_byte[0] <= reg_data_byte[0]; 
						reg_data_byte[1] <= reg_data_byte[1];
						reg_data_byte[2] <= reg_data_byte[2];
						reg_data_byte[3] <= reg_data_byte[3];
						reg_data_byte[4] <= reg_data_byte[4];
						reg_data_byte[5] <= reg_data_byte[5];
						reg_data_byte[6] <= reg_data_byte[6];
						reg_data_byte[7] <= reg_data_byte[7];
						STOP <= STOP;				
				end
		endcase
	 end
	end	
	
endmodule
//------------------------------------------------
//----testbench-----------------------------------
`timescale 1ns/1ns
`define clk_period 20

module uart_rx_r0_tb;
	reg clk;
   reg rst_n;
	
	reg [7:0] data_byte_tx;
	wire rx_done;

	reg send_en;
	reg [2:0] baud_set;
	wire [7:0] data_byte_rx;
	wire	rs232_rx;
	wire	tx_done;
	//wire	uart_state; 
	wire led;
	
	uart_rx_r0	uut_rx(
		.clk(clk),
		.rst_n(rst_n),
		.rs232_rx(rs232_rx),
		.baud_set(baud_set),
		.rx_done(rx_done),
		.data_byte(data_byte_rx)
	);
						
		uart_tx_r0 uut_tx(
		.clk(clk),
		.rst_n(rst_n),
		.send_en(send_en),
		.baud_set(baud_set),
		.tx_done(tx_done),
		.data_byte(data_byte_tx),
		.uart_state(led),
		.rs232_tx(rs232_rx)
	);
	
	
		initial begin
		clk = 1;
		rst_n = 0;
		send_en = 0;
		baud_set = 3'd4;
		#(`clk_period*20+1);
		rst_n = 1;
		#(`clk_period*50);
		data_byte_tx = 8'haa;//8'b1010_1010
		send_en = 1;
		#`clk_period;
		send_en = 0;
		
		@(posedge tx_done)
		
		#(`clk_period*5000);
		data_byte_tx = 8'h55;//0101_0101
		send_en = 1;
		#`clk_period;
		send_en = 0;
		
		@(posedge tx_done)
		#(`clk_period*5000);
		$stop;
	end
	always begin #(`clk_period/2) clk = ~clk;end
	
endmodule


3. Modelsim simulation

Insert picture description here

4. FPGA board-level verification
Insert picture description here

  • The serial port assistant sends data, ISSP software receives the data in real time.

----The learning content comes from the video of Xiaomei Ge FPGA

[Note]: Personal study notes, if there are any mistakes, please feel free to enlighten me. This is polite~~~

Guess you like

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