# HW6 7-Seg Display Controlled by UART 組員: M1125143 陳奕霖 | 指導老師:林宏益教授 >[color=#6038af]實驗目的 : >編寫RTL程式燒錄到FPGA面版,使用UART接收PC端TX訊號並將收到的訊號顯示在七段顯示器 >[color=#6038af]實驗材料: PC,Vivado,工作站 ## UART簡介 :::info UART發送端與接收端並不是由共同的時鐘信號來持續對齊,而是透過事先決定好頻率與開始、停止信號來判斷何時讀取資料。 ![螢幕擷取畫面 2023-12-06 114524](https://hackmd.io/_uploads/HkYACwaS6.png) 封包由一個Start bit + 8Bits data + 1Stop bit(奇偶較驗位),共10bits組成。 ![螢幕擷取畫面 2023-12-06 112520](https://hackmd.io/_uploads/rky0CDTBT.png) 開始位元為高電位轉為第一個的低電位,接收完個8bits完至奇偶較驗位(高電位) ::: ## 實作影片紀錄 :::info https://youtu.be/Dy2nt7xT2bo ::: ## RTL ### UART架構(rx) ![螢幕擷取畫面 2023-12-09 113533](https://hackmd.io/_uploads/rJ_DbPW8p.png =70%x) #### Top module ````VERILOG= `timescale 1ns / 1ps module rx_top( input clk, input rst, input rx_pin_in, output [7:0] seg7 ); wire [7:0] rx_data; wire rx_band_sig; wire clk_bps; rx_band_gen rx_band_gen( .clk( clk ), .rst( rst ), .band_sig( rx_band_sig ), .clk_bps( clk_bps ) ); H2L_detect rx_in_detect( .clk( clk ), .rst( rst ), .pin_in( rx_pin_in ), .sig_H2L( rx_pin_H2L ) ); rx_ctl rx_ctl( .clk( clk ), .rst( rst ), .rx_pin_in( rx_pin_in ), .rx_band_sig( rx_band_sig ), .rx_clk_bps( clk_bps ), .rx_data( rx_data ), .rx_done_sig( rx_done_sig ) ); ASCII27 ASCII27( .rst( rx_done_sig ), .ascii( rx_data ), //rx_data訊號->ASCII .seg7(seg7) ); endmodule ```` #### (H2L_detect):偵測start訊號 ````VERILOG= `timescale 1ns / 1ps module H2L_detect( input clk, input rst, input pin_in, output sig_H2L ); reg pin_pre; assign sig_H2L = !pin_in & pin_pre; always @( posedge clk or posedge rst ) if( rst ) pin_pre <= 1'b0; else pin_pre <= pin_in; endmodule ```` #### rx_ctl 狀態機出發接收動作 ````VERILOG= `timescale 1ns / 1ps module rx_ctl( input clk, input rst, input rx_pin_in, input rx_pin_H2L, output reg rx_band_sig, input rx_clk_bps, output reg[7:0] rx_data, output reg rx_done_sig ) ; localparam [3:0] IDLE = 4'd0, BEGIN = 4'd1, DATA0 = 4'd2, DATA1 = 4'd3, DATA2 = 4'd4, DATA3 = 4'd5, DATA4 = 4'd6, DATA5 = 4'd7, DATA6 = 4'd8, DATA7 = 4'd9, END = 4'd10 , BFREE = 4'd11; //選擇使用4位元表示狀態是為了確保有足夠的位元數來表示所有可能的狀態(獨一無二定義數) reg [3:0] pos; always@( posedge clk or posedge rst ) if( rst ) begin rx_band_sig <= 1'b0; rx_data <= 8'd0; pos <= IDLE; rx_done_sig <= 1'b0; end else case( pos ) IDLE: if( rx_pin_H2L) begin rx_band_sig <= 1'b1; pos <= pos + 1'b1; rx_data <= 8'd0; end if( rx_clk_bps) begin if( rx_pin_in == 1'b0 ) begin pos <= pos + 1'b1; end else begin rx_band_sig <= 1'b0; pos <= IDLE; end end DATA0,DATA1,DATA2,DATA3,DATA4,DATA5,DATA6,DATA7 //接續儲存 if( rx_clk_bps) begin rx_data[ pos - DATA0 ] <= rx_pin_in; pos <= pos + 1'b1; end END: if( rx_clk_bps) begin rx_done_sig <= 1'b1; pos <= pos + 1'b1; rx_band_sig <= 1'b0; end BFREE: begin rx_done_sig <= 1'b0; pos <= IDLE; end endcase endmodule ```` #### rx_band_gen 產生9600bps 接收資料 ````VERILOG= `timescale 1ns / 1ps module rx_band_gen( input clk, input rst, input band_sig, output reg clk_bps ); parameter SYS_RATE = 125000000; parameter BAND_RATE = 9600; parameter CNT_BAND = SYS_RATE / BAND_RATE; parameter HALF_CNT_BAND = CNT_BAND / 2; reg [13:0] cnt_bps; always @( posedge clk or posedge rst ) if( rst ) begin cnt_bps <= HALF_CNT_BAND; clk_bps <= 1'b0; end else if( !band_sig ) begin cnt_bps <= HALF_CNT_BAND; clk_bps <= 1'b0; end else if( cnt_bps == CNT_BAND ) begin cnt_bps <= 14'd0; clk_bps <= 1'b1; end else begin cnt_bps <= cnt_bps + 1'b1; clk_bps <= 1'b0; end endmodule ```` #### ASCII27 ````VERILOG= module ASCII27 ( rst, Ascii, seg7 ); input rst; input [7:0] Ascii; reg [7:0] seg7; output [7:0] seg7_out; always@( posedge rst ) begin case (Ascii) //Spyglass requires nonblocking 8'b0011_0000 : seg7 <=8'b0000_0011; 8'b0011_0001 : seg7 <=8'b1001_1111; 8'b0011_0010 : seg7 <=8'b0010_0101; 8'b0011_0011 : seg7 <=8'b0000_1101; 8'b0011_0100 : seg7 <=8'b1001_1001; 8'b0011_0101 : seg7 <=8'b0100_1001; 8'b0011_0110 : seg7 <=8'b0100_0001; 8'b0011_0111 : seg7 <=8'b0001_1111; 8'b0011_1000 : seg7 <=8'b0000_0001; 8'b0011_1001 : seg7 <=8'b0000_1001; 8'b0100_0001 : seg7 <=8'b0001_0001; 8'b0100_0010 : seg7 <=8'b1100_0001; 8'b0100_0011 : seg7 <=8'b1110_0101; 8'b0100_0100 : seg7 <=8'b1000_0101; 8'b0100_0101 : seg7 <=8'b0110_0001; 8'b0100_0110 : seg7 <=8'b0111_0001; default : seg7 <=8'b0110_0001; endcase assign seg7_out=seg7; end endmodule ```` ## TestBench ````verilog= module rx_tb(); reg clk; reg rst; reg uart_rx; wire [7:0] seg7; rx_top u_rx_top( .clk(clk), .rst(rst), .rx_pin_in(uart_rx), .seg7(seg7) ); initial begin clk=0; //INIT rst=1; //觸發start posedge 開始接收訊號 rst=0; //復位 uart_rx=1; //(確保高電位) //Start bit #130208 uart_rx = 0; //Ascii test #130208 uart_rx = 1; #130208 uart_rx = 0; #130208 uart_rx = 0; #130208 uart_rx = 0; #130208 uart_rx = 0; #130208 uart_rx = 0; #130208 uart_rx = 0; #130208 uart_rx = 0; //Stop bit #130208 uart_rx = 1; #130208 uart_rx = 1; #130208 uart_rx = 1; #130208 uart_rx = 1; end always #10 clk=~clk; endmodule ```` * Teshbench參考參考資料 2。 * 波特率=每秒可傳輸bits的速率,實驗用板子時脈=125MHz,1bit所需傳輸時間125M/9600=130208(ns) ## Simulation :::success ![IMG_0059](https://hackmd.io/_uploads/rkutuvaHT.jpg) 9600(baud/second): 每個訊號間格為1/9600=104µs 經過104µs低電位(Start bit)後開始接收訊號,但由於訊號還不穩定所以會先等54µs後才真正開始儲存來源訊號(per data bit)。 ::: ## Schematic ![螢幕擷取畫面 2023-12-05 133328](https://hackmd.io/_uploads/ByZops3rT.png) ## Coverage :::success ![螢幕擷取畫面 2023-12-07 105608](https://hackmd.io/_uploads/ryRPEhAHa.png) * 開始的Test bench寫法跑coverage覆蓋率很低(TB如上),所以把實驗要求所有情況和default都補上,重跑一遍後覆蓋率有顯著提升。 * Branch coverage: 原本Module rx_ctl部分缺少 else和 default ,因此覆蓋率只有85%左右 拉低了整體覆蓋率。所以加上 default的條件與Coverage on/off提升,並防止line Coverage下降。 * FSM coverage: 由於參考的程式碼沒有跑出FSM coverage,找出原因發現狀態轉換敘述不完整,所以想用Current state ,Next state..去化簡原本的12個狀態,試著嘗試很多次修改程式碼仍然效果不好,所以最後未在Makefile加入執行FSM coverage。(經過Spyglass發現有可能是因為同時含有兩個邏輯敘述導致不會出現FSM Coverage) * Line coverage: 沿用 //coverage on //coverage off屏蔽掉未執行到的程式碼提升了覆蓋率。 ::: ![螢幕擷取畫面 2023-12-07 104530](https://hackmd.io/_uploads/SklD7nCSp.png) ## Lint(SPYGLASS) :::success ![螢幕擷取畫面 2023-12-06 105626](https://hackmd.io/_uploads/rylXOw6rp.png) ### Warnings ![螢幕擷取畫面 2023-12-06 102048](https://hackmd.io/_uploads/SyuQchArT.png) Sequential and Combinational parts of FSM desciption should be seperated : * 時序和組合邏輯部分在同一個Top module 中造成。因為同一個區塊中用了時序(正負緣觸發)和組合邏輯(ascii27)導致,所以盡量不要把這兩個邏輯敘述放在一起,不然會導致程式提高複雜性,進而降低程式的可讀性,在使用Tool上也會增加負擔,得回去重新修改RTL Code. ::: ## 參考資料 https://www.youtube.com/watch?v=IyGwvGzrqp8 https://blog.csdn.net/qq_24287711/article/details/130294198?utm_medium=distribute.pc_relevant.none-task-blog-2