Notas de estudio de FPGA _ Protocolo de puerto serie UART y diseño de receptor de puerto serie

Notas del estudio FPGA

1. Protocolo de puerto serie UART y diseño de receptor de puerto serie

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

1.1 Diseño de receptor de protocolo de puerto serie

  • Objetivo: FPGA recibe datos de otros dispositivos a través de UART.
  • Fenómeno experimental: En Quartusz II, llame a la
    herramienta de edición de fuentes y sondas del sistema para ver los datos recibidos por el módulo receptor UART, los datos son enviados por la PC.
  • Puntos de conocimiento:
    1. El principio del protocolo de comunicación de uart y la realización de la aceptación de datos en un entorno industrial
    2. Uso de herramientas de depuración en fuentes del sistema y editor de sondas (ISSP)

1. Esquemático

Inserte la descripción de la imagen aquí

  • Composición del módulo:
    1. Módulo de sincronización de señal de entrada
    2. Iniciar módulo de detección de datos
    3. Módulo de generación de velocidad en baudios
    4. Proceso de recepción de datos

(1). Diagrama de secuencia de la recopilación de datos en el laboratorio final de envío

Inserte la descripción de la imagen aquí

  • Entorno de laboratorio: muestrear el punto medio de un dato

(2). Diagrama de tiempo de la recopilación de datos industriales en el remitente
Inserte la descripción de la imagen aquí

  • Entorno industrial: la interferencia electromagnética en el entorno industrial es grave, la señal de ruido es fácil de provocar errores y los datos muestreados solo una vez son inexactos.
  • Método: Tome los resultados de las 6 veces intermedias de cada bit de muestreo de datos y determine el resultado final de acuerdo con el número de ocurrencias del nivel (0,1) de los 6 resultados.
    Inserte la descripción de la imagen aquí

2. Código Verilog

//----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. Modelim simulación

Inserte la descripción de la imagen aquí

4. Verificación a nivel de placa FPGA
Inserte la descripción de la imagen aquí

  • El asistente del puerto serie envía datos, el software ISSP recibe los datos en tiempo real.

---- El contenido de aprendizaje proviene del video de Xiaomei Ge FPGA

[Nota]: notas de estudio personal, si hay errores, no dude en aclararme, esto es cortés ~~~

Supongo que te gusta

Origin blog.csdn.net/weixin_50722839/article/details/109744919
Recomendado
Clasificación