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

本次是實現9600bps的通訊協議
架構
---

原版程式
---
目的:將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
```

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

```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
```
波型驗證圖
---






# Area and Power report
Design Compiler
---
最小面積使用與最小動態功率Constraint




---->沒有設面積2900up

|
第二版
---
思考狀態機的縮減,將接收資料狀態合併成一個狀態--->用編碼減少狀態
```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


面積由原本的2473縮小為2354,縮小率大約為4.8%.
第三版
---
1. 合併狀態後思考著編碼方式的差別,因為one-hot編碼,每個編碼都只有一個高位元所以邏輯上不會合成出複雜的decoder電路。參考課本第299頁


隱憂:相較第二版的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


與原面積相比,由2473降至2306,縮小率約為6.75%.
# UART在FPGA上的實測






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