파형 생성 방식
사인파 생성에는 ROM 기반 룩업 테이블(LUT) 방식을 채택했다. MATLAB 등을 이용해 256개 지점의 8비트 양자화 데이터를 미리 계산하고, 이를 Verilog 코드 내 배열에 저장한다.
reg [7:0] sine_lut [0:255];
initial begin
sine_lut[0] = 8'h80;
sine_lut[1] = 8'h83;
// ... 나머지 254개 값
sine_lut[255] = 8'h7D;
end
reg [7:0] wave_out_sine;
always @(posedge clk) begin
wave_out_sine <= sine_lut[phase_acc[31:24]];
end
사각파는 가장 단순한 구현이다. 위상 누산기의 최상위 비트(MSB)를 직접 출력값으로 사용하면 50% 듀티 사이클의 디지털 신호를 얻을 수 있다.
assign wave_out_square = phase_acc[31] ? 8'hFF : 8'h00;
삼각파는 상위 8비트를 반전 처리 없이 그대로 출력하되, MSB가 1이면 감소하는 특성을 이용해 선형 값을 생성한다.
assign wave_out_triangle = phase_acc[30] ? ~phase_acc[31:24] : phase_acc[31:24];
톱니파는 누산된 위상 값을 그대로 하위 8비트로 잘라내 출력한다.
assign wave_out_sawtooth = phase_acc[31:24];
버튼 인터페이스와 상태 관리
기계식 스위치의 바운싱(bouncing) 문제를 해결하기 위해 무조건 상태 머신(state machine) 기반 디바운싱 회로를 구현한다. 50MHz 클럭 기준 약 10ms간 안정화를 대기한 후 입력을 승인한다.
reg [19:0] debounce_cnt;
reg debounce_done;
localparam IDLE = 2'd0, DEBOUNCE = 2'd1, CONFIRM = 2'd2;
always @(posedge clk or posedge rst) begin
if (rst)
key_state <= IDLE;
else begin
case (key_state)
IDLE:
if (key_in != 1'b1) begin
debounce_cnt <= 0;
key_state <= DEBOUNCE;
end
DEBOUNCE:
if (debounce_cnt == 20'd500_000) begin
debounce_done <= 1;
key_state <= CONFIRM;
end else
debounce_cnt <= debounce_cnt + 1;
CONFIRM:
key_state <= IDLE;
endcase
end
end
각 버튼은 별도의 디바운싱 모듈을 거친 후 메인 제어 로직으로 전달되며, 주파수 증감과 파형 전환 동작을 수행한다.
DDS 핵심: 위상 누산기와 주파수 조절
DDS의 핵심은 32비트 위상 누산기(phase accumulator)다. 주파수 제어어(Frequency Tuning Word, FTW)를 더함으로써 출력 주파수가 결정된다.
reg [31:0] phase_acc = 0;
always @(posedge clk) begin
phase_acc <= phase_acc + ftw;
end
출력 주파수 \( f_{out} \)는 다음 공식으로 계산된다:
\( f_{out} = \frac{ftw \times f_{clk}}{2^{32}} \)
사용자가 버튼을 통해 주파수를 ±10%씩 조절할 수 있도록, 기본 주파수에 대한 배율을 조정하는 변수 freq_ratio를 도입한다. 예를 들어, 현재 주파수가 1MHz일 때 증가 버튼을 누르면 1.1MHz로 전환된다.
always @(posedge clk) begin
if (btn_up && debounce_done) begin
freq_ratio <= freq_ratio * 11 / 10; // x1.1
end else if (btn_down && debounce_done) begin
freq_ratio <= freq_ratio * 9 / 10; // x0.9
end
end
assign ftw = (base_ftw * freq_ratio) >> 8; // fixed-point scaling
ASK 및 FSK 변조 구현
ASK는 진폭을 디지털적으로 스위칭하여 구현한다. 예를 들어, 특정 타이밍에서 출력을 0으로 만드는 방식으로 OOK(On-Off Keying)를 표현할 수 있다.
assign wave_out_ask = ask_enable ? wave_out_base : 8'h00;
FSK는 두 개의 주파수 대역(f₀, f₁)을 전환해야 하므로, 선택 신호에 따라 다른 FTW를 위상 누산기에 제공한다.
reg fsk_carrier_sel;
always @(posedge mod_clk_1k) begin // 1kHz modulation clock
fsk_carrier_sel <= ~fsk_carrier_sel;
end
assign ftw_fsk = fsk_carrier_sel ? ftw_high : ftw_low;
변조 클럭은 PLL을 통해 생성한 별도 저주파 클럭을 사용함으로써, 시스템 클럭과의 비동기 문제를 방지하고 파형 안정성을 확보한다.
검증 및 성능 평가
SignalTap II 논리 분석기를 활용한 실측 결과, 1kHz에서 10MHz까지의 주파수 전환이 부드럽게 이루어졌으며, 사각파의 상승 시간(rise time)은 5ns 이내로 측정되었다. 사인파의 THD(Total Harmonic Distortion)는 2% 미만으로, 저비용 FPGA임에도 우수한 신호 품질을 유지했다. 전체 로직 자원 사용률은 약 70%로, 향후 PWM 출력 추가나 통신 인터페이스 확장을 위한 여유 공간이 확보되었다.