FPGA study notes_Serial port transceiver and access dual-port ram simple application

FPGA study notes

Simple application of dual-port ram for serial port transceiver and access

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

Simple application of dual-port ram for serial port transceiver and access

  • Experimental phenomenon: Send data to FPGA through serial port on PC. After FPGA receives data, store the data in a continuous space of dual-port ram. When needed, press button 0, FPGA will store the data in ram. Send out through the serial port.
    Knowledge points:
  1. Internal structure of cyclone iv series devices
  2. The use of memory IP core
  3. Serial port transceiver + button + dual port ram composition suggestion system design

1. Schematic

Insert picture description here

  • Module composition:
    1. uart_rx (uart receiving end)
    2. dual_ram (dual port ram)
    3. uart_tx (uart sender)
    4. key_filter (key debounce)

2. Verilog code

//----top---------------------------------------
module uart_dual_ram(
	input clk,
	input rst_n,
	input  rs232_rx,
	input key_in,
	
	output   rs232_tx
);
	
	wire [7:0] rx_data;
	wire [7:0] tx_data;
	wire		  tx_done;
	wire		  rx_done;
	wire		  key_flag;
	wire		  key_state;
	wire [7:0] rdaddress;
	wire [7:0] wraddress;
	wire 		  wren;
	wire 		  send_en;
	
	
	fsm_key_filter uut_key_filter(
			.clk(clk), 
			.rst_n(rst_n),
			.key(key_in),
			.key_flag(key_flag),
			.key_state(key_state)
	);
	
	uart_rx_r0 uut_uart_rx(
			.clk(clk),
			.rst_n(rst_n),
			.rs232_rx(rs232_rx),
			.baud_set(3'd0),
			.rx_done(rx_done),
			.data_byte(rx_data)
);
	
	uart_tx_r0 uut_uart_tx(
		.clk(clk), 
		.rst_n(rst_n),
		.send_en(send_en),
		.baud_set(3'd0),
		.data_byte(tx_data),
		.rs232_tx(rs232_tx),
		.tx_done(tx_done),
		.uart_state()
);
		ip ram_dual(
		.clock(clk),
		.data(rx_data),
		.rdaddress(rdaddress),
		.wraddress(wraddress),
		.wren(wren),
		.q(tx_data)
);

	uart_ctrl uut_controller(
		.clk(clk),
		.rst_n(rst_n),
		.key_flag(key_flag),
		.key_state(key_state),
		.rx_done(rx_done),
		.tx_done(tx_done),
	
		.rdaddress(rdaddress),
		.wraddress(wraddress),
		.wren(wren),
		.send_en(send_en)

);
endmodule
//--------------------------------------------------------------
//----controller------------------------------------------------
module uart_ctrl(
	input clk,
	input rst_n,
	input key_flag,
	input key_state,
	input rx_done,
	input tx_done,
	
	output reg [7:0] rdaddress,
	output reg [7:0] wraddress,
	output 		  wren,
	output 	reg	  send_en

);
	reg read_send; //
	reg reg1_done;
	reg reg2_done;
	assign wren = rx_done;
//----wraddress-------------------------	
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			wraddress <= 8'd0;
		else if(rx_done)
			wraddress <= wraddress +8'd1;
		else
			wraddress <= wraddress;
//----rdaddress-------------------------			
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			read_send <= 1'd0;
		else if(key_flag && !key_state)
			read_send <= ~read_send;
		else
			read_send <= read_send;
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			rdaddress <= 8'd0;
		else if(read_send && tx_done)
			rdaddress <= rdaddress +8'd1;
		else
			rdaddress <= rdaddress;		
			
//----send_en---------------------------
	always@(posedge clk or negedge rst_n)
		if(!rst_n)begin
			reg1_done <= 1'd0;
			reg2_done <= 1'd0;
		end
		else begin
			reg1_done <= (read_send && tx_done);
			reg2_done <= reg1_done;
		end
			
	always@(posedge clk or negedge rst_n)
		if(!rst_n)
			send_en <= 1'd0;
		else if(key_flag && !key_state)
			send_en <= 1'd1;
		else if(reg2_done)
			send_en <= 1'd1;
		else
			send_en <= 1'd0;

endmodule
//---------------------------------------------------------------------
//----uart_rx----------------------------------------------------------
//请看上一节文章
//---------------------------------------------------------------------
//----uart_tx----------------------------------------------------------
//请看上一节文章
//---------------------------------------------------------------------
//----key_filter-------------------------------------------------------
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

3. Modelsim simulation

Insert picture description here

4. FPGA board-level verification

Insert picture description here


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