频率合成技术是利用频率合成的方法,使某一(或多个)基准频率,通过一定的变换与处理后,形成一系列等间隔的离散频率。
直接数字频率合成器(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
#include
#include
void main()
{
double pi=3.141593;
double step=pi*2/256;
ofstream outfile;
outfile.open("sin.mif");
outfile<<"--Maxplus Memory Initiallization File"<hex<dec<
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
由于时间匆忙,错误是难免的,欢迎大家交流讨论。