频率合成技术是利用频率合成的方法,使某一(或多个)基准频率,通过一定的变换与处理后,形成一系列等间隔的离散频率。
直接数字频率合成器(Direct Digital Frequency Synthesize)技术是一种基于全数字技术,从相位概念出发直接合成所需波形的一种频率合成技术。其原理图如下:
如图所示,用VHDL编程的话,至少需要建立一个加法器、一个锁存器以及一个ROM存储器;加法器用来累加相位或者地址信号,锁存器用来所存输出信号以及反馈,ROM存储器则用来存储波形数据的数字幅度;最后还需要一个总得模块将三者结合在一起。
首先:建立ROM表;
在quartus II上面使用LPM_ROM,就必须学会MegaWizard Plug-in Manager的用法,要用MegaWizard Plug-in Manager,那么就必须先学会创建mif或者hex文件,下面具体以正弦波为例,介绍mif文件的创建方法以及如何调用LPM_ROM。
1、创建mif文件的三种方法(其实不只三种,下面就我调试成功的来一一说明,并且附上源代码吧):
根据需要设置每个字的位宽WIDTH和总字数DEPTH。然后设置地址和数据的进制基数ADDRESS_RADIX、DATA_RADIX,使用无符号数UNS。然后用如下方法生成需要的数据(按上边的格式,注意中间“:”,最后“;”),往CONTENT BEGIN和END中间一贴就行了。
1)用VC++软件编程实现:
#include<iostream.h> #include<fstream.h> #include<math.h> void main() { double pi=3.141593; double step=pi*2/256; ofstream outfile; outfile.open("sin.mif"); outfile<<"--Maxplus Memory Initiallization File"<<endl; outfile<<"--sin.mif"<<endl; outfile<<"WIDTH=8;"<<endl; outfile<<"DEPTH=256;"<<endl; outfile<<"ADDRESS_RADIX=HEX;"<<endl; outfile<<"DATA_RADIX=DEC;"<<endl<<endl; outfile<<"CONTENT BEGIN"<<endl; for(int i=0;i<256;i++) { outfile<<hex<<i<<" : "<<dec<<int((sin(i*step)+1)/2*255+0.5)<<";"<<endl; } outfile<<"END;"; }2)用Matlab编程实现:
创建.m文件
width=8; %数据宽度为10位; depth=2^width; N=0:1:depth-1; s=sin(pi*N/depth); %计算0~pi/2的Sin值; fidc=fopen('sin_matlab.mif','wt'); %以"wt"的形式打开,\n为换行 % 写入 sin_matlab.mif % fprintf(fidc,'width=%d;\n',width); fprintf(fidc,'depth=%d;\n',depth); fprintf(fidc,'address_radix=uns;\n'); fprintf(fidc,'data_radix = uns;\n'); fprintf(fidc,'content begin\n'); for(x=1:depth); fprintf(fidc,'%d:%d;\n',x-1, round( (depth/2-1)*sin(pi*(x-1)/(depth/2)) + depth/2) ); end fprintf(fidc,'end;'); fclose(fidc);3)用软件Guagle_wave.exe自动生成mif或者hex文件
软件下载地址:http://download.csdn.net/detail/csf111/3766264
2、使用tools\MegaWizard Plug-in Manager来新建LPM_ROM,具体方法不讲述,只要quartus II软件当中去了,相应的设置选项都很容易懂的,主要是要设置你的ROM地址宽度和数据点数,其间需要调用mif文件的,选择你刚才建立的mif即可;
3、上面几步完成之后,quartus II 就会自动生成一个VHD文件,如下:
-- megafunction wizard: %ROM: 1-PORT% -- GENERATION: STANDARD -- VERSION: WM1.0 -- MODULE: lpm_rom -- ============================================================ -- File Name: lpm_rom8.vhd -- Megafunction Name(s): -- lpm_rom -- -- Simulation Library Files(s): -- lpm -- ============================================================ -- ************************************************************ -- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! -- -- 8.1 Build 163 10/28/2008 SJ Full Version -- ************************************************************ --Copyright (C) 1991-2008 Altera Corporation --Your use of Altera Corporation's design tools, logic functions --and other software and tools, and its AMPP partner logic --functions, and any output files from any of the foregoing --(including device programming or simulation files), and any --associated documentation or information are expressly subject --to the terms and conditions of the Altera Program License --Subscription Agreement, Altera MegaCore Function License --Agreement, or other applicable license agreement, including, --without limitation, that your use is for the sole purpose of --programming logic devices manufactured by Altera and sold by --Altera or its authorized distributors. Please refer to the --applicable agreement for further details. LIBRARY ieee; USE ieee.std_logic_1164.all; LIBRARY lpm; USE lpm.all; ENTITY lpm_rom8 IS PORT ( address : IN STD_LOGIC_VECTOR (7 DOWNTO 0); inclock : IN STD_LOGIC ; q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) ); END lpm_rom8; ARCHITECTURE SYN OF lpm_rom8 IS SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0); COMPONENT lpm_rom GENERIC ( intended_device_family : STRING; lpm_address_control : STRING; lpm_file : STRING; lpm_outdata : STRING; lpm_type : STRING; lpm_width : NATURAL; lpm_widthad : NATURAL ); PORT ( address : IN STD_LOGIC_VECTOR (7 DOWNTO 0); inclock : IN STD_LOGIC ; q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) ); END COMPONENT; BEGIN q <= sub_wire0(7 DOWNTO 0); lpm_rom_component : lpm_rom GENERIC MAP ( intended_device_family => "FLEX10K", lpm_address_control => "REGISTERED", lpm_file => "sin_soft.mif", lpm_outdata => "UNREGISTERED", lpm_type => "LPM_ROM", lpm_width => 8, lpm_widthad => 7 ) PORT MAP ( address => address, inclock => inclock, q => sub_wire0 ); END SYN; -- ============================================================ -- CNX file retrieval info -- ============================================================ -- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" -- Retrieval info: PRIVATE: AclrAddr NUMERIC "0" -- Retrieval info: PRIVATE: AclrByte NUMERIC "0" -- Retrieval info: PRIVATE: AclrOutput NUMERIC "0" -- Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" -- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" -- Retrieval info: PRIVATE: BlankMemory NUMERIC "0" -- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" -- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" -- Retrieval info: PRIVATE: Clken NUMERIC "0" -- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" -- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" -- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" -- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "FLEX10K" -- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" -- Retrieval info: PRIVATE: JTAG_ID STRING "NONE" -- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" -- Retrieval info: PRIVATE: MIFfilename STRING "sin_soft.mif" -- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "128" -- Retrieval info: PRIVATE: OutputRegistered NUMERIC "0" -- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" -- Retrieval info: PRIVATE: RegAdd NUMERIC "1" -- Retrieval info: PRIVATE: RegAddr NUMERIC "1" -- Retrieval info: PRIVATE: RegOutput NUMERIC "0" -- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" -- Retrieval info: PRIVATE: SingleClock NUMERIC "0" -- Retrieval info: PRIVATE: UseDQRAM NUMERIC "0" -- Retrieval info: PRIVATE: WidthAddr NUMERIC "7" -- Retrieval info: PRIVATE: WidthData NUMERIC "8" -- Retrieval info: PRIVATE: rden NUMERIC "0" -- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "FLEX10K" -- Retrieval info: CONSTANT: LPM_ADDRESS_CONTROL STRING "REGISTERED" -- Retrieval info: CONSTANT: LPM_FILE STRING "sin_soft.mif" -- Retrieval info: CONSTANT: LPM_OUTDATA STRING "UNREGISTERED" -- Retrieval info: CONSTANT: LPM_TYPE STRING "LPM_ROM" -- Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "8" -- Retrieval info: CONSTANT: LPM_WIDTHAD NUMERIC "7" -- Retrieval info: USED_PORT: address 0 0 7 0 INPUT NODEFVAL address[6..0] -- Retrieval info: USED_PORT: inclock 0 0 0 0 INPUT NODEFVAL inclock -- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL q[7..0] -- Retrieval info: CONNECT: @address 0 0 7 0 address 0 0 7 0 -- Retrieval info: CONNECT: q 0 0 8 0 @q 0 0 8 0 -- Retrieval info: CONNECT: @inclock 0 0 0 0 inclock 0 0 0 0 -- Retrieval info: LIBRARY: lpm lpm.lpm_components.all -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8.vhd TRUE -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8.inc FALSE -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8.cmp TRUE -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8.bsf FALSE -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8_inst.vhd FALSE -- Retrieval info: LIB_FILE: lpm
其次,建立锁存器模块;
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY REG8B IS PORT ( Load : IN STD_LOGIC; DIN : IN STD_LOGIC_VECTOR(7 DOWNTO 0); DOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) ); END REG8B; ARCHITECTURE behav OF REG8B IS BEGIN PROCESS(Load, DIN) BEGIN IF Load'EVENT AND Load = '1' THEN -- 时钟到来时,锁存输入数据 DOUT <= DIN; END IF; END PROCESS; END behav;
第三,建立加法器模块;
LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; ENTITY ADDER8B IS PORT ( A : IN STD_LOGIC_VECTOR(7 DOWNTO 0); B : IN STD_LOGIC_VECTOR(7 DOWNTO 0); S : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END ADDER8B; ARCHITECTURE behav OF ADDER8B IS BEGIN S <= A + B; END behav;
第四,顶层模块的设计;
--------------------------------------------------------------------- -- Designed By Michael Chen( chen sifan) --- -- 2011\11\07 --- --------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; --------------------------------------------------------------------- ENTITY mydds IS -- 顶层设计 PORT ( CLK : IN STD_LOGIC; FWORD : IN STD_LOGIC_VECTOR(7 DOWNTO 0); FOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END mydds; --------------------------------------------------------------------- ARCHITECTURE behav OF mydds IS --------------------------------------------------------------------- COMPONENT REG8B --load 'event and load = 1 --dout <= din; PORT ( LOAD : IN STD_LOGIC; DIN : IN STD_LOGIC_VECTOR(7 DOWNTO 0); DOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END COMPONENT; --------------------------------------------------------------------- COMPONENT ADDER8B PORT ( A : IN STD_LOGIC_VECTOR(7 DOWNTO 0); B : IN STD_LOGIC_VECTOR(7 DOWNTO 0); S : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END COMPONENT; --------------------------------------------------------------------- COMPONENT lpm_rom8 PORT ( address : IN STD_LOGIC_VECTOR(7 DOWNTO 0); inclock : IN STD_LOGIC ; q : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END COMPONENT; ----------------------------------------------------------------------- SIGNAL F8B : STD_LOGIC_VECTOR( 7 DOWNTO 0); SIGNAL A8B : STD_LOGIC_VECTOR( 7 DOWNTO 0); SIGNAL B8B : STD_LOGIC_VECTOR( 7 DOWNTO 0); SIGNAL C8B : STD_LOGIC_VECTOR( 7 DOWNTO 0); --------------------------------------------------------------------- BEGIN F8B<=FWORD; U1 : ADDER8B PORT MAP( A=>F8B,B=>B8B, S=>A8B ); U2 : REG8B PORT MAP( DOUT=>B8B,DIN=>A8B, LOAD=>CLK ); U3 : REG8B PORT MAP( DOUT=>C8B,DIN=>B8B, LOAD=>CLK ); U4 : lpm_ROM8 PORT MAP( address=>C8B(7 downto 0), q=>FOUT, inclock=>CLK ); END behav;
仿真结构如下:
设置成模拟显示的方法如下图(Analog WaveForm选项 ):
最后,有兴趣的“玩家”可以将仿真的波形拿到Matlab当中去。具体方法如下:在quartus II中将波形仿真文件保存为tbl格式的文件,然后在Matlab环境下面去建立M文件去将tbl还原成波形图,顺带也把代码贴下面吧:
%mydds.m %Designed By Michael Chen (Chen sifan),2011\11\07 clear all; fid = fopen('D:\Program Files\alter\MyWork\MyDDS.tbl','r');%tbl文件的路径要写对哦 data = fscanf(fid,'%s'); fclose(fid); b = find(data == '='); number = length(b); j = 0; for i = 1 : number-1 j = j+1; c_s(j,1) = data(b(i)+1); c_s(j,2) = data(b(i)+2); end; d_s = hex2dec(c_s);%将16进制的数据转换成十进制的 plot(d_s);
波形图比较丑,是因为我的mif没有做好的缘故。请见谅哈!
Ok了,程序设计步骤大致如上所示,但是这个程序还只是实现了DDS一个基本的功能,想要探究DDS的强大功能的话,还要继续花大量时间去整理的。
在此,我附上我个人的仿真程序下载地址:http://download.csdn.net/detail/csf111/3767213
由于时间匆忙,错误是难免的,欢迎大家交流讨论。