관리 메뉴

거북이처럼 천천히

Verilog RTL 설계(7월 23일 - 5, DHT11 구현 (4) ) 본문

RTL Design/Verilog RTL 설계

Verilog RTL 설계(7월 23일 - 5, DHT11 구현 (4) )

유로 청년 2024. 8. 19. 18:54

1. DHT11과 Basys3 통신 과정에서 예외 상황이 발생했을 경우

  • 이전 게시글인 Verilog RTL 설계(7월 23일 - 4, DHT11 구현 (3))  에서는 dht11과 Basys3 간에 통신이 원활히 이루어져서 온도, 습도 데이터를 제대로 전달 받는 상황을 가정하고 설계하였다.
  • 하지만, 예기치 못한 상황이 발생하여 dht11과 basys3 간에 통신이 끊기거나 데이터를 전송하고, 받는 과정에서 신호 및 데이터를 놓치는 경우가 발생할 수 있기 때문에 이에 대한 예외 처리 할 필요가 있다.
  • 따라서 Verilog RTL 설계(7월 23일 - 4, DHT11 구현 (3)) 게시글에서 구현했던 DHT11 Control 모듈을 기반으로 The Worst Case 상황에 대한 예외 처리를 하도록 설계 해도록 하겠다.

 

 

 

2.  The worst case에 대한 예외 처리 

  • The worst case에 대한 예외 처리는 이전에 구현한 dht11 control 모듈과 비교하며, 코드의 일부를 수정 및 설명을 하도록 하겠다.
  • Q) DHT11과 Basys3 통신 과정에서 문제가 발생할 수 있는 부분은 어디 부분인가?
    A)
    통신 과정에서 문제가 발생할 수 있는 부분은 총 3가지 부분으로 볼 수 있으며, 이에 대한 예외처리가 필요하다.
    ▶ DHT11가 Basys3로부터 Start Signal을 받지 못해 Response Signal을 못하는 경우
    ▶ DHT11로부터 40bit 온,습도 데이터를 받는 과정에서 1bit 이상의 데이터를 놓친 경우
    ▶ DHT11에서 온,습도 데이터를 40bit 크기로 받지 못한 경우


 

2.1. 3 단계)  S_HIGH_20US 단계에서 dht11_data wire에 negative edge가 발생하지 않을 경우

  • 원할히 통신이 이루어 져서 Basys3측에서 Start Signal을 dht11측으로 전달하면 dht11은 Response Signal을 basys3측으로 전달할 것이다.
  • 하지만, 원치 않는 이유로 Basys3측에서 Start Signal이 dht11측으로 전달되지 못한다면 dht11은 Start signal을 받지 못해 Response signal을 발생시키지 못한다.
  • 따라서 이에 대한 예외처리가 필요하며, 이를 위한 처리를 다음과 같이 설계하였다.

DHT11_data wire에서 Negative edge가 발생하지 않는 경우

 

 

< 수정 전, 3단계) S_HIGH_20US > 

// 3단계 : S_HIGH_20US
S_HIGH_20US : begin
     if(counter < 22'd20) begin
         enable_counter = 1;
         temp_dht11 = 'bz;
     end
     else begin
        enable_counter = 0;
        next_state = S_LOW_80US;
     end 
end

 

< 수정 후, 3단계) S_HIGH_20US > 

S_HIGH_20US : begin
    counter_enable = 1;
    reg_of_dht11_data = 'bz;
    
    if (usec_counter >= 22'd100_000) begin
        next_state = S_IDLE;
        counter_enable = 0;
    end
    else if (dht11_data_nedge) begin
        counter_enable = 0;
        next_state = S_LOW_80US;
    end 
end
  • usecond counter를 통해 100ms까지 기다려 본 뒤, 100ms 이전에 Negative edge가 발생하면 usecond counter를 초기화 시켜준 뒤, 다음 상태인 S_LOW_80US로 넘어간다.
  • 하지만, 100ms까지 기다려 봤음에도 Negative edge가 발생하지 않는다면 'DHT11과 통신하는 과정에서 예기치 못한 문제가 발생하여 DHT11측에서 Response signal을 발생시키지 않았다." 라고 판단하여 usecond counter를 초기화 시켜준 뒤, 첫 단계인 S_IDLE로 넘어 간다.

 

 

 

 

2.2. 4 단계)   S_LOW_80US 단계에서 dht11_data wire에 positive edge가 발생하지 않을 경우

  • DHT11의 Response signal이 정상적으로 동작한다면 S_LOW_80US 단계에서 Positve edge를 발생하며, 다음 단계인 S_HIGH_80US 단계로 넘어 갈 것이다.
  • 하지만, dht11의 Response signal이 basys3측으로 전달되는 과정에서 예기치 못한 이유로 positive edge가 발생하지 않을 수 도 있기 때문에 이에 대한 예외 처리가 필요하다.

 

 

 

< 수정 전, 4단계) S_LOW_80US 

// 4단계 : S_LOW_80US
S_LOW_80US : 
    if(dht11_data_pedge) next_state = S_HIGH_80US;

 

 

< 수정 후, 4단계) S_LOW_80US 

// 4단계) S_LOW_80US
S_LOW_80US : begin
    counter_enable = 1;
    if (usec_counter >= 22'd100_000) begin
        next_state = S_IDLE;
        counter_enable = 0;
    end
    else if (dht11_data_pedge) begin
        next_state = S_HIGH_80US;
        counter_enable = 0;
    end
end
  • usecond counter를 통해 100ms까지 기다려 본 뒤, 100ms 이전에 Positive edge가 발생하면 usecond counter를 초기화 시켜준 뒤, 다음 상태인 S_HIGH_80US로 넘어간다.
  • 하지만, 100ms까지 기다려 봤음에도 Positive edge가 발생하지 않는다면 'DHT11과 통신하는 과정에서 예기치 못한 문제가 발생하여 DHT11측에서 Response signal을 발생시키지 않았다." 라고 판단하여 usecond counter를 초기화 시켜준 뒤, 첫 단계인 S_IDLE로 넘어 간다.

 

 

 

 

2.3. 5 단계)  S_HIGH_20US 단계에서 dht11_data wire에 negative edge가 발생하지 않을 경우

  • DHT11이 정상적으로 동작한다면 S_HIGH_80US 단계에서 Negate edge를 발생하며, 다음 단계인 S_DATA 단계로 넘어 갈 것이다.
  • 하지만, dht11에서 basys3측으로 온습도 데이터 전달되는 과정에서 예기치 못한 이유로 Negative edge가 발생하지 않을 수 도 있기 때문에 이에 대한 예외 처리가 필요하다.

 

 

 

< 수정 전, 5단계) S_HIGH_80US 

// 5단계 : S_HIGH_80US
S_HIGH_80US : 
     if(dht11_data_nedge) next_state = S_READ_DATA;

 

< 수정 후, 5단계) S_HIGH_80US 

// 5단계) S_HIGH_80US
S_HIGH_80US : begin
    counter_enable = 1;
    if (usec_counter >= 22'd100_000) begin
        next_state = S_IDLE;
        counter_enable = 0;
    end
    else if (dht11_data_nedge) begin
        next_state = S_DATA;
        counter_enable = 0;
    end
end
  • usecond counter를 통해 100ms까지 기다려 본 뒤, 100ms 이전에 Negative edge가 발생하면 usecond counter를 초기화 시켜준 뒤, 다음 상태인 S_DATA로 넘어간다.
  • 하지만, 100ms까지 기다려 봤음에도 Negative edge가 발생하지 않는다면 'DHT11과 통신하는 과정에서 예기치 못한 문제가 발생한 상태이다." 라고 판단하여 usecond counter를 초기화 시켜준 뒤, 첫 단계인 S_IDLE로 넘어 간다.

 

 

 

2.4. 6단계) S_DATA 단계에서 온,습도 데이터 전달에 문자가 발생한 경우

  • S_DATA 단계에서 온,습도 데이터를 40bit 크기의 2진수로 표현된 데이터를 받게 된다.
  • dht11과 basys3 간에 통신이 정상적으로 이루어진다면 40bit 온,습도 데이터를 받게 되지만, 예기치 못한 이유로 데이터를 받는 과정에서 문제가 발생하여 데이터를 못 받을 수 있기 때문에 이에 대한 예외 처리가 필요하다.
  • 이를 위해 negative edge가 발생하면 usecond counter를 활성화 시킨 뒤, 다음 negative edge가 발생할 때까지 Counting하며, 만약 negative edge가 발생한다면 negative edge 간에 counting한 값이 95us 이하일 경우 데이터 0이라고 인식하여, 데이터 0을 padding하며, 95us 보다 클 경우 데이터 1로 판단하여, 데이터 1을 padding한다.
  • 하지만, 100ms 동안 기다려 보았음에도 negative edge가 발생하면 "DHT11측으로부터 온,습도 데이터를 전달 받는 과정에서 문제 발생한 상태이다." 라고 판단하여 usecond counter를 초기화 시켜준 뒤, 첫 단계인 S_IDLE로 넘어 간다.

 

 

 

< 수정 전, 6단계) S_DATA 

// 6단계 : S_READ_DATA
S_READ_DATA : begin
    case (sub_state)
        S_WAIT_PEDGE : begin
            if(dht11_data_pedge) begin
                enable_counter = 1;
                sub_state = S_WAIT_NEDGE;
            end
        end
        S_WAIT_NEDGE : begin
            if(dht11_data_nedge) begin
                if(counter < 45)
                    temp_data = {temp_data[38:0], 1'b0};
                else
                    temp_data = {temp_data[38:0], 1'b1};
                enable_counter = 0;
                sub_state = S_WAIT_PEDGE;
                count_data = count_data + 1;
            end
        end
    endcase

    // 40bit 데이터를 받았는지 여부 확인
    if(count_data >= 40) begin
        // Check Sum과 비교하여 데이터 손실 없음을 확인하면 FND로 출력한다.
        if(temp_data[39:32] + temp_data[31:24] + temp_data[23:16] + temp_data[15:8] == temp_data[7:0]) begin
            humidity = temp_data[39:32];
            temperature = temp_data[23:16];
        end
        // count_data 변수 값을 0으로 초기화
        count_data = 0;
        enable_counter = 0;
        // state, sub-state 초기화
        next_state = S_IDLE;
        sub_state = S_WAIT_PEDGE;
    end
end

 

 

< 수정 후, 6단계) S_DATA 

S_DATA: begin
    counter_enable = 1;
    
    // 100ms 동안 대기 했음에도 Negative edge가 발생하지 않는다면 
    // "dht11측에서 문제가 발생하여 온,습도 데이터를 전송하지 못하는 상태이다."
    // 라고 판단하여 usec counter를 초기화한 후, 첫 단계인 S_IDLE로 이동한다.
    if (usec_counter >= 22'd100_000) begin
        counter_enable = 0;
        next_state = S_IDLE;
        sub_state = S_WAIT_PEDGE;
        n_data = 0;
        temp_data = 0;
    end
    else begin
        case (sub_state)
        	// Negative edge가 발생하면 usec counter를 활성화시키고,
            // 다음 Negative edge에서 usec counter를 counting한 뒤, 초기화한다.
            S_WAIT_PEDGE: 
                if (dht11_data_pedge) sub_state = S_WAIT_NEDGE;
            
            S_WAIT_NEDGE: begin
                if (dht11_data_nedge) begin
                    if (usec_counter < 95) temp_data = {temp_data[38:0], 1'b0};
                    else temp_data = {temp_data[38:0], 1'b1};
                
                	// usec counter를 초기화한 후, sub state를 S_WAIT_PEDGE로 이동
                    // The number of data 을 1씩 증가시킨다.
                    counter_enable = 0;
                    sub_state = S_WAIT_PEDGE;
                    n_data = n_data + 1;
                end
            end
        endcase
    end 
    
    if (n_data >= 40) begin
    	// check sum을 통해 데이터 손실이 없음이 확인되면 FND로 출력한다.
        if (temp_data[39:32] + temp_data[31:24] + temp_data[23:16] + temp_data[15:8] == temp_data[7:0]) begin
            temperature = temp_data[23:16];
            humidity = temp_data[39:32];
        end
        
        n_data = 0;
        counter_enable = 0;
        
        sub_state = S_WAIT_PEDGE;
        next_state = S_IDLE;
    end
end

 

 

 

 

3. 전체 소스 코드

// Top module of Dht11 
module top_module_for_dht11 (
    input clk, reset_p,
    inout dht11_data,
    output [5:0] led_state,
    output [3:0] com,
    output [7:0] seg_7);
    
    // DHT11 Control module
    wire [7:0] temperature, humidity;
    dht11_cntr dht11_cntr_0(.clk(clk), .reset_p(reset_p), .dht11_data(dht11_data),
                            .state_led(led_state), .temperature(temperature), .humidity(humidity));
                            
   // Converting from binary to BCD
   wire [15:0] temperature_bcd, humidity_bcd;
   bin_to_dec bin_to_dec_temperature (.bin(temperature), .bcd(temperature_bcd));
   bin_to_dec bin_to_dec_humidity (.bin(humidity), .bcd(humidity_bcd));
   
   // FND Control module
   fnd_cntr fnd_cntr_0 (.clk(clk), .reset_p(reset_p), .hex_value({temperature_bcd[7:0], humidity_bcd[7:0]}),
                        .com(com), .seg_7(seg_7));
endmodule

// DHT11 Control module
module dht11_cntr(
    input clk, reset_p,
    inout dht11_data,
    output [5:0] state_led,
    output reg [7:0] temperature, humidity);
    
    // Declare state 
    parameter S_IDLE = 6'b00_0001;
    parameter S_LOW_20MS = 6'b00_0010;
    parameter S_HIGH_20US = 6'b00_0100;
    parameter S_LOW_80US = 6'b00_1000;
    parameter S_HIGH_80US = 6'b01_0000;
    parameter S_DATA = 6'b10_0000;
    
    // Declare sub state.
    parameter S_WAIT_PEDGE = 2'b01;
    parameter S_WAIT_NEDGE = 2'b10;
    
    // Declare state, next_state
    reg [5:0] state, next_state;
    reg [1:0] sub_state;
    
    // Get 1usec one cycle pulse
    wire clk_1usec_dht11; 
    clk_div_100 clk_div_1usec(.clk(clk), .reset_p(reset_p), .clk_div_100_nedge(clk_1usec_dht11));
    
    // Declare necessary variables.
    reg [21:0] usec_counter;
    reg counter_enable;
    
    // Declare register of dht11_data wire.
    reg reg_of_dht11_data;
    assign dht11_data = reg_of_dht11_data;
    
    // Get one cycle pulse of negative edge of dht11_data.
    wire dht11_data_nedge, dht11_data_pedge;
    edge_detector edge_detector_dht11_data (.clk(clk), .reset_p(reset_p),
                        .cp(dht11_data), .p_edge(dht11_data_pedge), .n_edge(dht11_data_nedge));
    
    // Declare useconed counter.
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) usec_counter = 0;
        else if(clk_1usec_dht11 && counter_enable) usec_counter = usec_counter + 1;
        else if(!counter_enable) usec_counter = 0;
    end 
    
    // 언제 다음 state로 넘어가는가?
    always @(posedge clk or posedge reset_p) begin
        if(reset_p) state = S_IDLE;         
        else state = next_state;
    end 
    
    // dht11로 받은 데이터를 임시저장하는 레지스터 선언
    // check sum과 비교한 후, 데이터 손실이 없음을 확인하면 그 때, 출력
    reg [39:0] temp_data;
    reg [5:0] n_data;
    
    // 현재 어떤 상태에 있는지 확인하기 위해 LED 출력
    assign state_led = state;
    
    // 각 상태 단계에서의 동작과 다음 상태 단계로 넘어가기 위한 조건을 정의
    always @(negedge clk or posedge reset_p) begin
        if(reset_p) begin
            next_state = S_IDLE;
            sub_state = S_WAIT_PEDGE;
            reg_of_dht11_data = 0;
            temp_data = 40'b0;
            n_data = 0;
            counter_enable = 0;
            temperature = 0;
            humidity = 0;
        end    
        else begin
            case(state)
                // 1단계) S_IDLE (3초 대기)
                S_IDLE : begin
                     if(usec_counter < 22'd3_000_000) begin
                        counter_enable = 1;
                        next_state = S_IDLE;
                        reg_of_dht11_data = 'bz;
                     end 
                     else begin
                        counter_enable = 0;
                        next_state = S_LOW_20MS;
                     end
                end
                
                // 2단계) S_LOW_20MS
                S_LOW_20MS : begin
                    if(usec_counter < 22'd20_000) begin
                        counter_enable = 1;
                        next_state = S_LOW_20MS;
                        reg_of_dht11_data = 0;
                    end
                    else begin
                        counter_enable = 0;
                        next_state = S_HIGH_20US;
                    end 
                end
                
                // 3단계) S_HIGH_20US
                S_HIGH_20US : begin
                    counter_enable = 1;
                    reg_of_dht11_data = 'bz;
                
                    if(usec_counter >= 22'd100_000) begin
                        next_state = S_IDLE;
                        counter_enable = 0;
                    end
                    else if(dht11_data_nedge) begin
                        counter_enable = 0;
                        next_state = S_LOW_80US;
                    end 
                end
                
                // 4단계) S_LOW_80US
                S_LOW_80US : begin
                    counter_enable  = 1;
                    if(usec_counter >= 22'd100_000) begin
                        next_state = S_IDLE;
                        counter_enable  = 0;
                    end
                    else if(dht11_data_pedge) begin
                        next_state = S_HIGH_80US;
                        counter_enable  = 0;
                    end
                end
                
                
                // 5단계) S_HIGH_80US
                S_HIGH_80US : begin
                    counter_enable  = 1;
                    if(usec_counter >= 22'd100_000) begin
                        next_state = S_IDLE;
                        counter_enable  = 0;
                    end
                    else if(dht11_data_nedge) begin
                        next_state = S_DATA;
                        counter_enable  = 0;
                    end
                end
                
                
                // 6단계) S_DATA
                S_DATA : begin
                    counter_enable = 1;
                    
                    if(usec_counter >= 22'd100_000) begin
                        counter_enable  = 0;
                        next_state = S_IDLE;
                        sub_state = S_WAIT_PEDGE;
                        n_data = 0;
                        temp_data = 0;
                    end
                    else begin
                        case(sub_state)
                            S_WAIT_PEDGE : 
                                if(dht11_data_pedge) sub_state = S_WAIT_NEDGE;
                        
                            S_WAIT_NEDGE : begin
                                if(dht11_data_nedge) begin
                                    if(usec_counter < 95) temp_data = {temp_data[38:0], 1'b0};
                                    else temp_data = {temp_data[38:0], 1'b1};
                                
                                    counter_enable = 0;
                                    sub_state = S_WAIT_PEDGE;
                                    n_data = n_data + 1;
                                end
                            end
                        endcase
                    end 
                
                   
                       
                    if(n_data >= 40) begin
                         if(temp_data[39:32] + temp_data[31:24] + temp_data[23:16] + temp_data[15:8] == temp_data[7:0]) begin
                             temperature = temp_data[23:16];
                             humidity = temp_data[39:32];
                         end
                        
                         n_data = 0;
                         counter_enable = 0;
                            
                         sub_state = S_WAIT_PEDGE;
                         next_state = S_IDLE;
                   end
                end
            endcase
        end
    end
endmodule

 

 

 

 

 

4. 구현

< Oscilloscope을 통한 dht11_data wire 측정 >

 

 

< 구현 영상 >