FSM 순서
- idle: din이 1로 유지될 때 대기상태. din이 0이 되면 enable 신호에 맞춰 load로 상태 변경
- load: 8비트의 데이터를 받은 뒤 parity를 읽고, parity check로 상태 변경
- parity check: 저장한 parity bit와 data bit를 이용하여 패리티 검사
- transmit: 패리티 검사 이후 병렬 데이터를 dout으로 전송
- 다음과 같이 코드를 작성했다.
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 2024/07/28 13:46:57 // Design Name: // Module Name: uart_rx // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module uart_rx( input rst, input clk, input enable, input din, output reg parity_err, output reg [7:0] dout ); localparam odd = 1'b0, even = 1'b1; localparam [1:0] idle = 2'b00, load = 2'b01, parity_chk = 2'b10, transmit = 2'b11; reg [1:0] state = 2'b0; //idle - load - parity check - transmit reg [3:0] bit_cnt = 4'b0; reg [7:0] data; reg read = 1'b0; reg parity; always @(posedge clk) begin if(state==load) begin if(enable) bit_cnt = bit_cnt+1; end end always @(posedge clk) begin case(state) //state idle idle: begin parity_err = 0; if(enable && !din) state = load; else state = idle; end //state load load: begin if(bit_cnt<8) data[bit_cnt] = din; else begin parity = din; if((bit_cnt > 9) && (din == 1)) state = parity_chk; end end //state parity check parity_chk: begin parity_err = (^data) == parity; state = transmit; end transmit: begin dout = data; state = idle; end endcase end endmodule
그 결과는 위와 같이 나타났다. parity_err 신호가 0으로 유지되어야 하는데, 상태 변화 시 잠깐 1로 나타나는 오류가 발생했다.
코드 수정 1: Parity Error이 나타나는 오류 수정
- 테스트벤치 확인 결과 idle에서 bit count도 초기화되지 않았고, parity를 읽어오는 시점이 din의 9번째 비트일 때 읽어야 하나 8번째 비트일 때 읽는 오류도 확인했다.
위 코드에서 주석에 code edit 1로 표기한 부분을 수정하여 문제를 해결했다, - parity error이 나타나는 부분을 확인해보니 다음과 같이 나타났다.
parity check 과정에서 오류가 발생했다. parity error을 출력하는 조건에 문제가 있는 것으로 보인다. - parity error 신호는 데이터의 1의 개수가 홀수일 때 parity가 odd parity이면 오류가 없다는 0을 표시해야 하는데, 코드에서 위 두 값이 같으면(오류가 없으면) 1을 표시하도록 잘못 설계하여 해당 부분을 xor 연산으로 수정하였다.
코드 수정 후 패리티 오류가 발생하지 않았다.
Elaborated Design 확인
Elaborated Design을 확인하였는데, 의도와 다르게 DOUT이 버스 구조로 되어있지 않은것을 확인했다.
따라서 top module에서 output을 output [7:0] DOUT으로 수정하여 문제를 해결했다.
최종 설계 코드
[ uart_top.v ]
더보기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/07/28 13:53:22
// Design Name:
// Module Name: uart_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_top(
input RST,
input CLK,
input SEND,
input PARITY,
input [7:0] DIN,
output BUSY,
output PARITY_ERR,
output [7:0] DOUT
);
wire baudrate, tx2rx, ENABLE;
baud_rate_gen #(.clk_freq (13020), .baud_rate_freq (1)) BAUD_RATE_GEN(
.clk (CLK),
.rst (RST),
.enable (ENABLE),
.baud_rate_signal (BAUDRATE)
);
uart_tx UART_TX(
.rst (RST),
.clk (CLK),
.baud_rate (BAUDRATE),
.din (DIN),
.send (SEND),
.parity (PARITY),
.busy (BUSY),
.dout (tx2rx)
);
uart_rx UART_RX(
.rst (RST),
.clk (CLK),
.enable (ENABLE),
.din (tx2rx),
.parity_err (PARITY_ERR),
.dout (DOUT)
);
endmodule
[ baud_rate_gen.v ]
더보기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/07/23 10:22:39
// Design Name:
// Module Name: baud_rate_gen
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module baud_rate_gen(
input clk,
input rst,
output enable,
output baud_rate_signal
);
parameter clk_freq = 125_000_000;
parameter baud_rate_freq = 9600;
parameter bit_cnt_std = clk_freq/(baud_rate_freq*16);
//reg [15:0] bit = 16'd0;
//reg [12:0] cnt = 13'd0;
reg [19:0] clk_cnt = 12'd0;
reg baud_rate = 1'b1;
assign baud_rate_signal = baud_rate;
reg en;
assign enable = en;
always@(posedge clk) clk_cnt = clk_cnt+1;
always@(posedge clk)begin
if(rst) begin
en = 0;
//bit = 0;
//cnt = 0;
end
else begin
if(clk_cnt > bit_cnt_std*8) begin
baud_rate = 1;
//enable to 1 only 1 clock
// if((bit_cnt_std*8 + 1>clk_cnt) && !baud_rate) en= 1;
// else en = 0;
if(clk_cnt > bit_cnt_std*16)begin
baud_rate = 0;
en = 1;
clk_cnt = 0;
end
end
// if(((bit+8) % 16) == 0) begin
// en = 1;
// bit = 0;
// cnt = 0;
// end
else en = 0;
end //else end
end
endmodule
[ uart_tx.v ]
더보기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/07/23 14:28:21
// Design Name:
// Module Name: uart_tx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_tx(
input rst,
input clk,
input baud_rate,
input [7:0] din,
input send,
input parity,
output reg busy,
output reg dout
);
parameter data_bits = 8;
parameter stop_bits = 1;
//reg [1:0] currstate;
reg [1:0] state;
reg [3:0] bit_cnt = 4'b0;
reg [10:0] data;
reg [7:0] DIN;
reg PARITY;
localparam [1:0] idle = 2'b00,
load = 2'b01,
transmit = 2'b10,
stop = 2'b11;
always @(posedge clk) begin
if(rst) begin dout <= 1'b1; busy <= 1'b0; state <= idle; end
end
always @(posedge baud_rate) begin
if(state == transmit) bit_cnt = bit_cnt+1;
end
always @(posedge clk) begin
//currstate <= nextstate;
PARITY <= parity;
DIN <= din;
end
always@(posedge clk) begin
case (state)
//idle
idle: begin
busy = 1'b0;
dout = 1'b1;
data = 11'b0;
bit_cnt = 0;
if((DIN>=0)&&send) begin
//dout = 0;
state = load;
end
else state = idle;
end
//load data from din
load: begin
if(DIN >= 0) begin
data = {1'b1, PARITY, DIN, 1'b0}; //stop bit - parity - data - start bit
if (send) state = transmit;
end else state = load;
end
//transmit
transmit:begin
if(bit_cnt < data_bits + stop_bits + 2) begin
busy = 1;
dout = data [bit_cnt];
end
else begin dout = 1'b1; state = idle; end
end
//stop
/*stop: begin
dout = 1'b1;
nextstate = idle;
end*/
endcase
end
endmodule
[ uart_rx.v ]
더보기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/07/28 13:46:57
// Design Name:
// Module Name: uart_rx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_rx(
input rst,
input clk,
input enable,
input din,
output reg parity_err,
output reg [7:0] dout
);
localparam odd = 1'b0, even = 1'b1;
localparam [1:0] idle = 2'b00,
load = 2'b01,
parity_chk = 2'b10,
transmit = 2'b11;
reg [1:0] state = 2'b0; //idle - load - parity check - transmit
reg [3:0] bit_cnt = 4'b0;
reg [7:0] data;
reg read = 1'b0;
reg parity;
always @(posedge clk) begin
if(state==load) begin
if(enable) bit_cnt = bit_cnt+1;
end
end
always @(posedge clk) begin
case(state)
//state idle
idle: begin
parity_err = 0;
bit_cnt = 0; //code edit 1
if(enable && !din) state = load;
else state = idle;
end
//state load
load: begin
if(bit_cnt<9) //code edit 1
data[bit_cnt] = din;
else begin
parity = din;
if((bit_cnt > 9) && (din == 1)) state = parity_chk;
end
end
//state parity check
parity_chk: begin
parity_err = (^data) ^ parity;
state = transmit;
end
transmit: begin dout = data; state = idle; end
endcase
end
endmodule
[ uart_tb.v ]
더보기
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024/07/28 13:57:15
// Design Name:
// Module Name: uart_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module uart_tb();
parameter CLK_PD = 8.0;
reg rst, clk, send, parity;
reg [7:0] din;
wire busy, dout, enable;
uart_top uut0(
.RST (rst),
.CLK (clk),
.DIN (din),
.SEND (send),
.PARITY (parity),
.BUSY (busy),
.DOUT (dout)
);
initial begin
rst = 1'b1;
#(CLK_PD*10);
rst = 1'b0;
end
initial clk = 1'b0;
always #(CLK_PD/2) clk = ~clk;
initial begin
rst = 1'b1;
#(CLK_PD*5000);
rst = 1'b0;
parity = 1'b1;
#(CLK_PD*10);
send = 1'b1;
#(CLK_PD*5);
din = 8'b10011110;
#(CLK_PD*10);
send = 1'b0;
#(CLK_PD*20);
$finish;
end
endmodule
'자습시간 > Verilog' 카테고리의 다른 글
Verilog 복습 프로젝트 - 스탑워치 / 계산기 / 타이머 / Pmod OLED (0) | 2025.02.11 |
---|---|
UART(Universal Asynchronous Receiver/Transmitter) (1) | 2024.07.30 |
UART 설계(2) - UART TX 설계 (0) | 2024.07.26 |
UART 설계(1) - Baud Rate Generator 설계 (0) | 2024.07.22 |