DDS的verilog 实现个人总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xubuwei/article/details/6603730

先说说DDS算法 的基本原理:

DDS是直接式数字频率合成的简称。它在无线通信系统实现中是一门关键技术。其实,DDS在FPGA中的实现方法说白了就是在定义好的ROM数据中寻址并找到该地址对应的波形数据。在系统参考时钟的驱动下,通过控制频率控制字来驱动相位累加寄存器数值的变化,从而是在ROM中寻址并找到对应数据,最后输出为波形数据。其中,在每一个系统时钟脉冲来临时,相位累加寄存器都会相应叠加一次频率控制字。其实,频率控制字的功能就是控制步进长度,也就是形成的波形的频率和系统时钟频率的比例关系,最终可以确定输出波形的频率。比如要输出正弦波,系统参考时钟频率为20M,输出每位宽度为10bit,则令频率控制字位宽为20bit,f(out)=(频率控制字/2^20)*f(clk)。这样就可以控制输出波形的频率。

本人用的是QUETUS II开发环境。对于quatus ii 中ROM 可用的数据文件格式为mif。此文件数据可以用MATLAB来产生。

具体产生方法如下:

新建一个.m文件,然后输入:

width=10;//位宽
depth=2^width;//数据深度
t=linspace(0,6.28,depth);
sin_val=sin(t);
cos_val=cos(t);
sin_val=fix(sin_val*(2^width-1)/2+0.5);//四舍五入求结果
cos_val=fix(cos_val*(2^width-1)/2+0.5);

addr=[0:1023];
%存盘
file=fopen('f:/My Works/FPGA Examples/sin.mif','wt');
fprintf(file,'WIDTH=%d;\n',width);
fprintf(file,'DEPTH=%d;\n',depth);
fprintf(file,'ADDRESS_RADIX=UNS;\n');
fprintf(file,'DATA_RADIX=DEC;\n');//这个数据格式最好不要变,不然改动会很麻烦
fprintf(file,'CONTENT BEGIN\n');
for i=1:depth
    fprintf(file,'%d:%d;\n',addr(i),sin_val(i));
end
fprintf(file,'END;\n');
fclose(file);

file=fopen('f:/My Works/FPGA Examples/cos.mif','wt');
fprintf(file,'WIDTH=%d;\n',width);
fprintf(file,'DEPTH=%d;\n',depth);
fprintf(file,'ADDRESS_RADIX=UNS;\n');
fprintf(file,'DATA_RADIX=DEC;\n');
fprintf(file,'CONTENT BEGIN\n');
for i=1:depth
    fprintf(file,'%d:%d;\n',addr(i),cos_val(i));
end
fprintf(file,'END;\n');
fclose(file);

上述程序可以产生可用的mif文件数据,并可以导入ROM中。

最后就是编写verilog代码。

module DDS(clk,rst,A,
           data0,data1,data2,data3,
           out_signal0,out_signal1,out_signal2,out_signal3,
           we,ddse
           );
           
input clk;
input rst;
input we;
input ddse;
input[3:0] A;
input[19:0] data0;
input[19:0] data1;
input[19:0] data2;
input[19:0] data3;
output[9:0] out_signal0;
output[9:0] out_signal1;
output[9:0] out_signal2;
output[9:0] out_signal3;

reg[19:0] ADD_A[3:0];
reg[19:0] ADD_B0,ADD_B1,ADD_B2,ADD_B3;
reg[9:0] signal_r[3:0];

wire[9:0] signal_d[3:0];
wire[9:0] ROM[3:0];

assign out_signal0=signal_r[0];
assign out_signal1=signal_r[1];
assign out_signal2=signal_r[2];
assign out_signal3=signal_r[3];
assign ROM[0]=ADD_B0[19:10];
assign ROM[1]=ADD_B1[19:10];
assign ROM[2]=ADD_B2[19:10];
assign ROM[3]=ADD_B3[19:10];

always@(posedge clk or negedge rst) begin
          if(!rst) begin ADD_A[0] <= 20'b0; ADD_A[1] <= 20'b0;
                         ADD_A[2] <= 20'b0; ADD_A[3] <= 20'b0;
                   end
          else if(we)
            begin
              if(A==3'b0) begin ADD_A[0] <= 20'b0; ADD_A[1] <= 20'b0;
                                ADD_A[2] <= 20'b0; ADD_A[3] <= 20'b0;
                          end
              else begin ADD_A[0] <= data0; ADD_A[1] <= data1;
                         ADD_A[2] <= data2; ADD_A[3] <= data3;
                   end
            end
          else begin ADD_A[0] <= 20'b0; ADD_A[1] <= 20'b0;
                     ADD_A[2] <= 20'b0; ADD_A[3] <= 20'b0;
               end
end

always@(posedge clk or negedge rst) begin
          if(!rst) begin ADD_B0 <= 20'b0;ADD_B1 <= 20'b0;
                         ADD_B2 <= 20'b0;ADD_B3 <= 20'b0;
                   end
          else if(ddse)
            begin
               if(A) begin
                   ADD_B0 <= ADD_A[0] + ADD_B0;
                   ADD_B1 <= ADD_A[1] + ADD_B1;
                   ADD_B2 <= ADD_A[2] + ADD_B2;
                   ADD_B3 <= ADD_A[3] + ADD_B3;
                end
                else begin ADD_B0 <= 20'b0;ADD_B1 <= 20'b0;ADD_B2 <= 20'b0;ADD_B3 <= 20'b0; end
            end
          else begin ADD_B0 <= ADD_B0; ADD_B1 <= ADD_B1;ADD_B2 <= ADD_B2;ADD_B3 <= ADD_B3; end
end

always@(posedge clk or negedge rst) begin
          if(!rst) begin signal_r[0] <= 10'b0; signal_r[1] <= 10'b0;
                         signal_r[2] <= 10'b0; signal_r[3] <= 10'b0;
                   end
          else if(ddse)
               begin if(A)
                   begin
                    case(A)
                     4'b0001:begin signal_r[0] <= signal_d[0]; signal_r[1] <= 10'b0;
                                  signal_r[2] <= 10'b0;       signal_r[3] <= 10'b0;
                            end
                     4'b0010:begin signal_r[0] <= 10'b0;      signal_r[1] <= signal_d[1];
                                  signal_r[2] <= 10'b0;       signal_r[3] <= 10'b0;
                            end
                     4'b0011:begin signal_r[0] <= signal_d[0]; signal_r[1] <= signal_d[1];
                                  signal_r[2] <= 10'b0;        signal_r[3] <= 10'b0;
                            end
                     4'b0100:begin signal_r[0] <= 10'b0;      signal_r[1] <= 10'b0;
                                  signal_r[2] <= signal_d[2]; signal_r[3] <= 10'b0;
                            end
                     4'b0101:begin signal_r[0] <= signal_d[0]; signal_r[1] <= signal_d[1];
                                  signal_r[2] <= signal_d[2]; signal_r[3] <= signal_d[3];
                            end
                     4'b0110:begin signal_r[0] <= 10'b0; signal_r[1] <= signal_d[1];
                                  signal_r[2] <= signal_d[2]; signal_r[3] <= 10'b0;
                            end
                     4'b0111:begin signal_r[0] <= signal_d[0]; signal_r[1] <= signal_d[1];
                                  signal_r[2] <= signal_d[2]; signal_r[3] <= 10'b0;
                            end
                     4'b1000:begin signal_r[0] <= 10'b0; signal_r[1] <= 10'b0;
                                  signal_r[2] <= 10'b0; signal_r[3] <= signal_d[3];
                            end
                     4'b1001:begin signal_r[0] <= signal_d[0]; signal_r[1] <= 10'b0;
                                  signal_r[2] <= 10'b0; signal_r[3] <= signal_d[3];
                            end
                     4'b1010:begin signal_r[0] <= 10'b0; signal_r[1] <= signal_d[1];
                                  signal_r[2] <= 10'b0; signal_r[3] <= signal_d[3];
                            end
                     4'b1011:begin signal_r[0] <= signal_d[0]; signal_r[1] <= signal_d[1];
                                  signal_r[2] <= 10'b0; signal_r[3] <= signal_d[3];
                            end
                     4'b1100:begin signal_r[0] <= 10'b0; signal_r[1] <= 10'b0;
                                  signal_r[2] <= signal_d[2]; signal_r[3] <= signal_d[3];
                            end
                     4'b1101:begin signal_r[0] <= signal_d[0]; signal_r[1] <= 10'b0;
                                  signal_r[2] <= signal_d[2]; signal_r[3] <= signal_d[3];
                            end
                     4'b1110:begin signal_r[0] <= 10'b0; signal_r[1] <= signal_d[1];
                                  signal_r[2] <= signal_d[2]; signal_r[3] <= signal_d[3];
                            end
                     4'b1111:begin signal_r[0] <= signal_d[0]; signal_r[1] <= signal_d[1];
                                   signal_r[2] <= signal_d[2]; signal_r[3] <= signal_d[3];
                             end
                     default:begin signal_r[0] <= 10'b0; signal_r[1] <= 10'b0;
                                   signal_r[2] <= 10'b0; signal_r[3] <= 10'b0;
                             end
                     endcase
                   end
                   else begin signal_r[0] <= 10'b0; signal_r[1] <= 10'b0;
                              signal_r[2] <= 10'b0; signal_r[3] <= 10'b0;
                        end
               end
          else begin signal_r[0] <= 10'b0; signal_r[1] <= 10'b0;
                     signal_r[2] <= 10'b0; signal_r[3] <= 10'b0;
               end
end

rom_sin rom_sin1(
                 .address(ROM[0]),
                 .clock(clk),
                 .q(signal_d[0])
                 );
                 
rom_sin rom_sin2(
                 .address(ROM[1]),
                 .clock(clk),
                 .q(signal_d[1])
                 );
                 
rom_cos rom_cos1(
                 .address(ROM[2]),
                 .clock(clk),
                 .q(signal_d[2])
                 );  
                 
rom_cos rom_cos2(
                 .address(ROM[3]),
                 .clock(clk),
                 .q(signal_d[3])
                 );
            
endmodule

上述代码的功能是实现四路自选信号的产生,但是说实话,本程序是没有使用价值的,因为IO端口占用太多,没有复用,只是觉得好玩,编写着看看的。

从图中可以看到有很多毛刺,需要改进,这个要今后再说。


猜你喜欢

转载自blog.csdn.net/xubuwei/article/details/6603730
dds