__________

Designing the Future with Circuits

반도체 회로설계 취준기

자습시간/Verilog

UART 설계(3) - UART RX 설계 / 최종 설계 완료

semicon_circuitdesigner 2024. 7. 29. 14:36

FSM 순서
  1. idle: din이 1로 유지될 때 대기상태. din이 0이 되면 enable 신호에 맞춰 load로 상태 변경
  2. load: 8비트의 데이터를 받은 뒤 parity를 읽고, parity check로 상태 변경
  3. parity check: 저장한 parity bit와 data bit를 이용하여 패리티 검사
  4. 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으로 수정하여 문제를 해결했다.

Elaborated Design과 제작한 블록 다이어그램이 일치한다

 


최종 설계 코드


[ 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

uart.zip
17.75MB