-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added dynamic phase shift information into output and output file comments #175
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,8 @@ struct secondary_params{ | |
|
||
float freq; | ||
float phase; | ||
float phase_vco_step; | ||
float phase_div_step; | ||
}; | ||
|
||
struct pll_params{ | ||
|
@@ -62,6 +64,10 @@ struct pll_params{ | |
int feedback_div; | ||
int output_div; | ||
int primary_cphase; | ||
int primary_fphase; | ||
float primary_phase_vco_step; | ||
float primary_phase_div_step; | ||
|
||
string clkin_name; | ||
string clkout0_name; | ||
int dynamic; | ||
|
@@ -85,6 +91,8 @@ struct pll_params{ | |
} | ||
}; | ||
|
||
float calc_vco_phase_step(int fphase, int div); | ||
float calc_div_phase_step(int cphase, int div); | ||
void calc_pll_params(pll_params ¶ms, float input, float output); | ||
void calc_pll_params_highres(pll_params ¶ms, float input, float output); | ||
void generate_secondary_output(pll_params ¶ms, int channel, string name, float frequency, float phase); | ||
|
@@ -245,22 +253,38 @@ int main(int argc, char** argv){ | |
cout << "Feedback divisor: " << params.feedback_div << endl; | ||
cout << "clkout0 divisor: " << params.output_div << "" << endl; | ||
cout << "clkout0 frequency: " << params.fout << " MHz" << endl; | ||
if(params.dynamic){ | ||
cout << "clkout0 vco step: " << params.primary_phase_vco_step << " degrees" << endl; | ||
cout << "clkout0 div step: " << params.primary_phase_div_step << " degrees" << endl; | ||
} | ||
if(params.secondary[0].enabled){ | ||
cout << "clkout1 divisor: " << params.secondary[0].div << endl; | ||
cout << "clkout1 frequency: " << params.secondary[0].freq << " MHz" << endl; | ||
cout << "clkout1 phase shift: " << params.secondary[0].phase << " degrees" << endl; | ||
if(params.dynamic){ | ||
cout << "clkout1 vco step: " << params.secondary[0].phase_vco_step << " degrees" << endl; | ||
cout << "clkout1 div step: " << params.secondary[0].phase_div_step << " degrees" << endl; | ||
} | ||
} | ||
if(params.secondary[1].enabled){ | ||
cout << "clkout2 divisor: " << params.secondary[1].div << endl; | ||
cout << "clkout2 frequency: " << params.secondary[1].freq << " MHz" << endl; | ||
cout << "clkout2 phase shift: " << params.secondary[1].phase << " degrees" << endl; | ||
if(params.dynamic){ | ||
cout << "clkout2 vco step: " << params.secondary[1].phase_vco_step << " degrees" << endl; | ||
cout << "clkout2 div step: " << params.secondary[1].phase_div_step << " degrees" << endl; | ||
} | ||
} | ||
if(params.secondary[2].enabled){ | ||
cout << "clkout3 divisor: " << params.secondary[2].div << endl; | ||
cout << "clkout3 frequency: " << params.secondary[2].freq << " MHz" << endl; | ||
cout << "clkout3 phase shift: " << params.secondary[2].phase << " degrees" << endl; | ||
if(params.dynamic){ | ||
cout << "clkout3 vco step: " << params.secondary[2].phase_vco_step << " degrees" << endl; | ||
cout << "clkout3 div step: " << params.secondary[2].phase_div_step << " degrees" << endl; | ||
} | ||
} | ||
cout << "VCO frequency: " << params.fvco << endl; | ||
cout << "VCO frequency: " << params.fvco << " Mhz" << endl; | ||
if(vm.count("file")){ | ||
ofstream f; | ||
f.open(vm["file"].as<string>().c_str()); | ||
|
@@ -269,6 +293,14 @@ int main(int argc, char** argv){ | |
} | ||
} | ||
|
||
float calc_vco_phase_step(int fphase, int div){ | ||
return (360.f * (float)fphase) / (8.f * (float)div); | ||
} | ||
|
||
float calc_div_phase_step(int cphase, int div){ | ||
return (360.f * ((float)cphase - (float)div)) / (1.f + (float)div); | ||
} | ||
|
||
void calc_pll_params(pll_params ¶ms, float input, float output){ | ||
float error = std::numeric_limits<float>::max(); | ||
for(int input_div=1;input_div <= 128; input_div++){ | ||
|
@@ -278,24 +310,29 @@ void calc_pll_params(pll_params ¶ms, float input, float output){ | |
continue; | ||
for(int feedback_div=1;feedback_div <= 80; feedback_div++){ | ||
for(int output_div=1;output_div <= 128; output_div++){ | ||
float fvco = fpfd * (float)feedback_div * (float) output_div; | ||
|
||
if(fvco < VCO_MIN || fvco > VCO_MAX) | ||
continue; | ||
|
||
float fout = fvco / (float) output_div; | ||
if(fabsf(fout - output) < error || | ||
(fabsf(fout-output) == error && fabsf(fvco - 600) < fabsf(params.fvco - 600))){ | ||
error = fabsf(fout-output); | ||
params.refclk_div = input_div; | ||
params.feedback_div = feedback_div; | ||
params.output_div = output_div; | ||
params.fout = fout; | ||
params.fvco = fvco; | ||
// shift the primary by 180 degrees. Lattice seems to do this | ||
float ns_phase = 1/(fout * 1e6) * 0.5; | ||
params.primary_cphase = ns_phase * (fvco * 1e6); | ||
} | ||
float fvco = fpfd * (float)feedback_div * (float) output_div; | ||
|
||
if(fvco < VCO_MIN || fvco > VCO_MAX) | ||
continue; | ||
|
||
float fout = fvco / (float) output_div; | ||
if(fabsf(fout - output) < error || | ||
(fabsf(fout-output) == error && fabsf(fvco - 600) < fabsf(params.fvco - 600))){ | ||
error = fabsf(fout-output); | ||
params.refclk_div = input_div; | ||
params.feedback_div = feedback_div; | ||
params.output_div = output_div; | ||
params.fout = fout; | ||
params.fvco = fvco; | ||
// shift the primary by 180 degrees. Lattice seems to do this | ||
float ns_phase = 1/(fout * 1e6) * 0.5; | ||
float phase_count = ns_phase * (fvco * 1e6); | ||
params.primary_cphase = phase_count; | ||
int cphase = (int) phase_count; | ||
params.primary_fphase = (int) ((phase_count - cphase) * 8); | ||
params.primary_phase_vco_step = calc_vco_phase_step(params.primary_fphase, params.output_div); | ||
params.primary_phase_div_step = calc_div_phase_step(params.primary_cphase, params.output_div); | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -310,29 +347,38 @@ void calc_pll_params_highres(pll_params ¶ms, float input, float output){ | |
continue; | ||
for(int feedback_div=1;feedback_div <= 80; feedback_div++){ | ||
for(int output_div=1;output_div <= 128; output_div++){ | ||
float fvco = fpfd * (float)feedback_div * (float) output_div; | ||
|
||
if(fvco < VCO_MIN || fvco > VCO_MAX) | ||
continue; | ||
float ffeedback = fvco / (float) output_div; | ||
if(ffeedback < OUTPUT_MIN || ffeedback > OUTPUT_MAX) | ||
continue; | ||
for(int secondary_div = 1; secondary_div <= 128; secondary_div++){ | ||
float fout = fvco / (float) secondary_div; | ||
if(fabsf(fout - output) < error || | ||
(fabsf(fout-output) == error && fabsf(fvco - 600) < fabsf(params.fvco - 600))){ | ||
error = fabsf(fout-output); | ||
params.mode = pll_mode::HIGHRES; | ||
params.refclk_div = input_div; | ||
params.feedback_div = feedback_div; | ||
params.output_div = output_div; | ||
params.secondary[0].div = secondary_div; | ||
params.secondary[0].enabled = true; | ||
params.secondary[0].freq = fout; | ||
params.fout = fout; | ||
params.fvco = fvco; | ||
} | ||
} | ||
float fvco = fpfd * (float)feedback_div * (float) output_div; | ||
|
||
if(fvco < VCO_MIN || fvco > VCO_MAX) | ||
continue; | ||
float ffeedback = fvco / (float) output_div; | ||
if(ffeedback < OUTPUT_MIN || ffeedback > OUTPUT_MAX) | ||
continue; | ||
for(int secondary_div = 1; secondary_div <= 128; secondary_div++){ | ||
float fout = fvco / (float) secondary_div; | ||
if(fabsf(fout - output) < error || | ||
(fabsf(fout-output) == error && fabsf(fvco - 600) < fabsf(params.fvco - 600))){ | ||
error = fabsf(fout-output); | ||
params.mode = pll_mode::HIGHRES; | ||
params.refclk_div = input_div; | ||
params.feedback_div = feedback_div; | ||
params.output_div = output_div; | ||
params.secondary[0].div = secondary_div; | ||
params.secondary[0].enabled = true; | ||
params.secondary[0].freq = fout; | ||
params.fout = fout; | ||
params.fvco = fvco; | ||
|
||
// Is this correct for highres mode? | ||
float ns_phase = 1/(fout * 1e6) * 0.5; | ||
float phase_count = ns_phase * (fvco * 1e6); | ||
params.primary_cphase = phase_count; | ||
int cphase = (int) phase_count; | ||
params.primary_fphase = (int) ((phase_count - cphase) * 8); | ||
params.primary_phase_vco_step = calc_vco_phase_step(params.primary_fphase, params.output_div); | ||
params.primary_phase_div_step = calc_div_phase_step(params.primary_cphase, params.output_div); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -359,6 +405,8 @@ void generate_secondary_output(pll_params ¶ms, int channel, string name, flo | |
params.secondary[channel].cphase = cphase + params.primary_cphase; | ||
params.secondary[channel].fphase = fphase; | ||
params.secondary[channel].name = name; | ||
params.secondary[channel].phase_vco_step = calc_vco_phase_step(fphase, div); | ||
params.secondary[channel].phase_div_step = calc_div_phase_step(params.secondary[channel].cphase, div); | ||
} | ||
|
||
void write_pll_config(const pll_params & params, const string &name, ofstream& file) | ||
|
@@ -376,8 +424,22 @@ void write_pll_config(const pll_params & params, const string &name, ofstream& f | |
{ | ||
file << " input [1:0] phasesel, // clkout[] index affected by dynamic phase shift (except clkfb), 5 ns min before apply\n"; | ||
file << " input phasedir, // 0:delayed (lagging), 1:advence (leading), 5 ns min before apply\n"; | ||
file << " input phasestep, // 45 deg step, high for 5 ns min, falling edge = apply\n"; | ||
file << " input phaseloadreg, // high for 10 ns min, falling edge = apply\n"; | ||
file << " // high for 5 ns min, falling edge = apply\n"; | ||
file << " // " << params.primary_phase_vco_step << " deg step for " << params.clkout0_name << "\n"; | ||
for (int i = 0; i < 3; ++i){ | ||
if(params.secondary[i].enabled){ | ||
file << " // " << params.secondary[i].phase_vco_step << " deg step for " << params.secondary[i].name << "\n"; | ||
} | ||
} | ||
file << " input phasestep,\n"; | ||
file << " // high for 10 ns min, falling edge = apply\n"; | ||
file << " // " << params.primary_phase_div_step << " deg step for " << params.clkout0_name << "\n"; | ||
for (int i = 0; i < 3; ++i){ | ||
if(params.secondary[i].enabled){ | ||
file << " // " << params.secondary[i].phase_div_step << " deg step for " << params.secondary[i].name << "\n"; | ||
} | ||
} | ||
file << " input phaseloadreg,\n"; | ||
} | ||
file << " input " << params.clkin_name << ", // " << params.clkin_frequency << " MHz, 0 deg\n"; | ||
file << " output " << params.clkout0_name << ", // " << params.fout << " MHz, 0 deg\n"; | ||
|
@@ -422,7 +484,7 @@ void write_pll_config(const pll_params & params, const string &name, ofstream& f | |
file << " .CLKOP_ENABLE(\"ENABLED\"),\n"; | ||
file << " .CLKOP_DIV(" << params.output_div << "),\n"; | ||
file << " .CLKOP_CPHASE(" << params.primary_cphase << "),\n"; | ||
file << " .CLKOP_FPHASE(0),\n"; | ||
file << " .CLKOP_FPHASE(" << params.primary_fphase << "),\n"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why was 0 used here? The calculated fphase is not always 0. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, I'll need to take some time to look into this as it's been a good while since I touched the ECP5 PLLs. I will keep this on my list though. |
||
if(params.secondary[0].enabled){ | ||
file << " .CLKOS_ENABLE(\"ENABLED\"),\n"; | ||
file << " .CLKOS_DIV(" << params.secondary[0].div << "),\n"; | ||
|
@@ -504,6 +566,6 @@ void write_pll_config(const pll_params & params, const string &name, ofstream& f | |
file << " .PLLWAKESYNC(1'b0),\n"; | ||
file << " .ENCLKOP(1'b0),\n"; | ||
file << " .LOCK(locked)\n"; | ||
file << " );\n"; | ||
file << " );\n"; | ||
file << "endmodule\n"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same calculation as done for secondary clocks is this correct?