VHDL时钟分频器,用于控制占空比和相位

时间:2019-01-11 19:58:11

标签: vhdl

我正在使用高速时钟(来自内部PLL),并试图对其进行分频以生成2个时钟,它们具有不同的占空比和相位关系。如果我单步输入时钟,代码将正确运行。随着频率的增加,辅助输出的相位和占空比(代码样本中的iDM_out)会损坏。在某些频率下,次级输出的占空比将是正确的。在其他频率下,占空比可能达到90%或199%。同相位关系(DMDelay)。我似乎有一些有关时钟缓冲器需求的文章,所以我在输出上尝试了几种类型的BUFF,CLKBUF和CLKINT,这似乎使情况变得更糟。是否有人对造成这种情况的原因有任何想法?

use work.A208_pckgs.all;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity DutyPhaseMod is
    port (
        rst     : in std_logic; 
        GLA     : in std_logic;     -- GLA is 36x faster than target frequency
        EXDuty  : in std_logic_vector(4 downto 0);  -- the number of GLA clock cycles for the EX duty cycle
        DMDuty  : in std_logic_vector(4 downto 0);  -- the number of GLA clock cycles for the DM duty cycle
        DMDelay : in std_logic_vector(4 downto 0);  -- the number of GLA clock cycles for the DM phase delay

        EX_out  : out std_logic;
        DM_out  : out std_logic
    );                   
end entity;

architecture behavioral of DutyPhaseMod is
    signal iGLA     : std_logic;
    signal iFREQlen : integer range 0 to 35;
begin
    process (rst, GLA)
        variable iEX_out    : std_logic;
        variable iDM_out    : std_logic;
        variable iEXctr     : natural range 0 to 35;
        variable iDMctr     : natural range 0 to 35;
    begin
        iFREQlen <= 35;                             -- number of clock cycles

        if rst = '1' then                           -- reset the counters on reset signal
            iEXctr  := 0;
            iDMctr  := 0;
        elsif rising_edge(GLA) then
            if iEXctr <= unsigned(EXDuty) then      -- first part of EX the duty cycle
                iEX_out := '1';             
                iEXctr := iEXctr + 1;
            elsif iEXctr < iFREQlen then            -- second part of EX duty cycle
                iEX_out := '0';
                iEXctr := iEXctr + 1;
            else                                    -- set for the start of the next cycle
                iEX_out := '1'; 
                iEXctr := 0;
            end if;

            if iEXctr = unsigned(DMDelay) then      -- reset for DM phase offset
                iDMctr := 0;                            
            elsif iDMctr <= unsigned(DMDuty) then   -- first part of the DM duty cycle
                iDM_out := '1';
                iDMctr := iDMctr + 1;
            elsif iDMctr <= iFREQlen - 1 then       -- second part of the DM duty cycle
                iDM_out := '0';
                iDMctr := iDMctr + 1;
            else                                    -- set for the start of the next cycle
                iDM_out := '1';
            end if;

            EX_out <= iEX_out;
            DM_out <= iDM_out;

        end if;
    end process;
end behavioral;

1 个答案:

答案 0 :(得分:0)

我要弯腰回答自己的问题。如果您认为我的答案不正确(或可以进一步添加/阐明),请随时发表评论。我决定将我的实体分为两个过程,并且看来工作正常。第一个过程在高速时钟的rising_edge上处理基本时钟划分。第二个过程在高速时钟的下降沿处理辅助(相位延迟)时钟。

        library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

    entity DutyPhaseMod is
        port (
            rst     : in std_logic; 
            GLA     : in std_logic;     
            EXDuty  : in std_logic_vector(3 downto 0);
            DMDuty  : in std_logic_vector(3 downto 0);
            DMDelay : in std_logic_vector(4 downto 0);

            EX_out  : out std_logic;
            DM_out  : out std_logic
        );                   
    end entity;

    architecture behavioral of DutyPhaseMod is
        signal iGLA     : std_logic;
        signal iFREQlen : integer range 0 to 35;
        signal iEXctr   : natural range 0 to 35;
    begin
        process (rst, GLA)
            variable iEX_out    : std_logic;
        begin
            iFREQlen <= 35;

            if rst = '1' then
                iEXctr  <= 0;
            elsif rising_edge(GLA) then

                if iEXctr <= unsigned(EXDuty) then
                    iEX_out := '1';                         --
                    iEXctr <= iEXctr + 1;
                elsif iEXctr < iFREQlen then
                    iEX_out := '0';
                    iEXctr <= iEXctr + 1;
                else
                    iEX_out := '1';
                    iEXctr <= 0;
                end if;

                EX_out <= iEX_out;
            end if;
        end process;

        process (rst, GLA)
            variable iDM_out    : std_logic;
            variable iDMctr     : natural range 0 to 30;
        begin
            case FW_FREQ is
            when F_46 =>
                iFREQlen <= 35;
            when F_82 =>
                iFREQlen <= 23;
            end case;

            if rst = '1' then
                iDMctr  := 0;
            elsif falling_edge(GLA) then
                if iEXctr = unsigned(DMDelay) then  
                    iDMctr := 0;                
                elsif iDMctr <= unsigned(DMDuty) then
                    iDM_out := '1';
                    iDMctr := iDMctr + 1;
                elsif iDMctr <= iFREQlen - 1 then
                    iDM_out := '0';
                    iDMctr := iDMctr + 1;
                else
                    iDM_out := '1';
                end if;

                DM_out <= iDM_out;
            end if;
        end process;
    end behavioral;