본문 바로가기
# Semiconductor/- Semicon Academy

[Harman 세미콘 아카데미] 58일차 - Verilog(Ultrasonic : 오류 수정, FSM 없이 구현, Testbench)

by Graffitio 2023. 9. 15.
[Harman 세미콘 아카데미] 58일차 - Verilog(Ultrasonic : 오류 수정, FSM 없이 구현, Testbench)
728x90
반응형
[오류 수정]

 

동작 중에 echo wire를 뺴버리면, 동작이 중단되고 pedge를 기다리는 상태에 갇혀서 못 빠져나온다.

따라서 이러한 에러가 발생했을 경우에 에러 처리를 하는 코드를 추가해보자.

 

S_WAIT_PEDGE : begin
    LED_bar[2] <= 1;
    if(echo_pedge) begin
        old_usec <= count_usec;
        count_usec_e <= 1;
        next_state <= S_WAIT_NEDGE;
    end
    else begin // 따지고 보면, pedge 발생 안 하면 아무 것도 안 하는 상태이다. 사실 아무 것도 안 아면, else 생략 가능
        if(count_usec < 22'd80_000) begin 
            count_usec_e <= 1;
            next_state <= S_WAIT_PEDGE;
        end
        else begin // 80ms동안 pedge가 안 나오면, 초기상태로 돌아가라.
            next_state <= S_IDLE;
            count_usec_e <= 0;
        end
    end
end

 

S_WAIT_NEDGE : begin
    LED_bar[3] <= 1;
    if(echo_nedge) begin
//      temp_value[0] <= count_usec; // 0번 index에 접근
        temp_value[index] <= count_usec - old_usec;
        index <= index + 1; // 2의 거듭제곱 쓰면 if문 써서 조건 추가할 필요가 없다. 15다음 16, 7다음8이니까~ 자동적으로 1더하면 0으로 초기화됨
        count_usec_e <= 0;
        next_state <= S_IDLE;
    end
    else begin // 안 써줘도 되는 건데, 가독성을 위해 작성
        if(count_usec < 22'd80_000) begin
            count_usec_e <= 1;
            next_state <= S_WAIT_NEDGE; 
        end
        else begin // 80ms동안 nedge 안 나오면, 초기상태로 돌아가라
            next_state <= S_IDLE;
            count_usec_e <= 0;
        end
    end
end

echo pin 꽃힌 상태

위와 같이 Echo핀을 빼도 trig 신호가 정상적으로 동작한다.

 


 

[FSM를 쓰지 않고 구현]

 

📌 Main module

module Ultrasonic_not_fsm(
    input clk, rst,
    input echo,
    output reg trig,
    output reg [15:0] distance,
    output reg [7:0] LED_bar
    );
    
    reg [16:0] count_usec_ch, count_usec_tr, count_usec_idle; // 넉넉히 주면 좋다. 메뉴얼에는 60ms의 여유를 주라 했는데, 실제로는 70ms 넘어서도 걸린다.
    wire clk_usec;
    reg count_usec_ch_e, count_usec_tr_e, count_usec_idle_e;
    clock_usec usec_clk(.clk(clk), .rst(rst), .clk_usec(clk_usec));
    
    // usec Counter
    always @(negedge clk, posedge rst) begin
        if(rst) begin
            count_usec_ch = 0; // 리셋 누르면 출력이 0되도록 설계
        end
        else begin
            // data가 들어올 때 동안만 count
            if(clk_usec && count_usec_ch_e) count_usec_ch = count_usec_ch + 1; // enable이 1이고, clk_usec가 들어올 때만 count++
            else if(!count_usec_ch_e) count_usec_ch = 0;       
        end
    end
    
    // usec Counter
    always @(negedge clk, posedge rst) begin
        if(rst) begin
            count_usec_tr = 0;
        end
        else begin
            // data가 들어올 때 동안만 count
            if(clk_usec && count_usec_tr_e) count_usec_tr = count_usec_tr + 1;
            else if(!count_usec_tr_e) count_usec_tr = 0;            
        end
    end
    
        // usec Counter
    always @(negedge clk, posedge rst) begin
        if(rst) begin
            count_usec_idle = 0;
        end
        else begin
            // data가 들어올 때 동안만 count
            if(clk_usec && count_usec_idle_e) count_usec_idle = count_usec_idle + 1;
            else if(!count_usec_idle_e) count_usec_idle = 0;            
        end
    end
    
    //Edge를 보내서 쓰는 걸로 clk 동기화
    wire echo_pedge, echo_nedge;
    edge_detector_n edg_echo(.clk(clk), .cp_in(echo), .rst(rst), .p_edge(echo_pedge), .n_edge(echo_nedge)); // Edge Detector
    
    // trigger
    always @(posedge clk, posedge rst) begin
        if(rst) begin
            trig = 0;
            count_usec_tr_e = 0;
            count_usec_idle_e = 0;
            LED_bar = 8'b0000_0000;
        end
        else begin
            // IDLE
            if(count_usec_idle < 22'd80_000) begin
//            if(count_usec_idle < 22'd5000) begin
                count_usec_idle_e = 1;
                LED_bar[0] = 1;
            end
            else begin
                // trigger
                if(count_usec_tr < 22'd12) begin
                    trig = 1;
                    count_usec_tr_e = 1;
                end            
                else begin
                    trig = 0;
                    count_usec_tr_e = 0;
                    count_usec_idle_e = 0;
                    LED_bar[1] = 1;
                end
            end
        end
    end

    //echo
    reg [16:0] temp_value [15:0], old_time;
    reg [20:0] sum_value;
    reg [3:0] index;
    always @(posedge clk, posedge rst) begin
        if(rst) begin
            count_usec_ch_e = 0;
            index = 0;
            old_time = 0;
            LED_bar = 8'b0000_0000;
        end
        else begin
            if(echo_pedge) begin
                old_time = count_usec_ch;
            end
            else if(echo_nedge) begin // 1 clk(8ns) 안에 pedge와 nedge가 둘 다 High가 되지 않으므로, els
                temp_value[index] = (count_usec_ch - old_time);
                index = index + 1;
                count_usec_ch_e = 0;
            end
            else begin
                if(count_usec_ch < 22'd23_200) begin
                    count_usec_ch_e = 1;
                end
                else begin
                    count_usec_ch_e = 0;
                end
            end
        end
    end

    // calculate
    reg [5:0] i;
    always @(posedge clk_usec, posedge rst) begin
        if(rst) begin
            sum_value = 0;
            i = 0;
        end
        else begin
            LED_bar[7] = 1;
            sum_value = 0;
            for(i = 0 ; i < 16 ; i = i+1) begin
                sum_value = sum_value + temp_value[i];
            end
        end
    end

    // distance
    always @(posedge clk_usec, posedge rst) begin
        if(rst) begin
            distance = 0;
        end
        else begin
            distance = sum_value[20:4] / 58;
        end
    end

endmodule

 

📌 Top module

module Ultrasonic_Top_not_fsm(
    input clk, rst,
    input echo,
    output trig,
    output [7:0] LED_bar,
    output [3:0] com,
    output [7:0] seg_7
    );

    wire [15:0] distance;
    Ultrasonic_not_fsm SR04_not(clk, rst, echo, trig, distance, LED_bar);

    wire [15:0] distance_dec;
    bin_to_dec ultra_b2d(.bin(distance[11:0]), .bcd(distance_dec)); // 400cm 충분히 받으므로 12bit로 짤라버려도 된다.

    FND_4digit_cntr fnd_cntr(.clk(clk), .rst(rst), .value(distance_dec), .com(com), .seg_7(seg_7));

endmodule

 

 

 

[Testbench]

 

module tb_Ultrasonic_profsr();
    reg clk, rst;
    reg echo;
    wire trig;
    wire [15:0] distance_cm;
//    wire [7:0] LED_bar;

    UltraSonic_Profsr DUT(clk, rst, echo, trig, distance_cm, LED_bar);
    
    parameter data1 = 58 * 10 * 1000; // 10cm, usec으로 바꿔주려면 1000 곱해줘야 한다.
    parameter data2 = 58 * 23 * 1000; // 23cm
    
    initial begin
        clk = 0;
        rst = 1; 
        echo = 0;    
    end
    
    always #4 clk = ~clk;
    
    // data1 16번 보내고, data2 16번 보낼 것이다.
    integer i;
    initial begin
        #8;
        rst = 0; #8;
        
        for(i = 0 ; i < 16 ; i = i+1) begin
            wait(trig);
            wait(!trig);
            #28000; // 28ms동안 burst 대기
            echo = 1; #data1;
            echo = 0;            
        end
        for(i = 0 ; i < 16 ; i = i+1) begin
            wait(trig);
            wait(!trig);
            #28000; // 28ms동안 burst 대기
            echo = 1; #data2;
            echo = 0;            
        end
        #28000; // FND에 출력될 시간은 줘야 된다.
        $stop;        
    end

endmodule

 

 

 


 

728x90
반응형