---
# System prepended metadata

title: 7-Seg Display Controlled by UART

---

#  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