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

FPGA study notes

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

  • Send a single byte

    1.1 Introduction to UART
    1.2 Serial protocol transmitter design

1.1 Introduction to UART

(1). Concept:
UART: (Universal Asynchronous Receiver/Transmitter) is the general term for asynchronous serial communication. Full duplex, sending end: parallel to serial; receiving end: serial to parallel. Including RS232, RS449, RS423, RS485 (interface standards and bus standards of various asynchronous serial communication ports, electrical characteristics, transmission rate, connection characteristics, mechanical characteristics of the interface, etc.).
(2). Features:
simple circuit structure and low cost.
(3). Key parameters:
data bits : the number of data bits sent during the start and stop of a single UART data transmission; 5, 6, 7, 8 (default) can be selected.
Baud rate (baud): from one The number of data bits that can be communicated per second from a device to another device. Typical baud rates are 300, 1200, 2400, 9600, 19200, 115200 (1s: 115200bits; 1bit: 8.68us), etc. The same baud rate should be set at both ends of the communication device.
[Conversion of baud rate and clock period]:
frequency (f)=500MHz, period (T)=20ns;
baud rate B(bps) >> 1s to transmit Bbit data >> 1bit data transmission needs (1/B(bps) )) s=(1000000000/ B(bps)) ns
baud rate division count value: (1000000000/ B(bps)) ns/clock period
System clock count value = baud rate division count value-1;
Insert picture description here
Parity bit: verify the correctness of the data. Even parity (even): the even number of 1 digits in the transmitted digits; odd parity (odd): the odd number of 1 digits in the transmitted digits (including each digit of the character and the check digit).
Stop bits:After the data bit of each byte is sent, the stop bit is sent to mark the completion of a data transmission. At the same time, it can be used to help the receiver's hardware synchronization. Selectable bits: 1 (default), 1.5, 2 bits.
RS323: 8N1 ​​(8 data bits, 1 stop bit, no parity bit)

1.2 The design of the sending end of the serial port protocol

(1). Overall block diagram of the serial port protocol transmitter
Insert picture description here
Insert picture description here

(2). Sequence diagram of the serial port protocol transmitter
Insert picture description here
START: low level
STOP: high level
DATA: 8bits

(3). Verilog code


module uart_tx_r0#(
	parameter START = 1'b0,
	parameter STOP = 1'b1
)
(
		input 		clk, //50MHz
		input 		rst_n,
		input			send_en,
		input [2:0] baud_set,
		input [7:0] data_byte,
		
		output reg	rs232_tx,
		output reg	tx_done,
		output reg	uart_state
);
//----define--------------------------------------
	reg [7:0]	reg_data_byte;
	reg [15:0] 	cnt;//divide frequence counter
	reg			baud_clk;
	reg [15:0]	cnt_max;//baud value
	reg [3:0]   cnt_bit;//
	
	
	
//----baud_set--------------------------------------
	always@(*)begin
		case(baud_set)
//			0:	cnt_max <= 16'd20832;
//			1: cnt_max <= 16'd10415;
			0: cnt_max <= 16'd5207;
			1: cnt_max <= 16'd2603;
			2: cnt_max <= 16'd1301;
			3: cnt_max <= 16'd867;
			4: cnt_max <= 16'd433;
//			7: cnt_max <= 16'd194;
			default: cnt_max <= 5207;
		endcase
	end

//----divide frequence counter-->baud clock------------------------	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			cnt <= 0;
		end 
		else if(uart_state)begin
			if(cnt == cnt_max) 
			cnt <= 0;
		else
			cnt <= cnt +16'd1;
		end else
			cnt <= 0;
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			baud_clk <= 1'b0;
		else if(cnt == 16'd1)
			baud_clk <= 1'b1;
		else
			baud_clk <= 1'b0;
	end
//----cnt_bit----------------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			cnt_bit <= 0;
		else if(cnt_bit == 4'd11)
				cnt_bit <= 0;
		else if(baud_clk)
				cnt_bit <= cnt_bit + 4'd1;
		else
				cnt_bit <= cnt_bit;
	end
//----rs232_tx --------------------------------------	
	always@(posedge clk or negedge rst_n)begin // asynchronos transimiter, reg_data_byte is used to keep input data stable 
		if(!rst_n)
			reg_data_byte <= 8'd0;
		else if(send_en)
			reg_data_byte <= data_byte;
		else
			reg_data_byte <= reg_data_byte;
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			rs232_tx <= 0;
		end begin
			case(cnt_bit) //0:initial cnt_bit=0 --> after sending data, rs232_tx always be 0; 
				0: rs232_tx <= 1'b1;
				1: rs232_tx <= START; //0
				2: rs232_tx <= reg_data_byte[0];
				3: rs232_tx <= reg_data_byte[1];
			   4: rs232_tx <= reg_data_byte[2];
				5: rs232_tx <= reg_data_byte[3];
				6: rs232_tx <= reg_data_byte[4];
				7: rs232_tx <= reg_data_byte[5];
				8: rs232_tx <= reg_data_byte[6];
				9: rs232_tx <= reg_data_byte[7];
				10: rs232_tx <= STOP; //1
				default: rs232_tx <= 1;
		endcase
	 end
	end
//----tx_done-----------------------------------------
		always@(posedge clk or negedge rst_n)begin
			if(!rst_n)
				tx_done <= 1'b0;
			else if(cnt_bit == 4'd11)
				tx_done <= 1'b1;
			else
				tx_done <= 1'b0;
		end
		
//----uart_state--------------------------------------
		always@(posedge clk or negedge rst_n)
			if(!rst_n)
				uart_state <= 1'b0;
			else if(send_en)
				uart_state <= 1'b1;
			else if(cnt_bit == 4'd11)
				uart_state <= 0;
			else
				uart_state <= uart_state;

endmodule

//------------------------------------------------
//----testbench-----------------------------------
`timescale 1ns/1ns
`define clk_period 20

module tb_uart_tx_r0;
	reg clk;
	reg rst_n;
	reg send_en;
	reg [2:0] baud_set;
	reg [7:0] data_byte;
	
	wire	rs232_tx;
	wire	tx_done;
	wire	uart_state; 
	
	uart_tx_r0 uut(
		.clk(clk),
		.rst_n(rst_n),
		.send_en(send_en),
		.baud_set(baud_set),
		.tx_done(tx_done),
		.data_byte(data_byte),
		.uart_state(uart_state),
		.rs232_tx(rs232_tx)
	);
	
	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 = 8'haa;//8'b1010_1010
		send_en = 1;
		#`clk_period;
		send_en = 0;
		
		@(posedge tx_done)
		
		#(`clk_period*5000);
		data_byte = 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

----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/109554050