거북이처럼 천천히

4X4 Matrix KeyPad - 1 본문

RTL Design/Verilog 연습

4X4 Matrix KeyPad - 1

유로 청년 2024. 8. 9. 12:07

1. 4X4 Matrix KeyPad

 

Verilog RTL 설계(7월 22일 - 1, 4X4 Matrix Keyboard - 1)

1. 4X4 Matrix Keyboard4X4 Matrix Keyboard는 다음과 같은 회로도를 같는다.Row와 Column간에 회로 연결은 16개의 Switch간에 연결되어 있다.   2. 어떻게  버튼이 눌렀는지를 확인하는가?Row 값(R1, R2, R3, R4)들이

jbhdeve.tistory.com

 

 

 

 

< Source, Edge detector >

// Edge detector 
module edge_detector (
    input clk, reset_p,
    input cp,
    output p_edge, n_edge );
    
    reg flip_flop_current, flip_flop_old;
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin flip_flop_current <= 0; flip_flop_old <= 0; end
        else begin
            flip_flop_current <= cp;
            flip_flop_old <= flip_flop_current;
        end
    end
    
    assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10)? 1 : 0;
    assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01)? 1 : 0;
    
endmodule

 

 

 

< Source, Decoder of 7-segment >

// Decoder of 7-seg
module decoder_seg7 (
    input [3:0] hex_value,
    output reg [7:0] seg_7 );
    
    always @(hex_value) begin
        case(hex_value)
            0  : seg_7 = 8'b0000_0011; //common anode, 0이 켜지는거임 
            1  : seg_7 = 8'b1001_1111;  // 1
            2  : seg_7 = 8'b0010_0101;  // 2
            3  : seg_7 = 8'b0000_1101;  // 3
            4  : seg_7 = 8'b1001_1001;  // 4
            5  : seg_7 = 8'b0100_1001;  // 5
            6  : seg_7 = 8'b0100_0001;  // 6
            7  : seg_7 = 8'b0001_1111;  // 7
            8  : seg_7 = 8'b0000_0001;  // 8
            9  : seg_7 = 8'b0000_1001;  // 9
            10 : seg_7 = 8'b0001_0001;  // A
            11 : seg_7 = 8'b1100_0001;  // b
            12 : seg_7 = 8'b0110_0011;  // C
            13 : seg_7 = 8'b1000_0101;  // d
            14 : seg_7 = 8'b0110_0001;  // E
            15 : seg_7 = 8'b0111_0001;  // F
        endcase
    end
endmodule

 

 

 

< Source, Ring counter of com >

// Ring Counter of com
module ring_counter (
    input clk, reset_p,
    output reg [3:0] com );
    
    // Get 1msec One Cycle Pulse.
    wire clk_1usec, clk_1msec;
    clk_div_100 clk_div_1usec (.clk(clk), .reset_p(reset_p), .clk_div_100(clk_1usec));
    clk_div_1000 clk_div_1msec (.clk(clk), .reset_p(reset_p), .clk_source(clk_1usec), .clk_div_1000_nedge(clk_1msec));
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) com = 4'b1110;
        else if(clk_1msec) com = {com[2:0], com[3]};
    end
    
endmodule

 

 

 

 

< Source, FND Control >

// FND Control
module fnd_cntr (
    input clk, reset_p,
    input [15:0] hex_value,
    output [3:0] com,
    output [7:0] seg_7 );
    
    ring_counter ring_counter_com (.clk(clk), .reset_p(reset_p), .com(com));
    
    reg [3:0] value;
    always @(*) begin
        case (com) 
            4'b1110 : value = hex_value [3:0];
            4'b1101 : value = hex_value [7:4];
            4'b1011 : value = hex_value [11:8];
            4'b0111 : value = hex_value [15:12];
            default : value = value;
        endcase
    end
    
    decoder_seg7 decoder_7_segment (.hex_value(value), .seg_7(seg_7));
endmodule

 

 

 

< Source, Clock divider 1000 >

// Clock Divider 1000
module clk_div_1000 (
    input clk, reset_p,
    input clk_source,
    output clk_div_1000,
    output clk_div_1000_nedge, clk_div_1000_pedge );
    
    // Get one cycle pulse of clk_source
    wire clk_source_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
    
    // Prescaling 1000
    reg [9:0] count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) count = 0;
        else if(clk_source_nedge) begin
            if(count >= 999) count = 0;
            else count = count + 1;
        end
    end
    
    assign clk_div_1000 = (count < 500)? 0 : 1;
    edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_1000), .p_edge(clk_div_1000__pedge), .n_edge(clk_div_1000_nedge));
    
endmodule

 

 

 

< Source, Clock divider 100 >

// Clock Divider 100
module clk_div_100 (
    input clk, reset_p,
    output clk_div_100,
    output clk_div_100_nedge, clk_div_100_pedge );
    
    reg [6:0] count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) count = 0;
        else begin
            if(count >= 99) count = 0;
            else count = count + 1;
        end
    end
    
    assign clk_div_100 = (count < 50)? 0 : 1;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_div_100), .p_edge(clk_div_100__pedge), .n_edge(clk_div_100_nedge));
    
endmodule

 

 

 

< Source, Control KeyPad >

// Control KeyPad
module keypad_cntr (
    input clk, reset_p,
    input [3:0] col,
    output reg [3:0] key_value,
    output reg [3:0] row);
    
    // Press Release LED
    assign press_release_led = press_release;
    
    // Declare press_release value
    // press_release = 1 이면 버튼 눌림
    // press_release = 0 이면 버튼 누르지 않음
    reg press_release;
    
    // Get 1msec One Cycle Pulse.
    wire clk_1usec, clk_1msec;
    clk_div_100 clk_div_1usec (.clk(clk), .reset_p(reset_p), .clk_div_100(clk_1usec));
    clk_div_1000 clk_div_1msec (.clk(clk), .reset_p(reset_p), .clk_source(clk_1usec), .clk_div_1000_nedge(clk_1msec));
    
    // 버튼이 누르지 않은 상태와 1msec One Cycle Pulse가 활성화 상태이면 Row값 Shifting
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) row = 4'b0001;
        else if(clk_1msec && !press_release) row = {row[2:0], row[3]};
    end
    
    
    // 버튼이 눌렀음을 확인하는 방법 : col 값이 0이 아닌 경우
    // case 문과 Behavioral modeling 을 통해 어느 버튼이 눌렀음을 확인
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin key_value = 0; press_release = 0; end
        else if(clk_1msec && col) begin
            press_release = 1;
            case({row, col})
                8'b0001_0001 : key_value = 4'h3;
                8'b0001_0010 : key_value = 4'h2;
                8'b0001_0100 : key_value = 4'h1;
                8'b0001_1000 : key_value = 4'h0;
                
                8'b0010_0001 : key_value = 4'h7;
                8'b0010_0010 : key_value = 4'h6;
                8'b0010_0100 : key_value = 4'h5;
                8'b0010_1000 : key_value = 4'h4;
                
                8'b0100_0001 : key_value = 4'hb;
                8'b0100_0010 : key_value = 4'ha;
                8'b0100_0100 : key_value = 4'h9;
                8'b0100_1000 : key_value = 4'h8;
                
                8'b1000_0001 : key_value = 4'hf;
                8'b1000_0010 : key_value = 4'he;
                8'b1000_0100 : key_value = 4'hd;
                8'b1000_1000 : key_value = 4'hc;
                
                default : key_value = key_value;
            endcase
        end
        else press_release = 0;
    end
    
endmodule

 

 

 

 

< Source, Top Module of KeyPad >

// Top Module of KeyPad
module KeyPad_0(
    input clk, reset_p,
    input [3:0] col,
    output press_release_led,
    output [3:0] row,
    output [3:0] com,
    output [7:0] seg_7 );
    
    // Get key value.
    wire [3:0] key_value;
    keypad_cntr keypad_cntr_0 (.clk(clk), .reset_p(reset_p), .col(col), .key_value(key_value), .row(row));
    
    // Print key_value to FND
    fnd_cntr fnd_cntr_0 (.clk(clk), .reset_p(reset_p), .hex_value({12'b0, key_value}), .com(com), .seg_7(seg_7));  
endmodule

 

 

 

 

 

 

2. 구현 연상

 

 

 

 

 

3. 전체 소스 코드

// Top Module of KeyPad
module KeyPad_0(
    input clk, reset_p,
    input [3:0] col,
    output press_release_led,
    output [3:0] row,
    output [3:0] com,
    output [7:0] seg_7 );
    
    // Get key value.
    wire [3:0] key_value;
    keypad_cntr keypad_cntr_0 (.clk(clk), .reset_p(reset_p), .col(col), .key_value(key_value), .row(row));
    
    // Print key_value to FND
    fnd_cntr fnd_cntr_0 (.clk(clk), .reset_p(reset_p), .hex_value({12'b0, key_value}), .com(com), .seg_7(seg_7));  
endmodule

// Control KeyPad
module keypad_cntr (
    input clk, reset_p,
    input [3:0] col,
    output reg [3:0] key_value,
    output reg [3:0] row);
    
    // Press Release LED
    assign press_release_led = press_release;
    
    // Declare press_release
    reg press_release;
    
    // Get 1msec One Cycle Pulse.
    wire clk_1usec, clk_1msec;
    clk_div_100 clk_div_1usec (.clk(clk), .reset_p(reset_p), .clk_div_100(clk_1usec));
    clk_div_1000 clk_div_1msec (.clk(clk), .reset_p(reset_p), .clk_source(clk_1usec), .clk_div_1000_nedge(clk_1msec));
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) row = 4'b0001;
        else if(clk_1msec && !press_release) row = {row[2:0], row[3]};
    end
    
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin key_value = 0; press_release = 0; end
        else if(clk_1msec && col) begin
            press_release = 1;
            case({row, col})
                8'b0001_0001 : key_value = 4'h3;
                8'b0001_0010 : key_value = 4'h2;
                8'b0001_0100 : key_value = 4'h1;
                8'b0001_1000 : key_value = 4'h0;
                
                8'b0010_0001 : key_value = 4'h7;
                8'b0010_0010 : key_value = 4'h6;
                8'b0010_0100 : key_value = 4'h5;
                8'b0010_1000 : key_value = 4'h4;
                
                8'b0100_0001 : key_value = 4'hb;
                8'b0100_0010 : key_value = 4'ha;
                8'b0100_0100 : key_value = 4'h9;
                8'b0100_1000 : key_value = 4'h8;
                
                8'b1000_0001 : key_value = 4'hf;
                8'b1000_0010 : key_value = 4'he;
                8'b1000_0100 : key_value = 4'hd;
                8'b1000_1000 : key_value = 4'hc;
                
                default : key_value = key_value;
            endcase
        end
        else press_release = 0;
    end
    
endmodule


// Clock Divider 100
module clk_div_100 (
    input clk, reset_p,
    output clk_div_100,
    output clk_div_100_nedge, clk_div_100_pedge );
    
    reg [6:0] count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) count = 0;
        else begin
            if(count >= 99) count = 0;
            else count = count + 1;
        end
    end
    
    assign clk_div_100 = (count < 50)? 0 : 1;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_div_100), .p_edge(clk_div_100__pedge), .n_edge(clk_div_100_nedge));
    
endmodule

// Clock Divider 1000
module clk_div_1000 (
    input clk, reset_p,
    input clk_source,
    output clk_div_1000,
    output clk_div_1000_nedge, clk_div_1000_pedge );
    
    wire clk_source_nedge;
    edge_detector edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
    
    reg [9:0] count;
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) count = 0;
        else if(clk_source_nedge) begin
            if(count >= 999) count = 0;
            else count = count + 1;
        end
    end
    
    assign clk_div_1000 = (count < 500)? 0 : 1;
    edge_detector edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_1000), .p_edge(clk_div_1000__pedge), .n_edge(clk_div_1000_nedge));
    
endmodule

// Edge detector 
module edge_detector (
    input clk, reset_p,
    input cp,
    output p_edge, n_edge );
    
    reg flip_flop_current, flip_flop_old;
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) begin flip_flop_current <= 0; flip_flop_old <= 0; end
        else begin
            flip_flop_current <= cp;
            flip_flop_old <= flip_flop_current;
        end
    end
    
    assign p_edge = ({flip_flop_current, flip_flop_old} == 2'b10)? 1 : 0;
    assign n_edge = ({flip_flop_current, flip_flop_old} == 2'b01)? 1 : 0;
    
endmodule

// Ring Counter of com
module ring_counter (
    input clk, reset_p,
    output reg [3:0] com );
    
    // Get 1msec One Cycle Pulse.
    wire clk_1usec, clk_1msec;
    clk_div_100 clk_div_1usec (.clk(clk), .reset_p(reset_p), .clk_div_100(clk_1usec));
    clk_div_1000 clk_div_1msec (.clk(clk), .reset_p(reset_p), .clk_source(clk_1usec), .clk_div_1000_nedge(clk_1msec));
    
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) com = 4'b1110;
        else if(clk_1msec) com = {com[2:0], com[3]};
    end
    
endmodule

// Decoder of 7-seg
module decoder_seg7 (
    input [3:0] hex_value,
    output reg [7:0] seg_7 );
    
    always @(hex_value) begin
        case(hex_value)
            0  : seg_7 = 8'b0000_0011; //common anode, 0이 켜지는거임 
            1  : seg_7 = 8'b1001_1111;  // 1
            2  : seg_7 = 8'b0010_0101;  // 2
            3  : seg_7 = 8'b0000_1101;  // 3
            4  : seg_7 = 8'b1001_1001;  // 4
            5  : seg_7 = 8'b0100_1001;  // 5
            6  : seg_7 = 8'b0100_0001;  // 6
            7  : seg_7 = 8'b0001_1111;  // 7
            8  : seg_7 = 8'b0000_0001;  // 8
            9  : seg_7 = 8'b0000_1001;  // 9
            10 : seg_7 = 8'b0001_0001;  // A
            11 : seg_7 = 8'b1100_0001;  // b
            12 : seg_7 = 8'b0110_0011;  // C
            13 : seg_7 = 8'b1000_0101;  // d
            14 : seg_7 = 8'b0110_0001;  // E
            15 : seg_7 = 8'b0111_0001;  // F
        endcase
    end
endmodule


// FND Control
module fnd_cntr (
    input clk, reset_p,
    input [15:0] hex_value,
    output [3:0] com,
    output [7:0] seg_7 );
    
    ring_counter ring_counter_com (.clk(clk), .reset_p(reset_p), .com(com));
    
    reg [3:0] value;
    always @(*) begin
        case (com) 
            4'b1110 : value = hex_value [3:0];
            4'b1101 : value = hex_value [7:4];
            4'b1011 : value = hex_value [11:8];
            4'b0111 : value = hex_value [15:12];
            default : value = value;
        endcase
    end
    
    decoder_seg7 decoder_7_segment (.hex_value(value), .seg_7(seg_7));
endmodule

'RTL Design > Verilog 연습' 카테고리의 다른 글

10kHz인 PWM 설계 (Duty ratio stage 100단계) - (1)  (0) 2024.08.11
4X4 Matrix KeyPad - 2  (0) 2024.08.10
Stop Watch - 1  (0) 2024.08.07
Advanced Clock  (0) 2024.08.06
Normal Clock  (0) 2024.08.04