LIBRARY IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY DIVIDER IS
PORT(
CLK_IN : IN std_logic;
SYNC : IN std_logic;
CLK_OUT : OUT std_logic
);
END DIVIDER;
-- START DIVIDER
ARCHITECTURE RTL of DIVIDER is
signal i : integer range 0 to 24000000; -- 25 bit
signal j : integer range 0 to 5860; -- max divide at 1 hz
signal k : integer range 0 to 5860;
begin
process(CLK_IN) begin
if rising_edge(CLK_IN) then
i <= i +1;
end if;
end process;
process(CLK_IN, SYNC) begin
if rising_edge(SYNC) then
j <= i / 4096;
-- RESET i
end if;
end process;
process(CLK_IN) begin
if rising_edge(CLK_REF) then
if k = 0 then
CLK_OUT <= '1';
k <= j;
-- RESET j
else
CLK_OUT <= '0';
k <= k -1;
end if;
end if;
end process;
end RTL;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity divider is
port(
clk_in : in std_logic;
rstn : in std_logic;
sync : in std_logic;
clk_out : out std_logic
);
end divider;
-- start divider
architecture rtl of divider is
signal period_counter : std_logic_vector(24 downto 0); -- 25 bit counter to
-- measure sync period
signal count_latch : std_logic_vector(11 downto 0);
signal clock_out_cnt : std_logic_vector(11 downto 0);
signal sync_r, sync_rr : std_logic;
signal clock_out_cnt_zero : std_logic;
signal sync_rising, sync_rising_r : std_logic;
signal clk_out_int : std_logic;
begin
clock_out_cnt_zero <= not (clock_out_cnt(11) or clock_out_cnt(10) or clock_out_cnt(9)
or clock_out_cnt(8) or clock_out_cnt(7) or clock_out_cnt(6)
or clock_out_cnt(5) or clock_out_cnt(4) or clock_out_cnt(3)
or clock_out_cnt(2) or clock_out_cnt(1) or clock_out_cnt(0));
sync_rising_r <= (not sync_rr) and sync_r;
sync_rising <= (not sync_r) and sync;
clk_out <= clk_out_int;
process (clk_in, rstn)
begin -- process
if rstn = '0' then -- asynchronous reset (active low)
sync_r <= '0';
sync_rr <= '0';
elsif clk_in'event and clk_in = '1' then -- rising clock edge
sync_r <= sync;
sync_rr <= sync_r;
end if;
end process ;
period_counting: process (clk_in, rstn)
begin -- process period_counting
if rstn = '0' then -- asynchronous reset (active low)
period_counter <= (others => '0');
elsif clk_in'event and clk_in = '1' then -- rising clock edge
if sync_rising_r = '1' then
period_counter <= (others => '0');
else
period_counter <= period_counter + 1;
end if;
end if;
end process period_counting;
process (clk_in, rstn)
begin -- process
if rstn = '0' then -- asynchronous reset (active low)
clk_out_int <= '0';
count_latch <= (others => '0');
clock_out_cnt <= (others => '0');
elsif clk_in'event and clk_in = '1' then -- rising clock edge
if sync_rising = '1'then
count_latch <= period_counter(24 downto 13);
end if;
if clock_out_cnt_zero = '1' then
clk_out_int <= not clk_out_int;
clock_out_cnt <= count_latch;
else
clock_out_cnt <= clock_out_cnt - 1;
end if;
end if;
end process;
end rtl;
I will try this when I am at home. If it works I will be the happiest men on earth. I am tryin it for almost a week but can't get it fixed.nand_gates said:Here is my solution to ur problem.
At least one cycle of sync should be done befor this circuit generates
4096 pulsese at clk_out.
Hope this helps!
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity divider is
port(
clk_in : in std_logic;
rstn : in std_logic;
sync : in std_logic;
clk_out : out std_logic
);
end divider;
-- start divider
architecture rtl of divider is
signal period_counter : std_logic_vector(24 downto 0); -- 25 bit counter to
-- measure sync period
signal count_latch : std_logic_vector(11 downto 0);
signal clock_out_cnt : std_logic_vector(11 downto 0);
signal sync_r, sync_rr : std_logic;
signal clock_out_cnt_zero : std_logic;
signal sync_rising : std_logic;
signal clk_out_int : std_logic;
begin
clock_out_cnt_zero <= not (clock_out_cnt(11) or clock_out_cnt(10) or clock_out_cnt(9)
or clock_out_cnt(8) or clock_out_cnt(7) or clock_out_cnt(6)
or clock_out_cnt(5) or clock_out_cnt(4) or clock_out_cnt(3)
or clock_out_cnt(2) or clock_out_cnt(1) or clock_out_cnt(0));
sync_rising <= (not sync_rr) and sync_r;
clk_out <= clk_out_int;
process (clk_in, rstn)
begin -- process
if rstn = '0' then -- asynchronous reset (active low)
sync_r <= '0';
sync_rr <= '0';
elsif clk_in'event and clk_in = '1' then -- rising clock edge
sync_r <= sync;
sync_rr <= sync_r;
end if;
end process ;
period_counting: process (clk_in, rstn)
begin -- process period_counting
if rstn = '0' then -- asynchronous reset (active low)
period_counter <= (others => '0');
elsif clk_in'event and clk_in = '1' then -- rising clock edge
if sync_rising = '1' then
period_counter <= (others => '0');
else
period_counter <= period_counter + 1;
end if;
end if;
end process period_counting;
process (clk_in, rstn)
begin -- process
if rstn = '0' then -- asynchronous reset (active low)
clk_out_int <= '0';
count_latch <= (others => '0');
clock_out_cnt <= (others => '0');
elsif clk_in'event and clk_in = '1' then -- rising clock edge
if sync_rising = '1'then
count_latch <= period_counter(24 downto 13);
end if;
if clock_out_cnt_zero = '1' then
clk_out_int <= not clk_out_int;
clock_out_cnt <= count_latch;
else
clock_out_cnt <= clock_out_cnt - 1;
end if;
end if;
end process;
end rtl;
module top (CLK_IN, SYNC, CLK_OUT);
parameter ratio = 4096; // output/input frequency ratio
input CLK_IN, SYNC;
reg [2:0] qsync = 0; // anti-metastability shift register
reg sync_edge = 0; // detect rising edge of SYNC
reg [25:0] count = 0; // measure SYNC period
reg signed [25:0] sync_period = 0; // measured SYNC period
reg signed [25:0] rate_count = 0; // output rate accumulator
output reg CLK_OUT = 0;
always @ (posedge CLK_IN) begin
qsync <= {qsync,SYNC};
sync_edge <= ~qsync[2] & qsync[1];
count <= sync_edge ? 1 : count + 1;
sync_period <= sync_edge ? count : sync_period;
if (rate_count >= sync_period) begin
rate_count <= rate_count + ratio * 2 - sync_period;
CLK_OUT <= ~CLK_OUT;
end else
rate_count <= rate_count + ratio * 2;
end
endmodule
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity divider is
port(
clk_in : in std_logic;
rstn : in std_logic;
sync : in std_logic;
clk_out : out std_logic
);
end divider;
-- start divider
architecture rtl of divider is
signal period_counter : std_logic_vector(24 downto 0); -- 25 bit counter to
-- measure sync period
signal count_latch : std_logic_vector(12 downto 0);
signal clock_out_cnt : std_logic_vector(12 downto 0);
signal sync_r, sync_rr : std_logic;
signal clock_out_cnt_zero : std_logic;
signal sync_rising : std_logic;
signal clk_out_int : std_logic;
begin
clock_out_cnt_zero <= not (clock_out_cnt(11) or clock_out_cnt(10) or clock_out_cnt(9)
or clock_out_cnt(8) or clock_out_cnt(7) or clock_out_cnt(6)
or clock_out_cnt(5) or clock_out_cnt(4) or clock_out_cnt(3)
or clock_out_cnt(2) or clock_out_cnt(1) or clock_out_cnt(0));
sync_rising <= (not sync_rr) and sync_r;
clk_out <= clk_out_int;
process (clk_in, rstn)
begin -- process
if rstn = '0' then -- asynchronous reset (active low)
sync_r <= '0';
sync_rr <= '0';
elsif clk_in'event and clk_in = '1' then -- rising clock edge
sync_r <= sync;
sync_rr <= sync_r;
end if;
end process ;
period_counting: process (clk_in, rstn)
begin -- process period_counting
if rstn = '0' then -- asynchronous reset (active low)
period_counter <= (others => '0');
elsif clk_in'event and clk_in = '1' then -- rising clock edge
if sync_rising = '1' then
period_counter <= (others => '0');
else
period_counter <= period_counter + 1;
end if;
end if;
end process period_counting;
process (clk_in, rstn)
begin -- process
if rstn = '0' then -- asynchronous reset (active low)
clk_out_int <= '0';
count_latch <= (others => '0');
clock_out_cnt <= (others => '0');
elsif clk_in'event and clk_in = '1' then -- rising clock edge
if sync_rising = '1'then
count_latch <= period_counter(24 downto 12);
end if;
if clock_out_cnt_zero = '1' then
clock_out_cnt <= count_latch;
else
clock_out_cnt <= clock_out_cnt - 1;
end if;
if clock_out_cnt_zero = '1' or clock_out_cnt = ('0'&count_latch(12 downto 1)) then
clk_out_int <= not clk_out_int;
end if;
end if;
end process;
end rtl;
This works very well, the only problem I have is that I use a EPM570 CPLD from altera which has only 570 Logic Elements, your solution uses almost twice as much LE's as the solution that nand_gates found. It works much better but I dont have enough free LE's to use your solution in my architecture.echo47 said:I don't speak VHDL, but maybe you can use this Verilog. It measures the frequency of SYNC by counting the period between the last two rising edges, and then outputs a (slightly jittery) square wave at "ratio" times that frequency. It's a frequency lock, not a phase lock.
The accuracy improved but maybe dividing by 1024 makes it even better and I should have enough LE's to do that. So my last question is to make a version that divides through 1024.nand_gates said:Little improved code. Here instead of 8192 I am dividing by 4096.
LIBRARY IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY DIVIDER IS
PORT(
CLK_IN : IN std_logic;
RESET : IN std_logic;
SYNC : IN std_logic;
CLK_OUT : OUT std_logic
);
END DIVIDER;
-- start divider
ARCHITECTURE RTL of DIVIDER is
SIGNAL period_counter : std_logic_vector(24 downto 0); -- 25 bit counter to measure SYNC period
SIGNAL CNT_LATCH : std_logic_vector(12 downto 0);
SIGNAL CLK_OUT_CNT : std_logic_vector(12 downto 0);
SIGNAL SYNC_r, SYNC_rr : std_logic;
SIGNAL CLK_OUT_CNT_ZERO : std_logic;
SIGNAL SYNC_rising, SYNC_rising_r : std_logic;
SIGNAL CLK_OUT_int : std_logic;
SIGNAL CNT_REST : std_logic_vector(11 downto 0);
SIGNAL USE_REST : std_logic;
begin
CLK_OUT_CNT_ZERO <= not (CLK_OUT_CNT(11) or CLK_OUT_CNT(10) or CLK_OUT_CNT(9) or CLK_OUT_CNT(8) or CLK_OUT_CNT(7) or CLK_OUT_CNT(6) or CLK_OUT_CNT(5) or CLK_OUT_CNT(4) or CLK_OUT_CNT(3) or CLK_OUT_CNT(2) or CLK_OUT_CNT(1) or CLK_OUT_CNT(0));
SYNC_rising_r <= (not SYNC_rr) and SYNC_r;
SYNC_rising <= (not SYNC_r) and SYNC;
CLK_OUT <= CLK_OUT_int;
process (CLK_IN, RESET) begin -- process
if RESET = '1' then
SYNC_r <= '0';
SYNC_rr <= '0';
elsif CLK_IN'event and CLK_IN = '1' then -- rising clock edge
SYNC_r <= SYNC;
SYNC_rr <= SYNC_r;
end if;
end process;
process (CLK_IN, RESET) begin -- process period_counting
if RESET = '1' then
period_counter <= (others => '0');
elsif CLK_IN'event and CLK_IN = '1' then -- rising clock edge
if SYNC_rising_r = '1' then
period_counter <= (others => '0');
else
period_counter <= period_counter + 1;
end if;
end if;
end process;
process (CLK_IN, RESET) begin -- process
if RESET = '1' then
CLK_OUT_int <= '0';
CNT_LATCH <= (others => '0');
CLK_OUT_CNT <= (others => '0');
elsif CLK_IN'event and CLK_IN = '1' then -- rising clock edge
if SYNC_rising = '1' then
CNT_LATCH <= period_counter(24 downto 12);
CNT_REST <= period_counter(11 downto 0);
elsif CLK_OUT_CNT_ZERO = '1' then
if CNT_REST >= (CNT_LATCH + 1) then
CNT_REST <= CNT_REST - (CNT_LATCH + 1);
USE_REST <= '1';
else
USE_REST <= '0';
end if;
end if;
if CLK_OUT_CNT_ZERO = '1' then
CLK_OUT_CNT <= (CNT_LATCH + USE_REST);
else
CLK_OUT_CNT <= CLK_OUT_CNT - 1;
end if;
if CLK_OUT_CNT_ZERO = '1' or CLK_OUT_CNT = ('0'&CNT_LATCH(12 downto 1)) then
CLK_OUT_int <= not CLK_OUT_int;
end if;
end if;
end process;
end rtl;
Well currently I am using the principe of your verilogfile into my own VHDL file because your solution is technicaly very good. The only problem I had was that it took me 1 full day to understand the exact working of your verilog file. But after that I realised that your solution is the best I can imagine. So I started rewriting your verilog file to a VHDL solution. And will try to save some LE's by dividing the input through 16 before I use the signal. I have also had a better specification of the SYNC signal, it will be between 40 and 120hz. The only thing thats important right now is that the output gives 4096 +- 1 pulses between the sync, the glitches aren't really a problem.echo47 said:If you add more arithmetic to your VHDL to improve its behavior, the number of logic elements will certainly grow. But try it and see! You may find a more efficient solution than my Verilog.
I can't think of any way to significantly simplify my Verilog module. Rearranging the arithmetic expressions may help qu(at)rtus optimize it better. (That sometimes happens with the Xilinx XST synthesizer.) Unfortunately, I don't have qu(at)rtus to try such experiments.
I'm looking back at your original message ... You never said that the output frequency needs to be 4096 times the input frequency. I assumed you needed a frequency multiplier, but is that correct? Would it be acceptable to simply generate a burst of 4096 high-speed pulses after each input pulse?
module top (CLK_IN, SYNC, CLK_OUT);
parameter xbits = 0; // more bits reduces the burst frequency
input CLK_IN, SYNC;
reg [1:0] qsync = 0; // anti-metastability shift register
reg sync_edge = 0; // detect rising edge of SYNC
reg [12+xbits:0] count = 0;
output CLK_OUT; // a burst of 4096 pulses
assign CLK_OUT = count[xbits];
always @ (posedge CLK_IN) begin
qsync <= {qsync,SYNC};
sync_edge <= ~qsync[1] & qsync[0];
count <= count ? count + 1 : count + sync_edge;
end
endmodule
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity sync is
generic (
xbits : integer := 0);
port (
CLK_IN : in std_logic;
SYNC : in std_logic;
CLK_OUT : out std_logic);
end sync;
architecture behave of sync is
signal qsync : std_logic_vector(1 downto 0) := "00"; -- anti-metastability shift register
signal sync_edge : std_logic := '0'; -- detect rising edge of SYNC
signal count : std_logic_vector(12+xbits downto 0) := (others => '0');
constant count_zero : std_logic_vector(12+xbits downto 0) := (others=>'0');
begin -- behave
process (CLK_IN)
begin -- process
if CLK_IN'event and CLK_IN = '1' then -- rising clock edge
qsync <= qsync(0)&SYNC;
sync_edge <= not qsync(1) and qsync(0);
if (count /= count_zero) then
count <= count + 1;
else
count <= count + sync_edge;
end if;
end if;
end process;
end behave;
LIBRARY IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY DIVIDER IS
PORT(
CLK_IN : IN std_logic;
RESET : IN std_logic;
SYNC : IN std_logic;
CLK_OUT : OUT std_logic
);
END DIVIDER;
-- start divider
ARCHITECTURE RTL of DIVIDER is
SIGNAL qsync : std_logic_vector(2 downto 0); -- anti-metastability shift register
SIGNAL sync_edge : std_logic; -- detect rising edge of SYNC
SIGNAL count : std_logic_vector(24 downto 0); -- 25 bit counter to measure SYNC period
SIGNAL sync_period : std_logic_vector(24 downto 0); -- 25 bit memory for measured SYNC period
SIGNAL rate_count : std_logic_vector(24 downto 0); -- output rate accumulator
SIGNAL CLK_OUT_int : std_logic;
begin
CLK_OUT <= CLK_OUT_int;
process (CLK_IN, RESET) begin -- process
if RESET = '1' then
qsync <= (others => '0');
sync_edge <= '0';
count <= (others => '0');
sync_period <= (others => '0');
rate_count <= (others => '0');
CLK_OUT_int <= '0';
elsif CLK_IN'event and CLK_IN = '1' then -- rising clock edge
qsync(0) <= SYNC;
qsync(1) <= qsync(0);
qsync(2) <= qsync(1);
sync_edge <= (not qsync(2)) and qsync(1);
if sync_edge = '1' then
sync_period <= count;
count <= (others => '0');
else
count <= count + '1';
end if;
if rate_count >= sync_period then
rate_count <= rate_count + 8192 - sync_period;
CLK_OUT_int <= not CLK_OUT_int;
else
rate_count <= rate_count + 8192;
end if;
end if;
end process;
end rtl;
module lock(CLK_IN, SYNC, CLK_OUT);
parameter delta = 2;
parameter lb_ratio = 12; //2**12 = 4096
parameter lb_reso = 20; //25 Mhz/40 Hz = 625E3 , lb(625E3) = 19,25-> 2**20
parameter lb_cnt = lb_reso - lb_ratio;
parameter cnt_init = 10;
input CLK_IN;
input SYNC;
output reg CLK_OUT = 0;
reg [lb_cnt-2:0] cnt = cnt_init;
reg [lb_cnt-2:0] cnt_load = cnt_init; //clocks per toggle //25/40 * 10**6 / (2*ratio);
reg [lb_ratio:0] r_cnt = 0; //output half-clocks(toggle) per sync (set for fractional frequency)
reg [1:0] qsync = 0;
reg sync_flag=0;
always @(posedge CLK_IN)
begin
qsync <= {qsync,SYNC};
if(~qsync[1] & qsync[0]) sync_flag =1;
cnt = cnt - 1;
if(!cnt)
begin
CLK_OUT = ~CLK_OUT;
cnt = cnt_load;
r_cnt = r_cnt - 1;
if(!r_cnt || sync_flag)
begin
cnt_load = !(r_cnt) ? cnt_load + delta : cnt_load - delta;
sync_flag = 0;
end
end
end
endmodule
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?