Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- BASYS3
- pwm
- half adder
- verilog
- java
- Edge Detector
- FND
- vivado
- i2c 통신
- dataflow modeling
- Pspice
- hc-sr04
- stop watch
- Algorithm
- KEYPAD
- ATMEGA128A
- behavioral modeling
- atmega 128a
- soc 설계
- Linked List
- ring counter
- uart 통신
- test bench
- gpio
- Recursion
- DHT11
- LED
- structural modeling
- D Flip Flop
- prescaling
Archives
- Today
- Total
거북이처럼 천천히
Verilog RTL 설계(7월 23일 - 5, DHT11 구현 (4) ) 본문
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을 발생시키지 못한다.
- 따라서 이에 대한 예외처리가 필요하며, 이를 위한 처리를 다음과 같이 설계하였다.
< 수정 전, 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 측정 >
< 구현 영상 >
'RTL Design > Verilog RTL 설계' 카테고리의 다른 글
Verilog RTL 설계(8월 21일 - 1, I2C 통신 - 1) (0) | 2024.08.22 |
---|---|
Verilog RTL 설계(7월 24일 - 1, HC-SR04 구현 ) (0) | 2024.08.21 |
Verilog RTL 설계(8월 12일 - 2, ADC Converter - 2) (0) | 2024.08.18 |
Verilog RTL 설계(8월 12일 - 1, ADC Converter - 1) (0) | 2024.08.18 |
Verilog RTL 설계(8월 2일 - 3, PWM을 통한 Servo-motor 제어 - 3) (0) | 2024.08.17 |