---
# System prepended metadata

title: UART 的實現與面積縮小

---

[](https://)UART 的實現與面積、功率的縮小
---
**2024**/**12**/**16新增**
**狀態機有錯**、**其餘部分參考上篇筆記**
利用UART通訊協議來實現資料傳輸
![image](https://hackmd.io/_uploads/HyNXBMMFp.png)
本次是實現9600bps的通訊協議

架構
---
![image](https://hackmd.io/_uploads/Sy5xb6XFT.png)


原版程式
---
目的:將PC端的傳輸訊號(ASCII)傳入至FPGA上(receiver端)，輸入1到9顯示1到9，輸入A到E顯示A~E，其他輸入顯示E。
```verilog=
//TOP MODULE
`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
```
```verilog=
//製造9600bps的除頻器

module rx_band_gen(
    input clk,
    input rst,
    input band_sig,
    output reg clk_bps
    );
    parameter SYS_RATE = 125000000;//FPGA 之系統頻率
    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

    
```

![image](https://hackmd.io/_uploads/S1VsoXGY6.png)

```verilog=
//偵測start 訊號
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
```
```verilog=
//UART 狀態機

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;
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://等待start 訊號，H2L發生跳到BEGIN
            if( rx_pin_H2L)
            begin
                rx_band_sig <= 1'b1;//產生rx_clk_bps訊號
                pos <= pos + 1'b1;
                rx_data <= 8'd0;
            end
        BEGIN:
            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://儲存rx_data
            if( rx_clk_bps)
            begin
                rx_data[ pos - DATA0 ] <= rx_pin_in;//rx_pin_in資料儲存至rx_data
                pos <= pos + 1'b1;
            end
            END://完成接收，rx_done_sig輸出1，
                //rx_band_sig輸出0，停止產收rx_clk_bps訊號，跳到BFREE。
            if( rx_clk_bps)
            begin
                rx_done_sig <= 1'b1;
                pos <= pos + 1'b1;
                rx_band_sig <= 1'b0;
            end
        BFREE://rx_done_sig輸出0，回到IDLE
        begin
            rx_done_sig <= 1'b0;
            pos <= IDLE;
        end
    endcase
endmodule
```



![image](https://hackmd.io/_uploads/rJJt0XzFa.png)

```verilog=
//鍵盤數字ASCII轉七段顯示器數字(共陽)之模組
module ASCII2seg7 (
    rst,
    ASCII,
    seg7_out
    );

input rst;
input [7:0] ASCII;
reg [7:0] seg7;
output [7:0] seg7_out;
always@( posedge rst )
begin

    case (ASCII)
        8'b0011_0000:
            seg7<=8'b00000011;
        8'b0011_0001:
            seg7<=8'b10011111;
        8'b0011_0010:
            seg7<=8'b00100101;
        8'b0011_0011:
            seg7<=8'b00001101;
        8'b0011_0100:
            seg7<=8'b10011001;
        8'b0011_0101:
            seg7<=8'b01001001;
        8'b0011_0110:
            seg7<=8'b01000001;
        8'b0011_0111:
            seg7<=8'b00011111;
        8'b0011_1000:
            seg7<=8'b00000001;
        8'b0011_1001:
            seg7=8'b00001001;
        8'b0100_0001:
            seg7=8'b00010001;
        8'b0100_0010:
            seg7=8'b11000001;
        8'b0100_0011:
            seg7=8'b11100101;
        8'b0100_0100:
            seg7=8'b10000101;
        8'b0100_0101:
            seg7=8'b01100001;
        8'b0100_0110:
            seg7=8'b01110001;
        default:
            seg7=8'b01100001;
    endcase

end
assign seg7_out=seg7;
endmodule
```
波型驗證圖
---
![1](https://hackmd.io/_uploads/BkOw2uXtT.jpg)

![2](https://hackmd.io/_uploads/BJUu6dmtT.jpg)

![3](https://hackmd.io/_uploads/SyktTOXFp.jpg)

![4](https://hackmd.io/_uploads/S11RaO7FT.jpg)

![5](https://hackmd.io/_uploads/H1SJAOQtp.jpg)

![6](https://hackmd.io/_uploads/B1YgRumKT.jpg)

# Area and Power report
Design Compiler
---
最小面積使用與最小動態功率Constraint
![image](https://hackmd.io/_uploads/HyQsq5mFp.png)

![image](https://hackmd.io/_uploads/ryhJo9XFp.png)
![image](https://hackmd.io/_uploads/r1E-i5Qt6.png)







![3B50837D-AA84-4E5A-A6FD-6EF2FB09A9CB](https://hackmd.io/_uploads/Sk2APK7K6.jpg)
---->沒有設面積2900up


![12](https://hackmd.io/_uploads/SJfskKXF6.jpg)







   |









第二版
---
思考狀態機的縮減，將接收資料狀態合併成一個狀態--->用編碼減少狀態

```verilog=
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,
    DATA = 4'd2,  // 合併所有數據狀態
    END = 4'd3,
    BFREE = 4'd4;

reg [3:0] pos;
    reg [2:0] data_bit_count; // 計數器用於追蹤數據位

always@(posedge clk or posedge rst) begin
    if(rst) begin
        rx_band_sig <= 1'b0;
        rx_data <= 8'd0;
        pos <= IDLE;
        rx_done_sig <= 1'b0;
        data_bit_count <= 3'd0;
    end
    else begin
        case(pos)
            IDLE: begin
                if(rx_pin_H2L) begin
                    rx_band_sig <= 1'b1;
                    pos <= BEGIN;
                    rx_data <= 8'd0;
                    data_bit_count <= 3'd0;
                end
            end
            BEGIN: begin
                if(rx_clk_bps) begin
                    if(rx_pin_in == 1'b0) begin
                        pos <= DATA;
                    end
                    else begin
                        rx_band_sig <= 1'b0;
                        pos <= IDLE;
                    end
                end
            end
            DATA: begin
                if(rx_clk_bps) begin
                    rx_data[data_bit_count] <= rx_pin_in;
                    if(data_bit_count == 3'd7) begin
                        pos <= END;
                    end
                    else begin
                        data_bit_count <= data_bit_count + 1'b1;
                    end
                end
            end
            END: begin
                if(rx_clk_bps) begin
                    rx_done_sig <= 1'b1;
                    pos <= BFREE;//也可寫<=pos+1
                    rx_band_sig <= 1'b0;
                end
            end
            BFREE: begin
                rx_done_sig <= 1'b0;
                pos <= IDLE;
            end
        endcase
    end
end

endmodule

```
# Second ver. Area and Power report
![messageImage_1705379431048](https://hackmd.io/_uploads/rJCyPKQtp.jpg)


![14](https://hackmd.io/_uploads/HyG2xKQYp.jpg)

面積由原本的2473縮小為2354,縮小率大約為4.8%.



第三版
---
1. 合併狀態後思考著編碼方式的差別，因為one-hot編碼，每個編碼都只有一個高位元所以邏輯上不會合成出複雜的decoder電路。參考課本第299頁
![17](https://hackmd.io/_uploads/SknBEtmKT.jpg)

![18](https://hackmd.io/_uploads/B1g_NFmYp.jpg)



隱憂:相較第二版的2進制只需要3位元，one-hot需要5位元---->面積下降不大。

好處:也因為邏輯轉換上較為簡單(每次只有一個1變0，一個0變1，而二進位可能有多位轉換)我們可以推測，功率會比較小。
```verilog=
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
);

// 使用one-hot編碼定義狀態
localparam [4:0]
    IDLE = 5'b00001,
    BEGIN = 5'b00010,
    DATA = 5'b00100,  // 合併所有數據狀態
    END = 5'b01000,
    BFREE = 5'b10000;

reg [4:0] pos; 
reg [2:0] data_bit_count; // 計數器用於追蹤數據位

always @(posedge clk or posedge rst) begin
    if (rst) begin
        rx_band_sig <= 1'b0;
        rx_data <= 8'd0;
        pos <= IDLE;
        rx_done_sig <= 1'b0;
        data_bit_count <= 3'd0;
    end else begin
        case (pos) // 使用one-hot狀態機
            IDLE: begin
                if (rx_pin_H2L) begin
                    rx_band_sig <= 1'b1;
                    pos <= BEGIN;
                    rx_data <= 8'd0;
                    data_bit_count <= 3'd0;
                end
            end
            BEGIN: begin
                if (rx_clk_bps) begin
                    if (rx_pin_in == 1'b0) begin
                        pos <= DATA;
                    end else begin
                        rx_band_sig <= 1'b0;
                        pos <= IDLE;
                    end
                end
            end
            DATA: begin
            if (rx_clk_bps) begin
                rx_data[data_bit_count] <= rx_pin_in;
                if (data_bit_count == 3'd7) begin
                    pos <= END;
                end else begin
                    data_bit_count <= data_bit_count + 1'b1;
                end
            end
        end
        END: begin
            if (rx_clk_bps) begin
                rx_done_sig <= 1'b1;
                pos <= BFREE;
                rx_band_sig <= 1'b0;
            end
        end
        BFREE: begin
            if (rx_clk_bps) begin
                rx_done_sig <= 1'b0;
                pos <= IDLE;
            end
        end
    endcase
   end
end

endmodule
```

# Third Ver. Area and Power report
![14D05D22-82A3-453C-8F2C-6A6D485D45F6](https://hackmd.io/_uploads/H1WhuKmKp.jpg)




![16](https://hackmd.io/_uploads/HksHfFmtT.jpg)

與原面積相比,由2473降至2306,縮小率約為6.75%.

# UART在FPGA上的實測

![100](https://hackmd.io/_uploads/SJChg9QKp.jpg)

![101](https://hackmd.io/_uploads/rkZCx5QKT.jpg)

![102](https://hackmd.io/_uploads/S1lgW9XFa.jpg)

![103](https://hackmd.io/_uploads/H1D4-9QYp.jpg)

![104](https://hackmd.io/_uploads/ByXr-qmKa.jpg)

![105](https://hackmd.io/_uploads/H12BZ57Y6.jpg)


[demo影片](https://youtu.be/bnsP-E6n6Qc?si=9rLoodm-iH_VMuvb)




















