已回答假定已回答

[征文]+转载 DDS技术之FPGA技术之LPM_ROM生成正弦波

AnanLV2 在 2013-8-22 詢問的問題
最後回覆由zhc7401於2013-9-24提供

在网上看到一篇文章,感觉还不错,给大家分享一下。网址:http://blog.csdn.net/csf111/article/details/6944148

 

频率合成技术是利用频率合成的方法,使某一(或多个)基准频率,通过一定的变换与处理后,形成一系列等间隔的离散频率。

       直接数字频率合成器(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++软件编程实现:

 

  1. #include<iostream.h> 
  2. #include<fstream.h> 
  3. #include<math.h> 
  4. void main() 
  5.     double pi=3.141593; 
  6.     double step=pi*2/256; 
  7.     ofstream outfile; 
  8.     outfile.open("<span style="color:#ff0000;">sin.mif</span>"); 
  9.     outfile<<"--Maxplus Memory Initiallization File"<<endl; 
  10.     outfile<<"--sin.mif"<<endl; 
  11.     outfile<<"WIDTH=8;"<<endl; 
  12.     outfile<<"DEPTH=256;"<<endl; 
  13.     outfile<<"ADDRESS_RADIX=HEX;"<<endl; 
  14.     outfile<<"DATA_RADIX=DEC;"<<endl<<endl; 
  15.     outfile<<"CONTENT BEGIN"<<endl; 
  16.     for(int i=0;i<256;i++) 
  17.     { 
  18.         outfile<<<span style="color:#ff0000;">hex</span><<i<<" : "<<<span style="color:#ff0000;">dec</span><<int((sin(i*step)+1)/2*255+0.5)<<";"<<endl; 
  19.     } 
  20.     outfile<<"END;"
  21. }  

      2)用Matlab编程实现:

      创建.m文件

 

 

[cpp]view plaincopyprint?
  1. width=8;                    %数据宽度为10位; 
  2. depth=2^width; 
  3. N=0:1:depth-1; 
  4. s=sin(pi*N/depth);             %计算0~pi/2的Sin值; 
  5. fidc=fopen('sin_matlab.mif','wt');       %以"wt"的形式打开,\n为换行 
  6. % 写入 sin_matlab.mif % 
  7. fprintf(fidc,'width=%d;\n',width); 
  8. fprintf(fidc,'depth=%d;\n',depth); 
  9. fprintf(fidc,'address_radix=uns;\n');    
  10. fprintf(fidc,'data_radix = uns;\n');     
  11. fprintf(fidc,'content begin\n'); 
  12. for(x=1:depth); 
  13. fprintf(fidc,'%d:%d;\n',x-1, round( (depth/2-1)*sin(pi*(x-1)/(depth/2)) + depth/2) ); 
  14. end 
  15. fprintf(fidc,'end;'); 
  16. fclose(fidc); 

    3)用软件Guagle_wave.exe自动生成mif或者hex文件软件下载地址:http://download.csdn.net/detail/csf111/37662642、使用tools\MegaWizard Plug-in Manager来新建LPM_ROM,具体方法不讲述,只要quartus II软件当中去了,相应的设置选项都很容易懂的,主要是要设置你的ROM地址宽度和数据点数,其间需要调用mif文件的,选择你刚才建立的mif即可;3、上面几步完成之后,quartus II 就会自动生成一个VHD文件,如下:

[cpp]view plaincopyprint?
  1. -- megafunction wizard: %ROM: 1-PORT% 
  2. -- GENERATION: STANDARD 
  3. -- VERSION: WM1.0 
  4. -- MODULE: lpm_rom  
  5.  
  6. -- ============================================================ 
  7. -- File Name: lpm_rom8.vhd 
  8. -- Megafunction Name(s): 
  9. --          lpm_rom 
  10. -- 
  11. -- Simulation Library Files(s): 
  12. --          lpm 
  13. -- ============================================================ 
  14. -- ************************************************************ 
  15. -- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE
  16. -- 
  17. -- 8.1 Build 163 10/28/2008 SJ Full Version 
  18. -- ************************************************************ 
  19.  
  20.  
  21. --Copyright (C) 1991-2008 Altera Corporation 
  22. --Your use of Altera Corporation's design tools, logic functions  
  23. --and other software and tools, and its AMPP partner logic  
  24. --functions, and any output files from any of the foregoing  
  25. --(including device programming or simulation files), and any  
  26. --associated documentation or information are expressly subject  
  27. --to the terms and conditions of the Altera Program License  
  28. --Subscription Agreement, Altera MegaCore Function License  
  29. --Agreement, or other applicable license agreement, including,  
  30. --without limitation, that your use is for the sole purpose of  
  31. --programming logic devices manufactured by Altera and sold by  
  32. --Altera or its authorized distributors.  Please refer to the  
  33. --applicable agreement for further details. 
  34.  
  35.  
  36. LIBRARY ieee; 
  37. USE ieee.std_logic_1164.all; 
  38.  
  39. LIBRARY lpm; 
  40. USE lpm.all; 
  41.  
  42. ENTITY lpm_rom8 IS 
  43.     PORT 
  44.     ( 
  45.         address     : IN STD_LOGIC_VECTOR (7 DOWNTO 0); 
  46.         inclock     : IN STD_LOGIC ; 
  47.         q       : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) 
  48.     ); 
  49. END lpm_rom8; 
  50.  
  51.  
  52. ARCHITECTURE SYN OF lpm_rom8 IS 
  53.  
  54.     SIGNAL sub_wire0    : STD_LOGIC_VECTOR (7 DOWNTO 0); 
  55.  
  56.  
  57.  
  58.     COMPONENT lpm_rom 
  59.     GENERIC ( 
  60.         intended_device_family      : STRING; 
  61.         lpm_address_control     : STRING; 
  62.         lpm_file        : STRING; 
  63.         lpm_outdata     : STRING; 
  64.         lpm_type        : STRING; 
  65.         lpm_width       : NATURAL; 
  66.         lpm_widthad     : NATURAL 
  67.     ); 
  68.     PORT ( 
  69.             address : IN STD_LOGIC_VECTOR (7 DOWNTO 0); 
  70.             inclock : IN STD_LOGIC ; 
  71.             q   : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) 
  72.     ); 
  73.     END COMPONENT; 
  74.  
  75. BEGIN 
  76.     q    <= sub_wire0(7 DOWNTO 0); 
  77.  
  78.     lpm_rom_component : lpm_rom 
  79.     GENERIC MAP ( 
  80.         intended_device_family => "FLEX10K"
  81.         lpm_address_control => "REGISTERED"
  82.         lpm_file => "sin_soft.mif"
  83.         lpm_outdata => "UNREGISTERED"
  84.         lpm_type => "LPM_ROM"
  85.         lpm_width => 8, 
  86.         lpm_widthad => 7 
  87.     ) 
  88.     PORT MAP ( 
  89.         address => address, 
  90.         inclock => inclock, 
  91.         q => sub_wire0 
  92.     ); 
  93.  
  94.  
  95.  
  96. END SYN; 
  97.  
  98. -- ============================================================ 
  99. -- CNX file retrieval info 
  100. -- ============================================================ 
  101. -- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" 
  102. -- Retrieval info: PRIVATE: AclrAddr NUMERIC "0" 
  103. -- Retrieval info: PRIVATE: AclrByte NUMERIC "0" 
  104. -- Retrieval info: PRIVATE: AclrOutput NUMERIC "0" 
  105. -- Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" 
  106. -- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" 
  107. -- Retrieval info: PRIVATE: BlankMemory NUMERIC "0" 
  108. -- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" 
  109. -- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" 
  110. -- Retrieval info: PRIVATE: Clken NUMERIC "0" 
  111. -- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" 
  112. -- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" 
  113. -- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" 
  114. -- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "FLEX10K" 
  115. -- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" 
  116. -- Retrieval info: PRIVATE: JTAG_ID STRING "NONE" 
  117. -- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" 
  118. -- Retrieval info: PRIVATE: MIFfilename STRING "sin_soft.mif" 
  119. -- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "128" 
  120. -- Retrieval info: PRIVATE: OutputRegistered NUMERIC "0" 
  121. -- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" 
  122. -- Retrieval info: PRIVATE: RegAdd NUMERIC "1" 
  123. -- Retrieval info: PRIVATE: RegAddr NUMERIC "1" 
  124. -- Retrieval info: PRIVATE: RegOutput NUMERIC "0" 
  125. -- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" 
  126. -- Retrieval info: PRIVATE: SingleClock NUMERIC "0" 
  127. -- Retrieval info: PRIVATE: UseDQRAM NUMERIC "0" 
  128. -- Retrieval info: PRIVATE: WidthAddr NUMERIC "7" 
  129. -- Retrieval info: PRIVATE: WidthData NUMERIC "8" 
  130. -- Retrieval info: PRIVATE: rden NUMERIC "0" 
  131. -- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "FLEX10K" 
  132. -- Retrieval info: CONSTANT: LPM_ADDRESS_CONTROL STRING "REGISTERED" 
  133. -- Retrieval info: CONSTANT: LPM_FILE STRING "sin_soft.mif" 
  134. -- Retrieval info: CONSTANT: LPM_OUTDATA STRING "UNREGISTERED" 
  135. -- Retrieval info: CONSTANT: LPM_TYPE STRING "LPM_ROM" 
  136. -- Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "8" 
  137. -- Retrieval info: CONSTANT: LPM_WIDTHAD NUMERIC "7" 
  138. -- Retrieval info: USED_PORT: address 0 0 7 0 INPUT NODEFVAL address[6..0] 
  139. -- Retrieval info: USED_PORT: inclock 0 0 0 0 INPUT NODEFVAL inclock 
  140. -- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL q[7..0] 
  141. -- Retrieval info: CONNECT: @address 0 0 7 0 address 0 0 7 0 
  142. -- Retrieval info: CONNECT: q 0 0 8 0 @q 0 0 8 0 
  143. -- Retrieval info: CONNECT: @inclock 0 0 0 0 inclock 0 0 0 0 
  144. -- Retrieval info: LIBRARY: lpm lpm.lpm_components.all 
  145. -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8.vhd TRUE 
  146. -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8.inc FALSE 
  147. -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8.cmp TRUE 
  148. -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8.bsf FALSE 
  149. -- Retrieval info: GEN_FILE: TYPE_NORMAL lpm_rom8_inst.vhd FALSE 
  150. -- Retrieval info: LIB_FILE: lpm 

     其次,建立锁存器模块;
[cpp]view plaincopyprint?
  1. LIBRARY IEEE; 
  2. USE IEEE.STD_LOGIC_1164.ALL; 
  3. ENTITY REG8B IS 
  4.     PORT (  Load :  IN STD_LOGIC; 
  5.              DIN :  IN STD_LOGIC_VECTOR(7 DOWNTO 0); 
  6.             DOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) ); 
  7. END REG8B; 
  8. ARCHITECTURE behav OF REG8B IS 
  9. BEGIN 
  10.     PROCESS(Load, DIN) 
  11.    BEGIN 
  12.    IF Load'EVENT AND Load = '1' THEN    -- 时钟到来时,锁存输入数据 
  13.             DOUT <= DIN; 
  14.         END IF; 
  15.     END PROCESS; 
  16. END behav; 
     第三,建立加法器模块;
[cpp]view plaincopyprint?
  1. LIBRARY IEEE; 
  2. USE IEEE.STD_LOGIC_1164.ALL; 
  3. USE IEEE.STD_LOGIC_UNSIGNED.ALL; 
  4. ENTITY ADDER8B IS 
  5.     PORT (  A : IN  STD_LOGIC_VECTOR(7 DOWNTO 0); 
  6.             B : IN  STD_LOGIC_VECTOR(7 DOWNTO 0); 
  7.             S : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); 
  8. END ADDER8B; 
  9. ARCHITECTURE behav OF ADDER8B IS 
  10.     BEGIN 
  11.     S <= A + B; 
  12. END behav; 
     第四,顶层模块的设计;
[cpp]view plaincopyprint?
  1. --------------------------------------------------------------------- 
  2. --                Designed By Michael Chen( chen sifan)           --- 
  3. --                                              2011\11\07        --- 
  4. --------------------------------------------------------------------- 
  5. LIBRARY IEEE; 
  6. USE IEEE.STD_LOGIC_1164.ALL; 
  7. USE IEEE.STD_LOGIC_UNSIGNED.ALL; 
  8. --------------------------------------------------------------------- 
  9. ENTITY mydds IS                                     -- 顶层设计 
  10.     PORT (   
  11.           CLK   : IN  STD_LOGIC; 
  12.           FWORD : IN  STD_LOGIC_VECTOR(7 DOWNTO 0); 
  13.           FOUT  : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); 
  14. END mydds; 
  15. --------------------------------------------------------------------- 
  16. ARCHITECTURE behav OF mydds IS 
  17. --------------------------------------------------------------------- 
  18.     COMPONENT REG8B       --load 'event and load = 1 --dout <= din; 
  19.     PORT (   
  20.            LOAD :  IN STD_LOGIC; 
  21.            DIN  :  IN STD_LOGIC_VECTOR(7 DOWNTO 0); 
  22.            DOUT :  OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); 
  23.     END COMPONENT; 
  24. --------------------------------------------------------------------- 
  25.     COMPONENT ADDER8B 
  26.     PORT (   
  27.            A : IN  STD_LOGIC_VECTOR(7 DOWNTO 0); 
  28.            B : IN  STD_LOGIC_VECTOR(7 DOWNTO 0); 
  29.            S : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); 
  30.     END COMPONENT;   
  31. --------------------------------------------------------------------- 
  32.     COMPONENT lpm_rom8 
  33.     PORT (  
  34.             address : IN STD_LOGIC_VECTOR(7 DOWNTO 0); 
  35.             inclock : IN STD_LOGIC ; 
  36.             q       : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); 
  37.     END COMPONENT;  
  38. -----------------------------------------------------------------------    
  39.     SIGNAL F8B : STD_LOGIC_VECTOR( 7 DOWNTO 0); 
  40.     SIGNAL A8B : STD_LOGIC_VECTOR( 7 DOWNTO 0); 
  41.     SIGNAL B8B : STD_LOGIC_VECTOR( 7 DOWNTO 0); 
  42.     SIGNAL C8B : STD_LOGIC_VECTOR( 7 DOWNTO 0); 
  43. --------------------------------------------------------------------- 
  44. BEGIN  
  45.     F8B<=FWORD; 
  46.     U1 : ADDER8B  PORT MAP( A=>F8B,B=>B8B, S=>A8B ); 
  47.     U2 : REG8B  PORT MAP( DOUT=>B8B,DIN=>A8B, LOAD=>CLK ); 
  48.     U3 : REG8B  PORT MAP( DOUT=>C8B,DIN=>B8B, LOAD=>CLK ); 
  49.     U4 : lpm_ROM8  PORT MAP( address=>C8B(7 downto 0), q=>FOUT, inclock=>CLK );     
  50. END  behav; 
         仿真结构如下:          设置成模拟显示的方法如下图(Analog WaveForm选项 ):        最后,有兴趣的“玩家”可以将仿真的波形拿到Matlab当中去。具体方法如下:在quartus II中将波形仿真文件保存为tbl格式的文件,然后在Matlab环境下面去建立M文件去将tbl还原成波形图,顺带也把代码贴下面吧:
[cpp]view plaincopyprint?
  1. %mydds.m 
  2. %Designed By Michael Chen (Chen sifan),2011\11\07 
  3. clear all; 
  4. fid = fopen('D:\Program Files\alter\MyWork\MyDDS.tbl','r');%tbl文件的路径要写对哦 
  5. data = fscanf(fid,'%s'); 
  6. fclose(fid); 
  7. b = find(data == '='); 
  8. number = length(b); 
  9. j = 0; 
  10. for i = 1 : number-1 
  11.     j = j+1; 
  12.     c_s(j,1) = data(b(i)+1); 
  13.     c_s(j,2) = data(b(i)+2); 
  14. end; 
  15. d_s = hex2dec(c_s);%将16进制的数据转换成十进制的 
  16. plot(d_s); 

 

      波形图比较丑,是因为我的mif没有做好的缘故。请见谅哈!

      Ok了,程序设计步骤大致如上所示,但是这个程序还只是实现了DDS一个基本的功能,想要探究DDS的强大功能的话,还要继续花大量时间去整理的。

      在此,我附上我个人的仿真程序下载地址:http://download.csdn.net/detail/csf111/3767213

      由于时间匆忙,错误是难免的,欢迎大家交流讨论

結果