FPGA의 FND와 BUTTON을 이용하여 스탑워치를 만들어보겠습니다. 만들기전에 FSM을 제작하여 로직에 대하여 확고히 해야 verilog 코딩하기 편해집니다.
클럭이 0.005초마다 토글이된다 (클럭이 0.01초마다 발생)

1) 스탑워치 버튼을 만듭니다 (1) runStop Button, (2) clear Button (3)reset Button
2) (1)과 (2) 와(3)을 위의 FSM reg를 만들어줍니다.
3) FND를 계속해서 켜주는 ClockDivider 1개와 FND를 밀리초부터 초까지 변경시켜주는 ClockDiver 1개 총 2개를 사용합니다. 같은 클럭을 주게되면 우리 눈에 보이는 숫자는 바뀌지 않는것으로 보이기때문에 크기가 다른 클럭을 줍니다.
제가 설계한 경우에는 FND에 4개를 번갈아 가는 출력하는것을 좀더 낮은 Hz를 설정하고 시간이 움직이는 Hz를 좀 더 높게 주었습니다.
4) 시간을 변경해주는 counter의 경우에는 1의자리, 10의자리, 100의자리, 1000의자리를 설정해주는 reg를 하나 만들어줍니다.
5) fnd 4개를 번갈아가면서 을 출력하는 counter의 경우에는 decoder 2x4에 넣어줍니다.'
6) fnd에 나타내가 되는 시간의 경우에는 decoder 3x8에 제공하게됩니다.
위의과정을 다 연결하고 RTL Schematic으로 회로 합성을하게 되면 다음과 같습니다.

module stopwatch_button
module stopwatch_button(
input in_clk, in_button,
output out_button
);
parameter PUSHED = 1'b1;
parameter RELEASED = 1'b0;
parameter TRUE = 1'b1;
parameter FALSE = 1'b0;
parameter DEBOUNCE_LIMIT = 500_000;
reg reg_returnValue = FALSE;
reg reg_preState = RELEASED;
reg [31:0] reg_count = 0;
assign out_button = reg_returnValue;
always@(posedge in_clk) begin
if ( (in_button == PUSHED) && (reg_preState == RELEASED) && (reg_count < DEBOUNCE_LIMIT) ) begin
reg_count <= reg_count +1;
reg_returnValue <= FALSE;
end
else if ( (in_button==PUSHED) && (reg_preState == RELEASED) && (reg_count == DEBOUNCE_LIMIT) ) begin
reg_count <= 0;
reg_preState <= PUSHED;
reg_returnValue <= TRUE;
end
else if( (in_button==RELEASED) && (reg_preState == PUSHED) && (reg_count < DEBOUNCE_LIMIT) ) begin
reg_count <= reg_count +1;
reg_returnValue <= FALSE;
end
else if( (in_button==RELEASED) && (reg_preState == PUSHED) && (reg_count == DEBOUNCE_LIMIT) ) begin
reg_count <= 0;
reg_preState <= RELEASED;
reg_returnValue <= FALSE;
end
else begin
reg_count<=0;
reg_returnValue<=FALSE;
end
end
endmodulemodule stopwatch_fsm
module stopwatch_fsm
( input in_clk, in_reset,
input in_run_stop_button, in_clear_button,
output out_run_stop, out_reset
);
parameter RUN = 2'b00;
parameter STOP = 2'b01;
parameter RESET = 2'b10;
reg reg_run_stop, reg_reset;
reg [1:0] state = STOP, next_state;
assign out_run_stop = reg_run_stop;
assign out_reset = reg_reset;
always@ (posedge in_clk or posedge in_reset) begin
if(in_reset)begin
state <= STOP;
end
else begin
state <= next_state;
end
end
always @ (*) begin
next_state <= 2'bxx;
case(state)
RUN: if (in_run_stop_button) next_state <= STOP;
else if (in_clear_button) next_state <= RUN;
STOP : if(in_run_stop_button) next_state <= RUN;
else if (in_clear_button) next_state <= RESET;
else next_state <= STOP;
RESET : next_state <= STOP;
endcase
end
always@(*) begin
reg_run_stop = 1'bx;
reg_reset = 1'bx;
case (state)
STOP :begin
reg_run_stop <= 1'b0;
reg_reset <= 1'b0;
end
RUN : reg_run_stop <= 1'b1;
RESET : reg_reset <= 1'b1;
endcase
end
endmoduleFSM을 만드는 과정을 이용하였습니다.
reg_run_stop, reg_reset의 경우에는 0과 1이 둘다올수있는데, state가 STOP, RUN, RESET일때의 상태를 나타내어 주는 코드입니다.
module clk_1khz
module clk_1khz(in_clk, in_reset, out_clk);
input in_clk, in_reset;
output out_clk;
reg out_clk = 0;
reg [31:0] count = 0;
always@(posedge in_clk or posedge in_reset) begin
if(in_reset) begin
out_clk <= 0;
count <= 0;
end
else begin
if(count == 50_000-1)begin
out_clk <= ~out_clk;
count<=0;
end
else begin
count <= count +1;
end
end
end
endmodule
클럭의 주파수는 100 MHz이므로, 1초 동안 클럭 신호는 100,000,000 번 발생합니다. MAX_COUNT가 50000이므로, 50000번의 클럭 신호 발생 후에 카운터가 리셋됩니다.
따라서, 50000번의 클럭 신호 발생에 걸리는 시간은 50000 / 100000000 = 0.0005초입니다.
따라서, MAX_COUNT가 50000일 때는 0.0005초가 소요됩니다.
module clk_1Mhz(in_clk, in_reset, out_clk);
input in_clk, in_reset;
output out_clk;
reg out_clk = 0;
reg [31:0] count = 0;
always@(posedge in_clk or posedge in_reset) begin
if(in_reset) begin
out_clk <= 0;
count <= 0;
end
else begin
if(count == 500_000-1)begin
out_clk <= ~out_clk;
count<=0;
end
else begin
count <= count +1;
end
end
end
endmodule1MHz라 이름을 명명하였지만 중간에 prescale을 수정하였습니다.
클럭의 주파수는 100 MHz이므로, 1초 동안 클럭 신호는 100,000,000 번 발생합니다. MAX_COUNT가 500000이므로, 500000번의 클럭 신호 발생 후에 카운터가 리셋됩니다.
따라서, 500000번의 클럭 신호 발생에 걸리는 시간은 500000 / 100000000 = 0.005초입니다.
따라서, MAX_COUNT가 500000일 때는 0.005초가 소요됩니다.
module_counter_10k
module counter_10k(
input in_clk, in_reset, in_run_stop, in_clear,
output [13:0] out_count_value
);
reg [13:0] out_count_value = 0;
always @(posedge in_clk or posedge in_reset or posedge in_clear) begin
if (in_reset || in_clear) begin
out_count_value <= 0;
end
else begin
if (out_count_value == 10000 - 1) begin
out_count_value <= 0;
end
else begin
if (in_run_stop) begin
out_count_value <= out_count_value + 1;
end
end
end
end
endmodule9999까지 나타내기위한 코드입니다.
module digit_divider
module digit_divider(
input [13:0] in_counter,
output [3:0] out_digit_1, out_digit_10, out_digit_100, out_digit_1000
);
assign out_digit_1 = in_counter % 10;
assign out_digit_10 = in_counter / 10 % 10;
assign out_digit_100 = in_counter / 100 % 10;
assign out_digit_1000 = in_counter / 1000 % 6;
endmodulemodule mux_4x1
module mux_4x1(in_sel,in_a, in_b, in_c, in_d,out_y);
input [1:0] in_sel;
input [3:0] in_a, in_b, in_c, in_d;
output [3:0] out_y;
reg [3:0] reg_y;
assign out_y = reg_y;
always @(in_sel) begin
reg_y = 0;
case (in_sel)
2'd0 : reg_y = in_a;
2'd1 : reg_y = in_b;
2'd2 : reg_y = in_c;
2'd3 : reg_y = in_d;
endcase
end
endmodule
module fnd_decoder
module fnd_decoder(in_data,out_fndFont);
input [3:0]in_data;
output [7:0] out_fndFont;
reg[7:0] out_fndFont;
always@(*)begin
//out_fndFont = 8'hff;
case (in_data)
default : out_fndFont = 8'hc0;//
1 : out_fndFont = 8'hf9;
2 : out_fndFont = 8'ha4;
3 : out_fndFont = 8'hb0;
4 : out_fndFont = 8'h99;
5 : out_fndFont = 8'h92;
6 : out_fndFont = 8'h82;
7 : out_fndFont = 8'hf8;
8 : out_fndFont = 8'h80;
9 : out_fndFont = 8'h90;
endcase
end
endmodule
module counter
module counter(in_clk, in_reset, out_value);
input in_clk, in_reset;
output [3:0] out_value;
reg[3:0] out_value =0;
always@(posedge in_clk or posedge in_reset) begin
if(in_reset) begin
out_value <=0;
end
else if (in_clk) begin
out_value <= out_value+1;
if(out_value == 9)
out_value<= 0;
end
end
endmodule각 자리를 9까지 나타내기 위한 코드입니다.
module dec_2x4
module dec_2x4(in_sel, out_sel);
input [1:0] in_sel;
output [3:0] out_sel;
reg[3:0] out_sel;
always@(*) begin
case(in_sel)
2'd0: out_sel = 4'b1110;
2'd1: out_sel = 4'b1101;
2'd2: out_sel = 4'b1011;
2'd3: out_sel = 4'b0111;
endcase
end
endmodule
module top_stopwatch(
input in_clk, in_reset,
input in_run_stop_button, in_clear_button,
output [7:0] out_fndData,
output [3:0] out_fndSelect
);
//-------------------button part
clk_1Mhz inst_100MHz(.in_clk(in_clk), .in_reset(in_reset), .out_clk(w_10khz));
wire w_run_stop_button;
stopwatch_button inst_stopwatch_runStop_button(
.in_clk(in_clk), .in_button(in_run_stop_button),
.out_button(w_run_stop_button)
);
wire w_reset_button;
stopwatch_button inst_stopwatch_reset_button(
.in_clk(in_clk), .in_button(in_clear_button),
.out_button(w_reset_button)
);
wire w_run_stop, w_reset;
stopwatch_fsm inst_stopwatch_fsm
(
.in_clk(in_clk), .in_reset(in_reset),
.in_run_stop_button(w_run_stop_button), .in_clear_button(w_reset_button),
.out_run_stop(w_run_stop), .out_reset(w_reset)
);
wire [3:0] w_count_data;
wire [13:0] w_count_10k;
counter_10k inst_counter_10k(
.in_clk(w_10khz), .in_reset(in_reset), .in_run_stop(w_run_stop), .in_clear(w_reset),
.out_count_value(w_count_10k)
);
wire [3:0] w_d1,w_d10,w_d100,w_d1000;
digit_divider inst_digit_divider(
.in_counter(w_count_10k),
.out_digit_1(w_d1), .out_digit_10(w_d10), .out_digit_100(w_d100), .out_digit_1000(w_d1000)
);
mux_4x1 inst_mux_4x1(.in_sel(w_count), .in_a(w_d1), .in_b(w_d10), .in_c(w_d100), .in_d(w_d1000),.out_y(w_count_data));
fnd_decoder inst_fnd_decoder(.in_data(w_count_data), .out_fndFont(out_fndData) );
//-----------------clock, decoder part
wire w_1khz;
wire [1:0] w_count;
wire w_count_2bit;
clk_1khz inst_clk_1khz(.in_clk(in_clk), .in_reset(in_reset), .out_clk(w_1khz));
counter inst_counter(.in_clk(w_1khz),
.in_reset(in_reset),
.out_value(w_count)
);
dec_2x4 inst_dec2x4(.in_sel(w_count), .out_sel(out_fndSelect));
//----------------------------
endmodule
다음내용은 다음에
'나의 전자 공부방 > FPGA' 카테고리의 다른 글
| vivado, FPGA로 LED right hift, LED left shift하기 (0) | 2023.05.15 |
|---|---|
| vivado, FPGA를 이용해서 시계(TimeClock)만들기 (0) | 2023.05.10 |
| Vivado, FPGA로 upcounter 만들기 (0) | 2023.05.09 |
| vivado의 create block design을 사용해서 apb 만들기 (0) | 2023.04.19 |