# HW6 7-Seg Display Controlled by UART
組員: M1125143 陳奕霖 | 指導老師:林宏益教授
>[color=#6038af]實驗目的 :
>編寫RTL程式燒錄到FPGA面版,使用UART接收PC端TX訊號並將收到的訊號顯示在七段顯示器
>[color=#6038af]實驗材料: PC,Vivado,工作站
## UART簡介
:::info
UART發送端與接收端並不是由共同的時鐘信號來持續對齊,而是透過事先決定好頻率與開始、停止信號來判斷何時讀取資料。

封包由一個Start bit + 8Bits data + 1Stop bit(奇偶較驗位),共10bits組成。

開始位元為高電位轉為第一個的低電位,接收完個8bits完至奇偶較驗位(高電位)
:::
## 實作影片紀錄
:::info
https://youtu.be/Dy2nt7xT2bo
:::
## RTL
### UART架構(rx)

#### 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

9600(baud/second): 每個訊號間格為1/9600=104µs
經過104µs低電位(Start bit)後開始接收訊號,但由於訊號還不穩定所以會先等54µs後才真正開始儲存來源訊號(per data bit)。
:::
## Schematic

## Coverage
:::success

* 開始的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屏蔽掉未執行到的程式碼提升了覆蓋率。
:::

## Lint(SPYGLASS)
:::success

### Warnings

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