實驗內容
在FPGA上設計一個DDS模塊,在DE0 開發板上運行,在FPGA芯片內部合成出數字波形即可。不用輸出模擬信號,本模塊滿足以下條件:
- 使用板載晶振的50MHz時鐘,合成以下頻率的信號
- 1、500KHz 正弦波信號。 2、1MHz 正弦波信號。 3、3MHz 正弦波信號。
- 頻率字字長32位,波表ROM尺寸爲 10比特地址,1024個word
- 波形格式爲2補碼格式,12比特量化
- 每個CLK輸出一個有效樣點。
- 輸入信號爲頻率字和頻率字輸入使能信號
- 使用板載的撥碼開關(Switch)控制生成的波形信號的不同頻率。
注:波表ROM代碼是用matlab或C打印生成的。不要手寫
實驗要求
- 人工繪製的 電路結構RTL設計圖,該圖片用於說明你設計電路時的想法,注意要在RTL圖中畫出Verilog代碼中的 生成D觸發器 reg 變量
- Quartus掃描生成的電路RTL圖,該圖片用於說明Quartus的電路編譯結果
- 相位累加器的輸出,SignalTap截圖
- 波表ROM的輸入地址,SignalTap截圖
- 至少捕獲 一個完整的輸出正弦波形週期的上述數據數值的SignalTap截圖。
- 輸出正弦波的樣值波形,SignalTap截圖
- 提交Verilog、相關MATLAB 代碼,請使用博客中提供的代碼塊功能
- 分析輸出的正弦波信號的頻譜,Matlab 截圖
手工繪製RTL圖
Quartus掃描生成的RTL
SignalTap截圖
MATLAB頻譜分析截圖
Verilog代碼
module switch_freq_word(
CLK , //時鐘
SW , //選擇頻率
FQWD , //輸出頻率字,作爲下一級計數器的步進值
EN ); //輸出頻率字的更新使能,高電平有效
input CLK,EN;
input [2:0] SW;
output reg[31:0] FQWD;
always @(posedge CLK) begin
if (EN) begin
case(SW)
3'b001: FQWD <= 10;//500kHz
3'b010: FQWD <= 20;//1MHz
3'b100: FQWD <= 60;//3MHz
default: FQWD <= 10;
endcase
end
else begin
FQWD <= FQWD ;
end
end
endmodule
////////////////////////////////////////////////////
module dds_core(
CLK , // 時鐘
IN , // 步進值
SINOUT); // 地址
input CLK;
input [31:0] IN;//頻率字字長32位
output reg[9:0] SINOUT;
always @ (posedge CLK) begin
SINOUT <= IN + SINOUT;
end
endmodule
module DDS_CORE_ROM(
CLK , // clock
RA , // read address
RD ); // read data
input CLK;
input [9 :0] RA;
output [11 :0] RD;
reg [11 :0] RD;
always @ (posedge CLK)
case(RA)
10'd 0 :RD = #1 12'b 000000000000; // 0 0x0
10'd 1 :RD = #1 12'b 000000001100; // 12 0xC
10'd 2 :RD = #1 12'b 000000011001; // 25 0x19
10'd 3 :RD = #1 12'b 000000100101; // 37 0x25
...
10'd 1023 :RD = #1 12'b 111111110100; // -12 0xFF4
default : RD = #1 0;
endcase
endmodule
MATLAB代碼
san;
data=san(:,5);%取數據中的第五列
signal=transpose(data); %矩陣轉置
fs=50E6; %採樣頻率
N=1024; %採樣點數
t=[0:1/fs:(N-1)/fs]; %採樣時刻
figure(1);plot(signal);
xlabel('Time (s)');
ylabel('Magnitude');
Y = fft(signal,N); %做FFT變換
Ayy = abs(Y); %取模
Ayy=Ayy/(N/2); %換算成實際的幅度
Ayy(1)=Ayy(1)/2;
F=([1:N]-1)*fs/N; %換算成實際的頻率值,Fn=(n-1)*Fs/N
figure(2);
stem(F(1:N/2),Ayy(1:N/2)); %顯示換算後的FFT模值結果
axis([0 5E6 0 2500]);
title('幅度-頻率曲線圖');
xlabel('Frequency (Hz)');
ylabel('Magnitude');
生成波表ROM的MATLAB代碼
#include<stdio.h>
#include<math.h>
#define PI 3.141593
#define DEPTH 1024 /* 數據深度,即存儲單元的個數 */
#define WIDTH 12 /* 存儲單元的寬度 */
int main(void)
{
int n,temp;
float v;
FILE * fp;
/* 建立文件名爲sine1024.mif新文件,允許寫入數據,
文件名隨意,但擴展名必須爲.mif */
fp = fopen("sine1024.mif","w+");
if(NULL==fp)
printf("Can not creat file!\r\n");
else
{
printf("File created successfully!\n");
/* 生成文件頭,注意不要忘了";" */
fprintf(fp,"DEPTH=%d;\n",DEPTH);
fprintf(fp,"WIDTH=%d;\n",WIDTH);
fprintf(fp,"ADDRESS_RADIX = HEX;\n");
fprintf(fp,"DATA_RADIX = HEX;\n");
fprintf(fp,"CONTENT\n");
fprintf(fp,"BEGIN\n");
/* 以十六進制輸出地址和數據 */
for(n=0;n<DEPTH;n++)
{
/* 週期爲1024個點的正弦波 */
v=sin(2*PI*n/DEPTH);
/* 將-1~1之間的正弦波的值擴展到0~4095之間 */
temp=(int)((v+1)*4095/2); //v+1將數值平移到0~2之間
/* 以十六進制輸出地址和數據 */
fprintf(fp,"%x\t:\t%x;\n",n,temp);
}
fprintf(fp,"END;\n");
fclose(fp); //關閉文件
}
}