1, Communication characteristics
Asynchronous, serial, full duplex
Generally, the characteristics of a communication are: synchronous / asynchronous, serial / parallel, half duplex / full duplex
Synchronization: one chip is required to control the timing of another chip. Generally, at least one bus connection is adopted between the two to control the clock ("clock line"), in which the host actively controls the clock line (output through the clock line) and the slave passively receives the clock line (input through the clock line).
Asynchronous: both parties will not connect the clock through the bus. Asynchronous communication requires both parties to use an independent clock generation device (baud rate generator) to generate the same communication speed.
Serial: there is only one data line in each data direction. Only one bit of data is transmitted at a time. Parallelism: there are multiple data lines in each data direction. Multiple bits of data can be transmitted at a time (generally 8 / 16 bits)
Half duplex: there is only one group of data lines. At the same time, only one party controls the transmission of data lines and the other party receives data (that is, both parties cannot send data at the same time)
Full duplex: there are two or more groups of data lines. At the same time, both sides of communication can send data to each other.
2, Introduction to uart protocol
uart: universal asynchronous transceiver Universal asynchronous receiver / transmitter is a universal serial data bus used for asynchronous communication. uart can realize two-way communication. In embedded design, it is often used for communication between host and auxiliary equipment. uart includes RS232, RS449, RS432, RS422, RS485 and other interface standard specifications and bus standard specifications, that is, uart is the general name of asynchronous serial communication port. RS232 , RS449, RS432, RS422 and RS485 are interface standards and bus standards corresponding to various asynchronous serial communication ports. They specify the electrical characteristics, transmission rate, connection characteristics and mechanical characteristics of the communication port. In fact, they belong to the concept of physical layer (the lowest layer) in the communication network and have no direct relationship with the communication protocol. (the content comes from Building your digital building blocks - digital circuit and logic design)
3, This blog mainly introduces the code implementation of RS232 interface standard
Tools used: ISE Design Suite 14.7 FPGA Development board: Basys2 Functions realized: Instruction 1: PC End sending I like FPGAļ¼Development board response I like FPGA, too. stay PC End display. Directive II: PC End sending I like Verilogļ¼Development board response I like Verilog, too. stay PC End display. RTL The view is as follows:
This blog post mainly records the code implementation, which will be sorted out in detail in the future. You are welcome to communicate and give advice
Receive data processing codemodule top_uart_tx_rx( input clk, input rst_n, input rs232_rx, output rs232_tx ); //uart_rx wire [7:0] rx_data; wire rx_done; //uart_tx wire tx_finish; wire send_en; wire [7:0] data_tx; //rx_datadeal wire tx_en1; wire tx_en2; //tx_datadeal uart_rx uart_rx( .clk (clk) , .rst_n (rst_n) , .rs232_rx(rs232_rx) , .rx_data (rx_data) , .rx_done (rx_done) ); uart_tx uart_tx( .clk (clk), .rst_n (rst_n), .send_en (send_en), .data_tx (data_tx), .rs232_tx (rs232_tx), .tx_finish (tx_finish) ); tx_datadeal tx_datadeal( .clk (clk ), .rst_n (rst_n ), .tx_en1 (tx_en1), .tx_en2 (tx_en2), .tx_finish (tx_finish), .send_en (send_en), .data_tx (data_tx) ); rx_datadeal rx_datadeal( .clk (clk) , .rst_n (rst_n) , .rx_data (rx_data), .rx_done (rx_done), .tx_en1 (tx_en1), .tx_en2 (tx_en2) ); endmodule
Receive codemodule rx_datadeal( input clk , input rst_n , input [7:0] rx_data , input rx_done , output reg tx_en1 , output reg tx_en2 ); reg [3:0] data_cnt; reg [3:0] flag1; reg [3:0] flag2; always@(posedge clk or negedge rst_n) begin if(!rst_n) data_cnt <= 4'd0; else if(flag1 == 4'd11 || flag2 == 4'd14 ) data_cnt <= 4'd0; else if(rx_done) data_cnt <= data_cnt + 1'b1; end //Enable signal to tx always@(posedge clk or negedge rst_n) begin if(!rst_n) begin tx_en1 <= 1'b0; tx_en2 <= 1'b0; end else if(flag1 == 4'd11) tx_en1 <= 1'b1; else if(flag2 == 4'd14) tx_en2 <= 1'b1; else begin tx_en1 <= 1'b0; tx_en2 <= 1'b0; end end always@(posedge clk or negedge rst_n) begin if(!rst_n) begin flag1 <= 4'd0; flag2 <= 4'd0; end else if(flag1 == 4'd11) flag1 <= 4'd0; else if(flag2 == 4'd14) flag2 <= 4'd0; else begin case(data_cnt) 4'd0 : begin if(rx_data == "I") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd1 : begin if(rx_data == " ") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd2 : begin if(rx_data == "L") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd3 : begin if(rx_data == "i") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd4 : begin if(rx_data == "k") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd5 : begin if(rx_data == "e") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd6 : begin if(rx_data == " ") begin flag1 <= flag1 + 1'b1; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd7 : begin if(rx_data == "F") begin flag1 <= flag1 + 1'b1; flag2 <= 4'd0; end else if(rx_data == "V") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd8 : begin if(rx_data == "P") begin flag1 <= flag1 + 1'b1; flag2 <= 4'd0; end else if(rx_data == "e") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd9 : begin if(rx_data == "G") begin flag1 <= flag1 + 1'b1; flag2 <= 4'd0; end else if(rx_data == "r") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd10 : begin if(rx_data == "A") begin flag1 <= flag1 + 1'b1; flag2 <= 4'd0; end else if(rx_data == "i") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd11 : begin if(rx_data == "l") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd12 : begin if(rx_data == "o") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end 4'd13 : begin if(rx_data == "g") begin flag1 <= 4'd0; flag2 <= flag2 + 1'b1; end else begin flag1 <= flag1; flag2 <= flag2; end end default : begin flag1 <= 4'd0; flag2 <= 4'd0; end endcase end end endmodule
Send data processing codemodule uart_rx(clk,rst_n,rs232_rx,rx_data,rx_done); input clk; input rst_n; input rs232_rx; output reg [7:0] rx_data; output reg rx_done; reg [1:0]s_rs232_rx;//Elimination of metastability reg [1:0]tmp_rs232_rx;//Data register wire nedge; reg [15:0]div_cnt;//Frequency division counter reg bps_clk; reg uart_state; reg [7:0]bps_cnt; reg [2:0]start_bit; reg [2:0]stop_bit; reg [2:0]rx_data_t [7:0]; // Address width always@(posedge clk or negedge rst_n) if(!rst_n) s_rs232_rx <= 0; else begin s_rs232_rx[0] <= rs232_rx; s_rs232_rx[1] <= s_rs232_rx[0]; end always@(posedge clk or negedge rst_n) if(!rst_n) tmp_rs232_rx <= 0; else begin tmp_rs232_rx[0] <= s_rs232_rx[1]; tmp_rs232_rx[1] <= tmp_rs232_rx[0]; end assign nedge = tmp_rs232_rx[1] & ~tmp_rs232_rx[0]; always@(posedge clk or negedge rst_n) if(!rst_n) div_cnt <= 16'd0; else if(uart_state == 1) begin if(div_cnt == 325) div_cnt <= 16'd0; else div_cnt <= div_cnt + 1; end else div_cnt <= 0; always@(posedge clk or negedge rst_n) if(!rst_n) bps_clk <= 1'b0; else if(div_cnt == 16'b1) bps_clk <= 1'b1; else bps_clk <= 1'b0; always@(posedge clk or negedge rst_n) if(!rst_n) uart_state <= 1'b0; else if(nedge) uart_state <= 1'b1; else if(rx_done || (bps_cnt == 8'd12 && start_bit > 2)) uart_state <= 1'b0; else uart_state <= uart_state; always@(posedge clk or negedge rst_n) if(!rst_n) bps_cnt <= 0; else if(bps_cnt == 8'd159 | (bps_cnt == 8'd12 && start_bit > 2)) bps_cnt <= 0; else if(bps_clk == 1) bps_cnt <= bps_cnt + 1; else bps_cnt <= bps_cnt; always@(posedge clk or negedge rst_n) if(!rst_n) begin rx_done <= 1'b0; end else if(bps_cnt == 8'd159) begin rx_done <= 1'b1; end else begin rx_done <= 1'b0; end always@(posedge clk or negedge rst_n) if(!rst_n) begin start_bit <= 3'd0; rx_data_t[0] <= 3'd0; rx_data_t[1] <= 3'd0; rx_data_t[2] <= 3'd0; rx_data_t[3] <= 3'd0; rx_data_t[4] <= 3'd0; rx_data_t[5] <= 3'd0; rx_data_t[6] <= 3'd0; rx_data_t[7] <= 3'd0; stop_bit <= 3'd0; end else if(bps_clk == 1) begin case(bps_cnt) 0:begin start_bit <= 3'd0; rx_data_t[0] <= 3'd0; rx_data_t[1] <= 3'd0; rx_data_t[2] <= 3'd0; rx_data_t[3] <= 3'd0; rx_data_t[4] <= 3'd0; rx_data_t[5] <= 3'd0; rx_data_t[6] <= 3'd0; rx_data_t[7] <= 3'd0; stop_bit <= 3'd0; end 5,6,7,8,9,10: start_bit <= start_bit + s_rs232_rx[1]; 21,22,23,24,25,26: rx_data_t[0] <= rx_data_t[0] + s_rs232_rx[1]; 37,38,39,40,41,42: rx_data_t[1] <= rx_data_t[1] + s_rs232_rx[1]; 53,54,55,56,57,58: rx_data_t[2] <= rx_data_t[2] + s_rs232_rx[1]; 69,70,71,72,73,74: rx_data_t[3] <= rx_data_t[3] + s_rs232_rx[1]; 85,86,87,88,89,90: rx_data_t[4] <= rx_data_t[4] + s_rs232_rx[1]; 101,102,103,104,105,106: rx_data_t[5] <= rx_data_t[5] + s_rs232_rx[1]; 117,119,120,121,122,123: rx_data_t[6] <= rx_data_t[6] + s_rs232_rx[1]; 133,135,136,137,138,139: rx_data_t[7] <= rx_data_t[7] + s_rs232_rx[1]; 149,151,152,153,154,155: stop_bit <= stop_bit + s_rs232_rx[1]; endcase end always@(posedge clk or negedge rst_n) if(!rst_n) rx_data <= 8'd0; else if(bps_cnt == 159) begin rx_data[0] <= rx_data_t[0][2]; rx_data[1] <= rx_data_t[1][2]; rx_data[2] <= rx_data_t[2][2]; rx_data[3] <= rx_data_t[3][2]; rx_data[4] <= rx_data_t[4][2]; rx_data[5] <= rx_data_t[5][2]; rx_data[6] <= rx_data_t[6][2]; rx_data[7] <= rx_data_t[7][2]; end endmodule
Send codemodule tx_datadeal( input clk, input rst_n, input tx_finish, input tx_en1, input tx_en2, output reg send_en, output reg [7:0] data_tx ); //define reg [4:0] data_cnt; reg tx_state1; reg tx_state2; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin tx_state1 <= 1'b0; tx_state2 <= 1'b0; end else if(tx_en1) tx_state1 <= 1'b1; else if(tx_en2) tx_state2 <= 1'b1; else if(data_cnt == 5'd15) tx_state1 <= 1'b0; else if(data_cnt == 5'd18) tx_state2 <= 1'b0; else begin tx_state1 <= tx_state1; tx_state2 <= tx_state2; end end //data_cnt always@(posedge clk or negedge rst_n) begin if(!rst_n) data_cnt <= 5'd0; else if(tx_state1 == 1'b1 && data_cnt == 5'd15) data_cnt <= 5'd0; else if(tx_state2 == 1'b1 && data_cnt == 5'd18) data_cnt <= 5'd0; else if(tx_finish) data_cnt <= data_cnt + 1'b1; else data_cnt <= data_cnt; end //send_en always@(posedge clk or negedge rst_n) begin if(!rst_n) send_en <= 1'b0; else if(tx_en1 || tx_en2) send_en <= 1'b1; else if(tx_finish) begin if(tx_state1) begin if(data_cnt < 5'd14) send_en <= 1'b1; else send_en <= 1'b0; end else if(tx_state2) begin if(data_cnt < 5'd17) send_en <= 1'b1; else send_en <= 1'b0; end end else send_en <= 1'b0; end always@(posedge clk or negedge rst_n) begin if(!rst_n) data_tx <= 8'd0; else if(tx_state1) begin case(data_cnt) 5'd0 : data_tx <= "I"; 5'd1 : data_tx <= " "; 5'd2 : data_tx <= "L"; 5'd3 : data_tx <= "i"; 5'd4 : data_tx <= "k"; 5'd5 : data_tx <= "e"; 5'd6 : data_tx <= " "; 5'd7 : data_tx <= "F"; 5'd8 : data_tx <= "P"; 5'd9 : data_tx <= "G"; 5'd10 : data_tx <= "A"; 5'd11 : data_tx <= ","; 5'd12 : data_tx <= "t"; 5'd13 : data_tx <= "o"; 5'd14 : data_tx <= "o"; default : data_tx <= 8'd0; endcase end else if(tx_state2) begin case(data_cnt) 5'd0 : data_tx <= "I"; 5'd1 : data_tx <= " "; 5'd2 : data_tx <= "L"; 5'd3 : data_tx <= "i"; 5'd4 : data_tx <= "k"; 5'd5 : data_tx <= "e"; 5'd6 : data_tx <= " "; 5'd7 : data_tx <= "V"; 5'd8 : data_tx <= "e"; 5'd9 : data_tx <= "r"; 5'd10 : data_tx <= "i"; 5'd11 : data_tx <= "l"; 5'd12 : data_tx <= "o"; 5'd13 : data_tx <= "g"; 5'd14 : data_tx <= ","; 5'd15 : data_tx <= "t"; 5'd16 : data_tx <= "o"; 5'd17 : data_tx <= "o"; default : data_tx <= 8'd0; endcase end else data_tx <= 8'd0; end endmodule
TESTBENCHmodule uart_tx(clk,rst_n,tx_finish,send_en,rs232_tx,uart_state,data_tx); input clk ; input rst_n ; input send_en ;//Send enable signal input [ 7:0] data_tx ;//Send byte output reg rs232_tx ; output reg tx_finish ; output reg uart_state ; reg bps_clk ;//baud rate clock reg [ 15:0] div_cnt ;//Frequency division counter reg [ 15:0] bps_DR = 5207 ;//Maximum frequency division count reg [ 3:0] bps_cnt ;//Baud rate counting clock reg [ 7:0] r_data_tx ; localparam START_BYTE = 1'b0 ; localparam STOP_BYTE = 1'b1 ; //control signal always@(posedge clk or negedge rst_n) if(!rst_n) uart_state <= 1'b0; else if(send_en) uart_state <= 1'b1; else if(bps_cnt == 4'd11) uart_state <= 1'b0; else uart_state <= uart_state; //The register stores the transmission information always@(posedge clk or negedge rst_n) if(!rst_n) r_data_tx <= 1'b0; else if(uart_state) r_data_tx <= data_tx; else r_data_tx <= r_data_tx; //counter always@(posedge clk or negedge rst_n) if(!rst_n) div_cnt <= 16'd0; else if(uart_state) begin if(div_cnt == bps_DR) div_cnt <= 16'd0; else div_cnt <= div_cnt + 1'b1; end else div_cnt <= 16'd0; //Generate bps_clk always@(posedge clk or negedge rst_n) if(!rst_n) bps_clk <= 1'b0; else if(div_cnt == 16'd1) bps_clk <= 1'd1; else bps_clk <= 1'b0; always@(posedge clk or negedge rst_n) if(!rst_n) bps_cnt <= 4'd0; else if(bps_cnt == 4'd11) bps_cnt <= 4'd0; else if(bps_clk) bps_cnt <= bps_cnt + 1'b1; else bps_cnt <= bps_cnt; //Generate transmission completion signal always@(posedge clk or negedge rst_n) if(!rst_n) tx_finish <= 1'b0; else if(bps_cnt == 4'd11) tx_finish <= 1'b1; else tx_finish <= 1'b0; //Sending module always@(posedge clk or negedge rst_n) if(!rst_n) rs232_tx <= 1'b1; else begin case(bps_cnt) 0:rs232_tx <= 1'b1; 1:rs232_tx <= START_BYTE; //0 2:rs232_tx <= r_data_tx[0]; 3:rs232_tx <= r_data_tx[1]; 4:rs232_tx <= r_data_tx[2]; 5:rs232_tx <= r_data_tx[3]; 6:rs232_tx <= r_data_tx[4]; 7:rs232_tx <= r_data_tx[5]; 8:rs232_tx <= r_data_tx[6]; 9:rs232_tx <= r_data_tx[7]; 10:rs232_tx <= STOP_BYTE; //1 default:rs232_tx <= 1'b1; endcase end endmodule
module tb_uart_tx_rx; // Inputs reg clk; reg rst_n; reg rs232_rx; // Outputs wire rs232_tx; // Instantiate the Unit Under Test (UUT) top_uart_tx_rx uut ( .clk(clk), .rst_n(rst_n), .rs232_rx(rs232_rx), .rs232_tx(rs232_tx) ); parameter period=20, RST_ING=1'b0, BPS_9600=32'd104_167; initial begin // Initialize Inputs clk = 0; forever #(period/2)clk=~clk; end reg [4:0] cnt; reg [7:0] data_tx; initial begin rst_n = RST_ING; #5000; rst_n = ~RST_ING; rs232_rx = 1'b1; //I Like FPGA #1000_000; data_tx = "I"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "L"; tx_task(data_tx); #1000_000; data_tx = "i"; tx_task(data_tx); #1000_000; data_tx = "k"; tx_task(data_tx); #1000_000; data_tx = "e"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "F"; tx_task(data_tx); #1000_000; data_tx = "P"; tx_task(data_tx); #1000_000; data_tx = "G"; tx_task(data_tx); #1000_000; data_tx = "A"; tx_task(data_tx); //I Like Verilog #100_000_000; data_tx = "I"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "L"; tx_task(data_tx); #1000_000; data_tx = "i"; tx_task(data_tx); #1000_000; data_tx = "k"; tx_task(data_tx); #1000_000; data_tx = "e"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "V"; tx_task(data_tx); #1000_000; data_tx = "e"; tx_task(data_tx); #1000_000; data_tx = "r"; tx_task(data_tx); #1000_000; data_tx = "i"; tx_task(data_tx); #1000_000; data_tx = "l"; tx_task(data_tx); #1000_000; data_tx = "o"; tx_task(data_tx); #1000_000; data_tx = "g"; tx_task(data_tx); //I Like FPGA #100_000_000; data_tx = "I"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "L"; tx_task(data_tx); #1000_000; data_tx = "i"; tx_task(data_tx); #1000_000; data_tx = "k"; tx_task(data_tx); #1000_000; data_tx = "e"; tx_task(data_tx); #1000_000; data_tx = " "; tx_task(data_tx); #1000_000; data_tx = "F"; tx_task(data_tx); #1000_000; data_tx = "P"; tx_task(data_tx); #1000_000; data_tx = "G"; tx_task(data_tx); #1000_000; data_tx = "A"; tx_task(data_tx); end task tx_task; input [7:0] rs232_tx; integer i; begin rs232_rx = 0; #BPS_9600; for(i = 0;i < 8;i = i+1) begin rs232_rx = data_tx[i]; #BPS_9600; end rs232_rx = 1; #BPS_9600; end endtask endmodule
The simulation diagram is as follows:
This blog post is used to record your study. If you reprint it, please indicate the source.