# 軟硬體協同設計HW6 ### ● 作業標題:7-Seg Display controlled by UART ### ● 班級姓名座號:國立高雄大學電機系大四 B1095117 黃致衡 ### ● 授課老師:林宏益教授 --- ## 一、作業內容: ### 撰寫具有 UART 通訊協定中能進行 RX 功能的模組。 ## 二、實作步驟: ### 1. 撰寫除頻器的 RTL code (clk_div.v) ``` module clk_div ( input clk, input rst_n, output reg clkout ); parameter BAUDRATE = 9600; parameter DIV_NUMBER = 125000000 / BAUDRATE; reg [13:0] num = 0; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin num <= 0; clkout <= 0; end else if(num == DIV_NUMBER-1) begin num <= 0; clkout <= 1; end else begin num <= num+1; clkout <= 0; end end endmodule ``` ### 2. 再撰寫除頻器的 Testbench (clk_div_tb.v) ``` `timescale 1ns / 1ps module clk_div_tb; reg tb_clk, tb_rst_n; wire clkout; parameter clk_duration = 8; initial begin $dumpfile("test.vcd"); $dumpvars; end initial begin tb_clk = 1'b1; tb_rst_n = 1'b0; #20 tb_rst_n = 1'b1; #20 tb_rst_n = 1'b0; #5_000_000 $finish; end always #(clk_duration/2) tb_clk = ~tb_clk; clk_div u_clk_div(.clk(tb_clk), .rst_n(tb_rst_n), .clkout(clkout)); endmodule ``` ※模擬結果圖 ![divsion](https://hackmd.io/_uploads/ryiLPnBIa.png) > 由此可知 DIVISION_NUMBER 大約需設定為 13020,其公式為: > Clock signal / BAUDRATE。 ### 3. 撰寫 UART 中 RX 模組的 RTL code (clk_div.v) ``` `timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 22:27:09 12/04/2019 // Design Name: // Module Name: uart_rx // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module uart_rx ( input clk, input rst_n, input rx, output reg [9:0] data_out ); // State Machine Defination parameter IDLE = 2'b01; parameter SAMP = 2'b10; // UART Configure Defination parameter START_BIT = 1; parameter DATA_BIT = 8; parameter STOP_BIT = 1; parameter PARI_BIT = 0; parameter RECV_BIT = START_BIT + DATA_BIT + STOP_BIT + PARI_BIT; // Negedge Detection Filter reg [3:0] data_in; always @ (posedge clk or negedge rst_n) if (!rst_n) begin data_in[0] <= 1'b0; data_in[1] <= 1'b0; data_in[2] <= 1'b0; data_in[3] <= 1'b0; end else begin data_in[0] <= rx; data_in[1] <= data_in[0]; data_in[2] <= data_in[1]; data_in[3] <= data_in[2]; end wire rx_neg = data_in[3] & data_in[2] & (~data_in[1]) & (~data_in[0]); reg [1:0] current_state, next_state; // Current State To Next State always @ (posedge clk or negedge rst_n) if(!rst_n) current_state <= IDLE; else current_state <= next_state; // State reg sample_finish; always @(current_state or sample_finish or rx_neg) begin next_state = 2'bx; case(current_state) IDLE : begin if (rx_neg) next_state = SAMP; else next_state = IDLE; end SAMP : begin if (sample_finish) next_state = IDLE; else next_state = SAMP; end default : next_state = IDLE; endcase end reg [3:0] recv_cnt; reg sample_en; reg [RECV_BIT - 1 : 0] data_temp; always @ (posedge clk or negedge rst_n) if (!rst_n) begin data_out <= 10'bx; data_temp <= 10'bx; sample_finish <= 1'b0; sample_en <= 1'b0; recv_cnt <= 4'b0; end else begin case (next_state) IDLE: begin //data_out <= 10'bx; data_temp <= 10'bx; sample_finish <= 1'b0; sample_en <= 1'b0; recv_cnt <= 4'b0; end SAMP: begin if (recv_cnt == RECV_BIT) begin data_out <= data_temp; data_temp <= 10'bx; sample_finish <= 1'b1; sample_en <= 1'b0; recv_cnt <= 4'b0; end else begin sample_en <= 1'b1; if (clk) begin data_out <= data_out; data_temp[recv_cnt] <= rx; sample_finish <= 1'b0; recv_cnt <= recv_cnt + 1'b1; end else begin data_out <= data_out; data_temp <= data_temp; sample_finish <= sample_finish; recv_cnt <= recv_cnt; end end end default: begin data_out <= 10'bx; sample_finish <= 1'b0; sample_en <= 1'b0; end endcase end // Sample Counter Signal Generator parameter BAUD_MAX = 50; reg [5:0] baud_cnt; always @ (posedge clk or negedge rst_n) if (!rst_n) begin baud_cnt <= 6'd0; end else begin if (sample_en) begin if (baud_cnt == BAUD_MAX - 1) baud_cnt <= 6'd0; else baud_cnt <= baud_cnt + 1'b1; end else baud_cnt <= 6'd0; end // Sample Clock Signal Generator parameter BAUD_CNT_H = (BAUD_MAX / 2); wire baud_clk = (baud_cnt == BAUD_CNT_H) ? (1'b1) : (1'b0); endmodule ``` ### 4. 再撰寫 UART 中 RX 模組的 Testbench (uart_tb.v) ``` `timescale 1ns / 1ps // Company: // Engineer: // // Create Date: 14:03:06 12/05/2019 // Design Name: uart_rx // Module Name: D:/Xlinx_ISE_Projects/testbench/uart_rx_tb.v // Project Name: test // Target Device: // Tool versions: // Description: // // Verilog Test Fixture created by ISE for module: uart_rx // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // module uart_tb; // Inputs reg CLK; reg RST_N; reg RX; // Outputs wire [9:0] DATA_OUT; integer i; initial begin $dumpfile("tt.vcd"); $dumpvars(0,uart_tb); $dumpvars; //$fsdbDumpfile("test.fsdb"); //$fsdbDumpvars; end initial begin for(i=0 ; i<=700000 ; i=i+1) begin i = i+1; $display("At time %t, RST_N=%b | RX=%b | data_i=%b", $realtime/1000, RST_N, RX, DATA_OUT); #200; end end always #1 CLK = ~CLK; initial begin // Initialize Inputs CLK = 0; RST_N = 0; RX = 1; // Wait 100 ns for global reset to finish #100; // Add stimulus here RST_N = 1; #100; // Generate Start bit #200 RX = 1'b0; // 8 data bits #200 RX = 1'b1; #200 RX = 1'b0; #200 RX = 1'b1; #200 RX = 1'b0; #200 RX = 1'b0; #200 RX = 1'b0; #200 RX = 1'b0; #200 RX = 1'b0; // Generate Stop bit #200 RX = 1'b1; #600; // Generate Start bit #200 RX = 1'b0; // 8 data bits #200 RX = 1'b1; #200 RX = 1'b1; #200 RX = 1'b1; #200 RX = 1'b0; #200 RX = 1'b0; #200 RX = 1'b1; #200 RX = 1'b1; #200 RX = 1'b1; // Generate Stop bit #200 RX = 1'b1; #20000 $finish; end // Instantiate the Unit Under Test (UUT) uart_rx U_uart_rx ( .clk(CLK), .rst_n(RST_N), .rx(RX), .data_out(DATA_OUT) ); endmodule ``` ※模擬結果圖 ![datawatch](https://hackmd.io/_uploads/B1bXi3SU6.png) ![datawatch2](https://hackmd.io/_uploads/BkFXjhSI6.png) > 由此可見在 testbench 中產生了兩組 data_out 的值,LSB 的 0 代表通知 RX 為 start bit,而 MSB 的 1 代表通知 RX 為 end bit。 >中間夾住的 8bits 則為需要傳送的訊號內容,由右至左判讀。