I think the 76.8 MHZ clock is a good option. As you say, there are more available sample rates, and it is a better fit for the 38.4 MHZ oscillator. I do not think that moving the spur down by 3 MHZ is a problem.
I like the idea of using the AD9866 multiplier. For Fossin=38.4, M=2, N=1 we get Fdac=153.6 and Fadc=76.8. Figure 77 does show greater phase noise but any PLL will add phase noise. Both the Versaclock and Si570 are PLLs. The question is whether the AD9866 PLL is so inferior that an external PLL can produce a significant improvement. I doubt this.
I am glad you are measuring the phase noise to clarify the issues. But I don't think your measurement is fair to the AD9866. Your source is a PLL followed by the AD9866 PLL. The direct clock case is an XO and a single PLL. Certainly it is hard to beat the the simplicity of a common XO and nothing else.
Your lengthy post describing the clock issues is masterful. Way to go Steve!
Jim
N2ADR
module fir1024(
input clock,
input clock_calc,
input we, // memory write enable
input signed [MBITS-1:0] x_real, // sample to write
input signed [MBITS-1:0] x_imag,
output reg y_avail,
output reg signed [ABITS-1:0] Raccum,
output reg signed [ABITS-1:0] Iaccum
);
localparam ADDRBITS = 10; // Address bits for 18/36 X 1024 rom/ram blocks
localparam MBITS = 18; // multiplier bits == input bits
parameter MifFile = "./FIRII/coefL8_single.mif"; // ROM coefficients
parameter ABITS = 24 ; // adder bits
parameter TAPS = 976; // number of filter taps, max 2**ADDRBITS
reg [ADDRBITS-1:0] raddr, caddr; // read address for sample and coef
wire [MBITS*2-1:0] q; // I/Q sample read from memory
reg [MBITS*2-1:0] reg_q;
wire signed [18:0] q_real, q_imag; // I/Q sample read from memory
wire signed [18:0] coef; // coefficient read from memory
reg signed [MBITS-1:0] reg_coef;
reg signed [MBITS*2-1:0] Rmult, Imult; // multiplier result
reg signed [MBITS*2-1:0] RmultSum, ImultSum; // multiplier result
reg [ADDRBITS:0] counter; // count TAPS samples
reg [ADDRBITS-1:0] waddr; // write sample memory address
reg [2:0] counter_skip_calc;
assign q_real = reg_q[MBITS*2-1:MBITS];
assign q_imag = reg_q[MBITS-1:0];
firrom18_1024 rom(caddr, clock_calc, coef); // coefficient ROM 18 X 1024
// sample RAM 36 X 1024; 36 bit == 18 bits I and 18 bits Q
// x_real, y_real 18 bit Real and 18bit Imag
// it's a double ported RAM with a two clock signals for reading and writing
firram36_1024 ram({x_real, x_imag}, raddr, clock_calc, ~we, waddr, clock, we, q);
always @(posedge clock)
begin
if (we)
begin
waddr = waddr + 1'd1;
counter_skip_calc = counter_skip_calc + 1'd1; //skip 2**3 = 8 samples - decimation rate
end
end
always @(posedge clock_calc)
begin // main pipeline here
if (we) // Wait until a new sample is written to memory
begin
counter = TAPS[ADDRBITS:0] + 4; // count samples and pipeline latency (delay of 3 clocks from address being presented)
raddr = waddr; // read address -> newest sample
caddr = 1'd0; // start at coefficient zero
Raccum <= 0;
Iaccum <= 0;
Rmult <= 0;
Imult <= 0;
y_avail <=1'd0;
end
else
begin
if ((0 < counter+1'd1) && (counter < (TAPS[ADDRBITS:0] + 2)) && (counter_skip_calc==3'd0) ) //calculation only every eighth input sample
begin
Rmult <= q_real * reg_coef;
Raccum <= Raccum + Rmult[35:12] + Rmult[11]; // truncate 36 bits down to 24 bits to prevent DC spur
Imult <= q_imag * reg_coef;
Iaccum <= Iaccum + Imult[35:12] + Imult[11];
counter <= counter - 1'd1;
raddr <= raddr - 1'd1; // move to prior sample
caddr <= caddr + 1'd1; // move to next coefficient
reg_q <= q;
reg_coef <= coef;
y_avail <=1'd0;
end
else
if (counter==0) //if (counter ==0) then we have been calculated ouput sample in Raccum(I) and Iaccum(Q)
begin
y_avail <=1'd1;
end
end
end
endmodule// File: ramnco.v
// Generated by MyHDL 0.9.0
// Date: Mon Jul 25 15:37:03 2016
`timescale 1ns/10ps
module ramnco (
clk,
intf_cos,
intf_run,
intf_addr,
intf_we,
intf_din,
intf_phase,
intf_sin
);
// RTL
input clk;
output signed [11:0] intf_cos;
reg signed [11:0] intf_cos;
input intf_run;
input [10:0] intf_addr;
input intf_we;
input signed [11:0] intf_din;
input [31:0] intf_phase;
output signed [11:0] intf_sin;
reg signed [11:0] intf_sin;
reg [10:0] raddr;
reg [19:0] lfsr;
wire signed [11:0] rdata;
reg [0:0] state;
reg [32:0] phase_acc;
reg signed [11:0] wavetable [0:2048-1];
always @(posedge clk) begin: RAMNCO_WRITE
if (intf_we) begin
wavetable[intf_addr] <= intf_din;
end
end
assign rdata = wavetable[raddr];
always @(posedge clk) begin: RAMNCO_FSM
case (state)
1'b0: begin
intf_cos <= rdata;
raddr <= (raddr + (2048 / 4));
phase_acc <= (phase_acc + {1'b0, intf_phase});
if (intf_run) begin
state <= 1'b1;
end
end
1'b1: begin
intf_sin <= rdata;
raddr <= phase_acc[32-1:(32 - 11)];
lfsr <= {lfsr[0], (lfsr[19] ^ lfsr[0]), lfsr[18], lfsr[17], (lfsr[16] ^ lfsr[0]), lfsr[15], (lfsr[14] ^ lfsr[0]), lfsr[14-1:1]};
state <= 1'b0;
end
endcase
end
endmoduleHi Vasyl,
lfsr <= {lfsr[0], (lfsr[19] ^ lfsr[0]), lfsr[18], lfsr[17], (lfsr[16] ^ lfsr[0]), lfsr[15], (lfsr[14] ^ lfsr[0]), lfsr[14-1:1]};