It's hard to tell what exactly is wrong as we don't see your whole code (and one hidden part was already one source of your problems!)
But from the look of what you get, I guess it might still be overflowing.
Have you tried with a wider accumulator width?
Fair enough, I have included the entire DDS NCO below.
Top Module:
module DE10_Nano_Function_Generator
#(
parameter PW=26,
parameter OW=16
)
(
input wire clk,
input wire res,
/////////SW "3.3-V LVTTL"//////////
input wire [1:0] SW,
/////////LED "3.3-V LVTTL"/////////
output wire [3:0] LED,
///////////function out////////////
// output wire func1_out,
output wire func_out
// output wire [OW-1:0] func_out
);
wire [1:0] func_select;
LED_display display
(
.sel(func_select),
.LED(LED)
);
dds_nco_synthesizer dds
(
.DAC_clk(clk),
.DAC_res(res),
.func_select(func_select),
// .LP_out(func_out)
.DAC_out(func_out)
);
defparam dds.OW=OW;
defparam dds.PW=PW;
assign func_select = SW[1:0];
endmodule
LED Display:
module LED_display
(
input wire [1:0] sel,
output reg [3:0] LED
);
always @(sel)
begin
case(sel)
2'b00: LED<=4'b0001;
2'b01: LED<=4'b0010;
2'b10: LED<=4'b0100;
2'b11: LED<=4'b1000;
endcase
end
endmodule
DDS NCO module:
module dds_nco_synthesizer
#(
parameter PW,OW
)
(
input wire DAC_clk,
input wire DAC_res,
input wire [PW-2:0] freq_tune, // need 2 samples per waveform at least
input wire [1:0] func_select,
// output wire [OW-1:0] LP_out
output wire DAC_out
);
reg [(PW-1):0] phase;
wire [(OW-1):0] sin_out;
wire [(OW-1):0] sqr_out;
wire [(OW-1):0] tri_out;
wire [(OW-1):0] sw_out;
wire [(OW-1):0] func;
always @(posedge DAC_clk or negedge DAC_res)
begin
if (DAC_res==0)
begin
/* define PW-bit number "phase" with PW-bit
decimal 0 created using repetition operator */
phase<={(PW){1'd0}};
end
else
/* add PW-bit number with decimal value 1 to "phase"
by concatenating 1 bit decimal value 1 to end of
(PW-1)-bit decimal 0 created using repetition
operator */
// phase<=phase+{{(PW-1){1'd0}},1'd1};
phase<=phase+'d200000;
// phase<=phase+freq_tune;
end
sine sine_out
(
.i_phase(phase[(PW-1):((PW-1)-(OW-1))]),
.o_sine(sin_out)
);
defparam sine_out.OW=OW;
square square_out
(
.i_phase(phase[(PW-1):((PW-1)-(OW-1))]),
.o_square(sqr_out)
);
defparam square_out.OW=OW;
triangle triang_out
(
.i_phase(phase[(PW-1):((PW-1)-(OW-1))]),
.o_triang(tri_out)
);
defparam triang_out.OW=OW;
saw saw_out
(
.i_phase(phase[(PW-1):((PW-1)-(OW-1))]),
.o_saw(sw_out)
);
defparam saw_out.OW=OW;
function_MUX MUX
(
.sel(func_select),
.si(sin_out),
.sq(sqr_out),
.tr(tri_out),
.sw(sw_out),
.o_func(func)
);
defparam MUX.OW=OW;
delta_sigma_DAC_2nd_order DAC2
(
.i_clk(DAC_clk),
.i_res(DAC_res),
.i_func(func),
.o_DAC(DAC_out)
);
defparam DAC2.OW=OW;
// CIC_LP_filter LPF
// (
// .i_clk(DAC_clk),
// .i_res(DAC_res),
// .i_filter(DAC_out),
// .o_filter(LP_out)
// );
// defparam LPF.OW=OW;
endmodule
Quarter wave sine synthesizer:
module sine
#(
parameter OW
)
(
input wire [(OW-1):0] i_phase,
output wire [(OW-1):0] o_sine
);
/* (1<<(OW-2)) means 2^(OW-2) */
reg [(OW-1):0] quartertable [0:((1<<(OW-2))-1)];
initial $readmemh("16bit_QuarterSineLookup.hex", quartertable);
wire [1:0] negate;
wire [((OW-1)-2):0] index; // OW-1:0 bit register reduced in size by 4quarters (2^2)
wire [(OW-1):0] tblvalue;
// Clock #1
assign negate[0] = i_phase[(OW-1)];
assign index=i_phase[(OW-2)]?~i_phase[(OW-3):0]:i_phase[(OW-3):0];
// Clock #2
assign tblvalue=quartertable[index];
assign negate[1]=negate[0];
// Output Clock
assign o_sine=negate[1]?-tblvalue:tblvalue;
// negate[1]?-tblvalue-{(OW-1){1'b1}}:tblvalue+{(OW-1){1'b1}};
// above works for 1st order DAC
endmodule
Square wave synthesizer:
module square
#(
parameter OW
)
(
input wire [(OW-1):0] i_phase,
output wire [(OW-1):0] o_square
);
assign o_square = {OW{i_phase[OW-1]}};
endmodule
Triangle wave synthesizer:
module triangle
#(
parameter OW
)
(
input wire [(OW-1):0] i_phase,
output wire [(OW-1):0] o_triang
);
assign o_triang = i_phase[OW-1]?~i_phase[(OW-1):0]:i_phase[(OW-1):0];
endmodule
Saw wave synthesizer:
module saw
#(
parameter OW
)
(
input wire [(OW-1):0] i_phase,
output wire [(OW-1):0] o_saw
);
assign o_saw = i_phase[(OW-1):0];
endmodule
Waveform selection MUX:
module function_MUX
#(
parameter OW
)
(
input wire [1:0] sel,
input wire [(OW-1):0] si,
input wire [(OW-1):0] sq,
input wire [(OW-1):0] tr,
input wire [(OW-1):0] sw,
output reg [(OW-1):0] o_func
);
always @(sel,si,sq,tr,sw)
begin
case(sel)
2'b00:o_func<=si;
2'b01:o_func<=sq;
2'b10:o_func<=tr;
2'b11:o_func<=sw;
default:o_func<=si;
endcase
end
endmodule
1st Order Sigma-Delta Digital-to-Analog Converter (not used now that 2nd order is working):
module delta_sigma_DAC
#(
parameter OW, // output word size
parameter OS=4 // oversampling ratio, 2^7 = 128
)
(
input wire i_clk, // input clock
input wire i_res, // input reset line
input wire [OW-1:0] i_func, // input function
output wire o_DAC // output DAC bit
);
reg [((OW-1)+OS):0] DAC_acc; // DAC accumulator
always @(posedge i_clk or negedge i_res)
begin
if (i_res==0)
begin
DAC_acc<={((OW-1)+OS){1'd0}}; // zeroes output on reset
end
else
DAC_acc<=DAC_acc[((OW-1)+OS)-1:0]+i_func; /* adds value of
i_func to DAC
accumulator
register */
end
assign o_DAC=DAC_acc[((OW-1)+OS)]; // outputs top bit of DAC accumulator
endmodule
2nd Order Sigma-Delta Digital-to-Analog Converter:
module delta_sigma_DAC_2nd_order
#(
parameter OW,
parameter OSR=8 // 2^OSR = oversampling ratio
)
(
input wire i_clk,
input wire i_res,
input wire [OW-1:0] i_func,
output wire o_DAC
);
reg [((OW-1)+OSR):0] DAC_acc_1st;
reg [((OW-1)+OSR):0] DAC_acc_2nd;
reg [((OW-1)+OSR):0] i_func_ext;
reg [OW-1:0] mid_DNR={(OW-1){1'd1}}+{(OW-6){1'd1}};
reg ADC_out;
always @*
begin
i_func_ext={{OSR{i_func[OW-1]}},i_func};
end
always @(posedge i_clk or negedge i_res)
begin
if (i_res==0)
begin
DAC_acc_1st<={((OW-1)+OSR){1'd0}};
DAC_acc_2nd<={((OW-1)+OSR){1'd0}};
ADC_out<=1'b0;
end
else
begin
if(ADC_out==1'b1)
begin
DAC_acc_1st=DAC_acc_1st+i_func_ext+mid_DNR;
DAC_acc_2nd=DAC_acc_2nd+DAC_acc_1st+mid_DNR;
end
else
begin
DAC_acc_1st=DAC_acc_1st+i_func_ext-mid_DNR;
DAC_acc_2nd=DAC_acc_2nd+DAC_acc_1st-mid_DNR;
end
ADC_out<=DAC_acc_2nd[((OW-1)+OSR)];
end
end
assign o_DAC=ADC_out;
endmodule
Cascaded integrator comb rolling average low pass filter (not used except for simulations):
module CIC_LP_filter
#(
parameter OW,
parameter FB=7 // number of sample bits for rolling average filter
)
(
input wire i_clk,
input wire i_res,
input wire i_filter,
output reg [OW-1:0] o_filter
);
reg roll_data [0:2**FB-1];
reg [OW+FB-1:0] store;
wire [OW+FB-1:0] integrate=i_filter+store-roll_data[2**FB-1];
genvar i;
generate
for (i = 0; i < 2**FB-1 ; i = i + 1)
begin: gd
always @(posedge i_clk or negedge i_res)
begin
if(i_res==0)
begin
roll_data[i+1]<=0;
end
else
begin
roll_data[i+1] <= roll_data[i];
end
end
end
endgenerate
always @(posedge i_clk or negedge i_res)
begin
if(i_res==0)
begin
roll_data[0]<=0;
end
else
begin
roll_data[0] <= i_filter;
end
end
always@(posedge i_clk or negedge i_res)
begin
if (i_res==0)
begin
store<=0;
o_filter<=0;
end
else
begin
store<=integrate;
o_filter<=integrate[OW-1:0];
end
end
endmodule
*** EDIT ***
By popular demand, I have added the test bench file, and also a copy of the sine wave hex file (attached at the end of this message). If you want an output waveform for the test bench, you will have to uncomment the CIC LP filter in the DDS NCO module and feed the DAC output into the input of the CIC LP filter module, and assign the output of the DDS NCO module to the output of the CIC LP filter module
Testbench Module:
`timescale 100ns/10ns
module dds_nco_synthesizer_tb
#(
parameter PW=26,
parameter OW=16
)
(
output wire [OW-1:0] LP_out
);
reg clk;
reg res;
reg [1:0] sel;
reg [PW-2:0] freq;
dds_nco_synthesizer dds
(
.DAC_clk(clk),
.DAC_res(res),
.func_select(sel),
.freq_tune(freq),
.LP_out(LP_out)
);
defparam dds.OW=OW;
defparam dds.PW=PW;
initial
begin
clk=0; res=0; freq=25'd1; #5; res=1;
sel=0;
$display("1 kHz Sine"); freq=25'd1000; #250000;
sel=1;
$display("1 kHz Square"); freq=25'd1000; #250000;
sel=2;
$display("1 kHz Triangle"); freq=25'd1000; #250000;
sel=3;
$display("1 kHz Saw"); freq=25'd1000; #250000;
// $display("10 kHz"); freq=25'd10000; #100000;
// $display("100 kHz"); freq=25'd100000; #100000;
// $display("200 kHz"); freq=25'd200000; #100000;
// $display("400 kHz"); freq=25'd400000; #100000;
$stop;
end
always #10 clk=~clk;
endmodule
I have also added the timing constraints file for the board I am using (DE10 Nano from Terasic) for the Quartus Prime software suite (save it as .sdc rather than its existing .txt)