[](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)