/* 15 KHz PLL experiment with a Spartan 6 FPGA board https://twitter.com/tuliphouseRadio/status/1351935822421889025 ------------------------------------------------------------ | | | | | | 3.3 V / / / / | | | / 470 ohm / 470 ohm / 270 ohm / 270 ohm --- | / / / / / --- 1uF --->/ 200 ohm VR | | | | | / vco_pad1 vco_pad2 ph_out_u ph_out_d GND | | | GND --- --- --- 1nF --- 1nF | | GND GND */ component BUFG(in uint#1 I, out uint#1 O); component FDCE(in uint#1 C, in uint#1 CE, in uint#1 CLR, in uint#1 D, out uint#1 Q); component OBUFT(in uint#1 I, in uint#1 T, out uint#1 O); component IOBUF(in uint#1 T, in uint#1 I, out uint#1 O, inout uint#1 IO); component DCM_SP( out uint#1 CLKFX, in uint#1 CLKIN, in uint#1 PSCLK, in uint#1 PSEN, in uint#1 PSINCDEC, in uint#1 RST, out uint#1 LOCKED ); process test_clock(clkin uint#1 clk, rstin uint#1 rst, out uint#1 latch clk16k) { uint#11 i = 0; while (1) { if (i==0) clk16k = 0; else if (i==100) clk16k = 1; else if (i==1999) { i = 0b11111111111; } i++; } } // typical phase detector hierarchy phase_detector(in uint#1 clk1, in uint#1 clk2, out uint#1 out_u, out uint#1 out_d) { com uint#1 q_u, q_d; com uint#1 a; FDCE(clk1, 1, a, 1, q_u); FDCE(clk2, 1, a, 1, q_d); a = q_u & q_d; out_u = ~q_u; out_d = ~q_d; } // vco : https://ednjapan.com/edn/articles/1307/29/news062.html hierarchy vco(inout uint#1 pad1, inout uint#1 pad2, out uint#1 outp) { com uint#1 nor1_o, nor2_o, nor1_i1, nor2_i1; nor1_o = ~ (nor1_i1 | nor2_o); nor2_o = ~ (nor2_i1 | nor1_o); IOBUF(nor1_o, 0, nor1_i1, pad1); IOBUF(nor2_o, 0, nor2_i1, pad2); outp = nor1_o; } // generate 16 KHz from the 480 KHz vco output process counter(clkin uint#1 clk, rstin uint#1 rst, out uint#1 outp) { uint#1 st = 0; uint#5 ctr = 0; while (1) { if (ctr == 0) { st = ~st; outp = st; } ctr++; } } // just to see if the circuit is runnging or not process blink(clkin uint#1 clk, rstin uint#1 rst, out uint#2 latch led) { uint#24 i = 0; while (1) { led = i#(23..22); i++; } } toplevel logicboy( // 50 MHz clock input ( to generate 16 KHz test clock ) in uint#1 pin period<20> clk_in, // led out uint#2 pin led, // for phase detection out uint#1 pin ph_out_u, out uint#1 pin ph_out_d, // test clock out uint#1 pin clk16k_out, // vco output clock out uint#1 pin clk16k_vco_out, // for vco inout uint#1 pin vco_pad1, inout uint#1 pin vco_pad2 ) { com uint#1 clk; com uint#1 clkpo, clkp, clkplocked, clkplockedn; com uint#1 rstn; com uint#1 clk16k, clk16k_vco; com uint#1 clk16k_o, clk16k_vco_o; clk16k_out = clk16k_o; clk16k_vco_out = clk16k_vco_o; BUFG(clk_in, clk); rstn = 0; /* This DCM generats 32MHz */ generic ( CLKDV_DIVIDE : 2.0, CLKFX_DIVIDE : 25, CLKFX_MULTIPLY : 15, CLKIN_DIVIDE_BY_2 : FALSE, CLKIN_PERIOD : 20.0, CLKOUT_PHASE_SHIFT : "NONE", CLK_FEEDBACK : "NONE", DESKEW_ADJUST : "SYSTEM_SYNCHRONOUS", DLL_FREQUENCY_MODE : "HIGH", DUTY_CYCLE_CORRECTION : FALSE, PHASE_SHIFT : 0, STARTUP_WAIT : FALSE ) DCM_SP(clkpo, clk, 0, 0, 0, rstn, clkplocked); BUFG(clkpo, clkp); // generate 16 KHz test clock test_clock(clkp, clkplocked, clk16k_o); BUFG(clk16k_o, clk16k); // just to see if the circuit is runnging or not blink(clkp, clkplocked, led); { com uint#1 pu, pd; com uint#1 vcoo; com uint#1 vco_clk; phase_detector(clk16k_vco , clk16k, pu, pd); OBUFT(0, pu, ph_out_u); OBUFT(1, pd, ph_out_d); vco(vco_pad1, vco_pad2, vcoo); BUFG(vcoo, vco_clk); counter(vco_clk, clkplocked, clk16k_vco_o); BUFG(clk16k_vco_o, clk16k_vco); } }