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 | 31 |
Tags
- gpio
- LED
- FND
- soc 설계
- DHT11
- Linked List
- verilog
- dataflow modeling
- pwm
- Pspice
- KEYPAD
- ring counter
- hc-sr04
- i2c 통신
- java
- atmega 128a
- half adder
- Edge Detector
- behavioral modeling
- uart 통신
- Algorithm
- structural modeling
- ATMEGA128A
- prescaling
- D Flip Flop
- Recursion
- BASYS3
- vivado
- test bench
- stop watch
Archives
- Today
- Total
거북이처럼 천천히
Verilog RTL 설계(7월 18일 - 2, Stop Watch - 1) 본문
1. Stop Watch
- 이전 게시글에서 다루었던 Clock 지식을 기반으로 Stop Watch을 구현해보도록 하겠다.
- 단계별로 기능을 하나씩 추가해 나아가도록 하겠다.
2. Basic Stop Watch
- 기본적인 Stop Watch는 다음과 같이 동작한다.
- 초기에는 00 : 00초로 시작하며, 시작 버튼을 누르기 전까지는 시계는 동작하지 않는다.
- btn[0], btn_start을 누르면 시계가 동작하며, 다시 btn_start을 누르면 다시 시계가 멈춘다.
2.1. Stop watch에서 시계를 어떻게 멈추게 할 것인가?
- Basys3의 기본 클럭 펄스를 기반으로 분주화를 통해 1sec / 1min을 주기로 갖는 One Cycle Pulse를 얻는다.
- 이 과정에서 기본 클럭 펄스 대신 0을 주게된다면 항상 Low Level이기 때문에 분주 모듈내에 Counter는 동작하지 않을 것이며, 이로 인해 시계는 더 이상 분과 초 값을 바꾸지 못해 시계가 멈추게 된다.
- 그러고 다시 0값 대신 기본 클럭 펄스를 주게 되면 분주 모듈내에 Counter가 클럭 펄스에 따라 Counting을 시작하며, 분과 초 값이 바뀌면서 시계가 움직이게 된다.
2.2. 기본 Clock 모듈을 기반으로 설계하겠다.
- 기본적인 시계 기능을 수행하는 모듈을 베이스로 할 것이기 때문에 기계 기능을 수행하는 모듈에 관한 게시글을 한 번 읽고, 오는 것을 추천한다.
https://jbhdeve.tistory.com/264
2.3. 기본 Clock 모듈과 비교하였을 때, 다른 소스 코드를 중심으로 설명하겠다.
< Source, Get One Cycle Pulse of btn_start >
// Control Stop Watch
wire btn_start;
button_cntr control_btn_set (.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_nedge(btn_start));
- chattering 현상을 해결하기 위해 D Flip-Flop를 이용하여 delay time을 갖고, button 값을 읽도록 하겠다.
- btn[0] : Watch 모드와 Stop 모드를 컨트롤하는 버튼
- btn_start : start 버튼의 One Cycle Pulse
- One Cycle Pulse를 통해 해당 버튼이 눌려졌는지 여부를 확인할 수 있다.
< Source, Control Start / Stop mode >
// Control mode.
wire start_stop;
t_flip_flop t_flip_flop_0 (.clk(clk), .reset_p(reset_p), .t(btn_start), .q(start_stop));
- start_stop : 현재 스톱 워치가 start 상태인지, stop 상태인지를 나타내는 변수
- start_stop이 1인 경우 : start mode
- start_stop이 0인 경우 : stop mode - btn[0]이 눌러 btn_start가 활성화되면 T Flip-Flop을 통해 현재 모드를 Toggle시키게 된다.
< Source, Control Clock Pulse >
// Control clk.
wire clk_start;
assign clk_start = (start_stop)? clk : 0;
- MUX를 통해 현재 모드에 따라 분주 모듈의 argument 값으로 clk 값을 줄지, 0을 줄지를 결정한다.
- clk 값을 주게 되면 분주 모듈내에 있는 Counter가 정상적으로 clk에 따라 Counting을 할 수 있지만,
0을 주게 되면 항상 비활성화 상태이기 때문에 Counter는 정상적으로 Counting 할 수 없다.
< Source, Prescale >
// Get One Cycle Pulse of Second , Minute
wire clk_usec, clk_sec, clk_min;
clk_div_100 clk_div_usec (.clk(clk_start), .reset_p(reset_p), .clk_div_100(clk_usec));
clk_div_n clk_div_sec(.clk(clk), .reset_p(reset_p), .clk_source(clk_usec), .prescale(1000000), .clk_div_n_nedge(clk_sec));
clk_div_n clk_div_min(.clk(clk), .reset_p(reset_p), .clk_source(clk_sec), .prescale(60), .clk_div_n_nedge(clk_min));
- 이처럼 항상 clk 값을 주는 것이 아닌 모드에 따라 0 값과 clk 값을 선택하여 줌으로서 모드에 따라 시계를 멈출 수 있다.
< Source, 현재까지의 소스 코드 >
module Stop_Watch(
input clk, reset_p,
input [2:0] btn,
output [3:0] com,
output [7:0] seg_7 );
// Control Stop Watch
wire btn_start;
button_cntr control_btn_set (.clk(clk), .reset_p(reset_p), .btn(btn[0]), .btn_nedge(btn_start));
// Control mode.
wire start_stop;
t_flip_flop t_flip_flop_0 (.clk(clk), .reset_p(reset_p), .t(btn_start), .q(start_stop));
// Control clk.
wire clk_start;
assign clk_start = (start_stop)? clk : 0;
// Get One Cycle Pulse of Second , Minute
wire clk_usec, clk_sec, clk_min;
clk_div_100 clk_div_usec (.clk(clk_start), .reset_p(reset_p), .clk_div_100(clk_usec));
clk_div_n clk_div_sec(.clk(clk), .reset_p(reset_p), .clk_source(clk_usec), .prescale(1000000), .clk_div_n_nedge(clk_sec));
clk_div_n clk_div_min(.clk(clk), .reset_p(reset_p), .clk_source(clk_sec), .prescale(60), .clk_div_n_nedge(clk_min));
// BCD 60 Counter
wire [3:0] min10, min1, sec10, sec1;
counter_bcd_60 counter_sec(.clk(clk), .reset_p(reset_p), .clk_time(clk_sec), .bcd1(sec1), .bcd10(sec10));
counter_bcd_60 counter_min(.clk(clk), .reset_p(reset_p), .clk_time(clk_min), .bcd1(min1), .bcd10(min10));
// Combine data.
wire [15:0] hex_value;
assign hex_value = {min10, min1, sec10, sec1};
fnd_cntr fnd(.clk(clk), .reset_p(reset_p), .value(hex_value), .com(com), .seg_7(seg_7));
endmodule
// T Flip Flop
module t_flip_flop (
input clk, reset_p,
input t,
output reg q );
always @(posedge clk or posedge reset_p) begin
if(reset_p) q = 0;
else q = (t)? ~q : q;
end
endmodule
// Control Button.
module button_cntr (
input clk, reset_p,
input btn,
output btn_pedge, btn_nedge);
// Get 1ms One Cycle Pulse
reg [16:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else begin
if(counter >= 99999) counter = 0;
else counter = counter + 1;
end
end
wire clk_1ms, clk_1ms_nedge;
assign clk_1ms = (counter < 50000) ? 0 : 1;
edge_detector_n edge_dector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_1ms), .n_edge(clk_1ms_nedge));
// D Flip-Flop을 이용한 button 값 읽기
reg debounced_btn;
always @(posedge clk or posedge reset_p) begin
if(reset_p) debounced_btn = 0;
else if(clk_1ms_nedge) debounced_btn = btn;
end
edge_detector_n edge_dector_1 (.clk(clk), .reset_p(reset_p), .cp(debounced_btn), .n_edge(btn_nedge), .p_edge(btn_pedge));
endmodule
// BCD 60 Counter.
module counter_bcd_60(
input clk, reset_p,
input clk_time,
output reg [3:0] bcd1, bcd10 );
// Get One Cycle of clk_time
wire clk_time_nedge;
edge_detector_n edge_dector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_time), .n_edge(clk_time_nedge));
// Counter
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin
bcd1 = 0;
bcd10 = 0;
end
else if(clk_time_nedge) begin
if(bcd1 >= 9) begin
bcd1 = 0;
if(bcd10 >= 5) bcd10 = 0;
else bcd10 = bcd10 +1;
end else bcd1 = bcd1 + 1;
end
end
endmodule
// Prescaler n
module clk_div_n (
input clk, reset_p,
input clk_source,
input [31:0] prescale,
output clk_div_n, clk_div_n_nedge );
// Get one cycle pulse of clk_source
wire clk_source_nedge;
edge_detector_n edge_detector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_source), .n_edge(clk_source_nedge));
// Counting
integer counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else if(clk_source_nedge) begin
if(counter >= prescale-1) counter = 0;
else counter = counter + 1;
end
end
// Get clk_div_n wave, One cycle pulse of clk_div_n.
assign clk_div_n = (counter < prescale / 2)? 0 : 1;
edge_detector_n edge_detector_1 (.clk(clk), .reset_p(reset_p), .cp(clk_div_n), .n_edge(clk_div_n_nedge));
endmodule
// Prescaler 100.
module clk_div_100 (
input clk, reset_p,
input clk_div_100,
input clk_div_100_nedge );
reg [6:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else begin
if(counter >= 99) counter = 0;
else counter = counter + 1;
end
end
assign clk_div_100 = (counter < 50)? 0 : 1;
edge_detector_n edge_dector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_div_100), .n_edge(clk_div_100_nedge));
endmodule
// Control FND
module fnd_cntr (
input clk, reset_p,
input [15:0] value,
output reg [3:0] com,
output [7:0] seg_7 );
// prescaler 100000
reg[16:0] counter;
always @(posedge clk or posedge reset_p) begin
if(reset_p) counter = 0;
else begin
if(counter >= 99999) counter = 0;
else counter = counter + 1;
end
end
wire clk_1ms, clk_1ms_nedge;
assign clk_1ms = (counter < 50000)? 0 : 1;
edge_detector_n edge_dector_0 (.clk(clk), .reset_p(reset_p), .cp(clk_1ms), .n_edge(clk_1ms_nedge));
// Shifting com.
always @(posedge clk or posedge reset_p) begin
if(reset_p) com = 4'b1110;
else if(clk_1ms_nedge) begin
if(com == 4'b0111) com = 4'b1110;
else com = {com[2:0], 1'b1};
end
end
// Get FND data.
reg [3:0] hex_value;
always @(com) begin
case(com)
4'b1110 : hex_value = value[3:0];
4'b1101 : hex_value = value[7:4];
4'b1011 : hex_value = value[11:8];
4'b0111 : hex_value = value[15:12];
default : hex_value = hex_value;
endcase
end
decoder_7seg fnd(.hex_value(hex_value), .seg_7(seg_7));
endmodule
// Decoder of 7-Segment.
module decoder_7seg (
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
// Edge detector
module edge_detector_n (
input clk, reset_p,
input cp,
output n_edge, p_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 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
2.4. 구현 영상
'RTL Design > Verilog RTL 설계' 카테고리의 다른 글
Verilog RTL 설계(7월 18일 - 4, Stop Watch - 3) (0) | 2024.07.22 |
---|---|
Verilog RTL 설계(7월 18일 - 3, Stop Watch - 2) (0) | 2024.07.21 |
Verilog RTL 설계(7월 18일 - 1, Advanced Clock Mode - 4) (0) | 2024.07.21 |
Verilog RTL 설계(7월 17일 - 7, Advanced Clock Mode) (0) | 2024.07.21 |
Verilog RTL 설계(7월 17일 - 6, Advanced Clock Mode - 3) (0) | 2024.07.21 |