MMCM reset

From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA Project was completed in May 2017

If you need to switch clock speeds you can reprogram the MMCM on the fly. Here's an example of changing the division factor for CLKOUT0/CLKOUT0B

Update: It looks like you don't have to reset the MMCM if you only change the divisor (which sort of makes sense, as the VCO frequency stays the same). To do this, just remove the 'rst' signal. This will keep the MMCM 'lock' signal asserted.


mmcm_reset.vhd

--------------------------------------------------------------------------------------------------------
-- Playing with the MMCM DRP ports on the Artix-7 FPGA
--
-- Author: Mike Field <hamster@snap.net.nz>
--
-- This reprograms and then resets the MMCM to change division factor for the CLKOUT0/CLKOUT0B
-- signal.
--
-- see https://www.xilinx.com/support/documentation/application_notes/xapp888_7Series_DynamicRecon.pdf
-- for the dynamic Reconviguration Port addresses and definitions
--------------------------------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity mmcm_reset is
    Port ( clk_100 : in STD_LOGIC;
           btn_raw : in STD_LOGIC;
           led     : out STD_LOGIC_VECTOR (15 downto 0));
end mmcm_reset;

architecture Behavioral of mmcm_reset is
    signal btn_meta     : std_logic := '0';
    signal btn          : std_logic := '0';
    signal speed_select : std_logic := '0';
    signal counter      : unsigned(26 downto 0) := (others => '0');
    signal debounce     : unsigned(15 downto 0) := (others => '0');
    signal clk_switched : std_logic := '0';
    signal clk_fb       : std_logic := '0';
    
    type t_state is (state_idle_fast, state_go_slow_1, state_go_slow_2, state_go_slow_3,
                       state_idle_slow, state_go_fast_1, state_go_fast_2, state_go_fast_3);
    signal state   : t_state := state_idle_fast;
    
    
    -----------------------------------------------------------------------------
    --- This is the CLKOUT0 ClkReg1 address - the only register to be played with 
    -----------------------------------------------------------------------------
    signal daddr : std_logic_vector(6 downto 0) := "0001000";
    signal do    : std_logic_vector(15 downto 0) := (others => '0');
    signal drdy  : std_logic := '0';
    signal den   : std_logic := '0';
    signal di    : std_logic_vector(15 downto 0) := (others => '0');
    signal dwe   : std_logic := '0';
    signal rst   : std_logic := '0';
            
begin


   MMCME2_ADV_inst : MMCME2_ADV
   generic map (
      BANDWIDTH => "OPTIMIZED",      -- Jitter programming (OPTIMIZED, HIGH, LOW)
      CLKFBOUT_MULT_F => 10.0,        -- Multiply value for all CLKOUT (2.000-64.000).
      CLKFBOUT_PHASE => 0.0,         -- Phase offset in degrees of CLKFB (-360.000-360.000).
      -- CLKIN_PERIOD: Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz).
      CLKIN1_PERIOD => 10.0,
      CLKIN2_PERIOD => 0.0,
      -- CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for CLKOUT (1-128)
      CLKOUT1_DIVIDE => 1,
      CLKOUT2_DIVIDE => 1,
      CLKOUT3_DIVIDE => 1,
      CLKOUT4_DIVIDE => 1,
      CLKOUT5_DIVIDE => 1,
      CLKOUT6_DIVIDE => 1,
      CLKOUT0_DIVIDE_F => 10.0,       -- Divide amount for CLKOUT0 (1.000-128.000).
      -- CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for CLKOUT outputs (0.01-0.99).
      CLKOUT0_DUTY_CYCLE => 0.5,
      CLKOUT1_DUTY_CYCLE => 0.5,
      CLKOUT2_DUTY_CYCLE => 0.5,
      CLKOUT3_DUTY_CYCLE => 0.5,
      CLKOUT4_DUTY_CYCLE => 0.5,
      CLKOUT5_DUTY_CYCLE => 0.5,
      CLKOUT6_DUTY_CYCLE => 0.5,
      -- CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for CLKOUT outputs (-360.000-360.000).
      CLKOUT0_PHASE => 0.0,
      CLKOUT1_PHASE => 0.0,
      CLKOUT2_PHASE => 0.0,
      CLKOUT3_PHASE => 0.0,
      CLKOUT4_PHASE => 0.0,
      CLKOUT5_PHASE => 0.0,
      CLKOUT6_PHASE => 0.0,
      CLKOUT4_CASCADE => FALSE,      -- Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE)
      COMPENSATION => "ZHOLD",       -- ZHOLD, BUF_IN, EXTERNAL, INTERNAL
      DIVCLK_DIVIDE => 1,            -- Master division value (1-106)
      -- REF_JITTER: Reference input jitter in UI (0.000-0.999).
      REF_JITTER1 => 0.0,
      REF_JITTER2 => 0.0,
      STARTUP_WAIT => FALSE,         -- Delays DONE until MMCM is locked (FALSE, TRUE)
      -- Spread Spectrum: Spread Spectrum Attributes
      SS_EN => "FALSE",              -- Enables spread spectrum (FALSE, TRUE)
      SS_MODE => "CENTER_HIGH",      -- CENTER_HIGH, CENTER_LOW, DOWN_HIGH, DOWN_LOW
      SS_MOD_PERIOD => 10000,        -- Spread spectrum modulation period (ns) (VALUES)
      -- USE_FINE_PS: Fine phase shift enable (TRUE/FALSE)
      CLKFBOUT_USE_FINE_PS => FALSE,
      CLKOUT0_USE_FINE_PS => FALSE,
      CLKOUT1_USE_FINE_PS => FALSE,
      CLKOUT2_USE_FINE_PS => FALSE,
      CLKOUT3_USE_FINE_PS => FALSE,
      CLKOUT4_USE_FINE_PS => FALSE,
      CLKOUT5_USE_FINE_PS => FALSE,
      CLKOUT6_USE_FINE_PS => FALSE 
   )
   port map (
      -- Clock Outputs: 1-bit (each) output: User configurable clock outputs
      CLKOUT0  => clk_switched, CLKOUT0B => open,
      CLKOUT1  => open,         CLKOUT1B => open,
      CLKOUT2  => open,         CLKOUT2B => open,
      CLKOUT3  => open,         CLKOUT3B => open,
      CLKOUT4  => open,          
      CLKOUT5  => open,
      CLKOUT6  => open,
      -- Dynamic Phase Shift Ports: 1-bit (each) output: Ports used for dynamic phase shifting of the outputs
      PSDONE => open,
      -- Feedback Clocks: 1-bit (each) output: Clock feedback ports
      CLKFBOUT => clk_fb,
      CLKFBOUTB => open,
      -- Status Ports: 1-bit (each) output: MMCM status ports
      CLKFBSTOPPED => open,
      CLKINSTOPPED => open,
      LOCKED       => open,
      -- Clock Inputs: 1-bit (each) input: Clock inputs
      CLKIN1   => clk_100,
      CLKIN2   => '0', 
      -- Control Ports: 1-bit (each) input: MMCM control ports
      CLKINSEL => '1',
      PWRDWN   => '0',             -- 1-bit input: Power-down
      RST      => rst,                   -- 1-bit input: Reset

      -- DRP Ports: 16-bit (each) output: Dynamic reconfiguration ports
      DCLK  => clk_100,                 -- 1-bit input: DRP clock
      DO    => DO,                     -- 16-bit output: DRP data
      DRDY  => DRDY,                 -- 1-bit output: DRP ready
      -- DRP Ports: 7-bit (each) input: Dynamic reconfiguration ports
      DADDR => DADDR,               -- 7-bit input: DRP address
      DEN   => DEN,                   -- 1-bit input: DRP enable
      DI    => DI,                     -- 16-bit input: DRP data
      DWE   => DWE,                   -- 1-bit input: DRP write enable
      
 
      -- Dynamic Phase Shift Ports: 1-bit (each) input: Ports used for dynamic phase shifting of the outputs
      PSCLK    => '0',
      PSEN     => '0',
      PSINCDEC => '0',
      -- Feedback Clocks: 1-bit (each) input: Clock feedback ports
      CLKFBIN => clk_fb
   );

speed_change_fsm: process(clk_100)
    begin
        ---------------------------------------------------------------------
        --- This FSM changes the division factor for the MMCM, then resets it
        ---------------------------------------------------------------------
        if rising_edge(clk_100) then
            di <= (others => '0');
            dwe <= '0';
            den <= '0';  
            case state is
                when state_idle_fast =>
                    if speed_select = '1'then
                       state <= state_go_slow_1;
                       daddr <=  "0001000";  -- The CLKOUT0 ClkReg1 address
                       --               High 5      Low 5
                       di    <= "0001" & "000101" & "000101";
                       dwe   <= '1';
                       den   <= '1';  
                    end if;
                when state_go_slow_1 =>
                    if  drdy = '1' then
                        state <= state_go_slow_2;
                    end if;
                when state_go_slow_2 =>
                    rst <= '1';
                    state <= state_go_slow_3;
                when state_go_slow_3 =>
                    rst <= '0';
                    state <= state_idle_slow;
                    
                when state_idle_slow =>
                    di <= (others => '0');
                    if speed_select = '0' and drdy = '0' then
                       state <= state_go_fast_1;
                       daddr <=  "0001000";  -- The CLKOUT0 ClkReg1 address
                       --              High 20     Low 20 
                       di  <= "0001" & "010011" & "010011";
                       dwe <= '1';
                       den <= '1';  
                    end if;
                when state_go_fast_1 =>
                    if  drdy = '1' then
                        state <= state_go_fast_2;
                    end if;
                when state_go_fast_2 =>
                    rst <= '1';
                    state <= state_go_fast_3;
                when state_go_fast_3 =>
                    rst <= '0';
                    state <= state_idle_fast;    
            end case;
        end if;
    end process;
 
   ----------------------------------------------
   -- A proper debounce for hhe button, to set
   -- speed_select, including a synchronizer
   ----------------------------------------------    
dbounce_proc: process(clk_100)
    begin
        if rising_edge(clk_100) then
            if speed_select = btn then
                debounce <= (others => '0');
            elsif debounce(debounce'high) = '1' then
                speed_select <= not speed_select;
            else
                debounce <= debounce + 1;
            end if;
            -- Syncronise the button
            btn      <= btn_meta;
            btn_meta <= btn_raw;
        end if;
    end process;

   ------------------------------------------
   -- Something to update the LEDs, to show
   --  the current clock speed
   -----------------------------------------
show_speed_proc: process(clk_switched) 
    begin
        if rising_edge(clk_switched) then
            counter <= counter + 1;            
            led(7 downto 0) <= std_logic_vector(counter(counter'high downto counter'high-7));
        end if;
    end process;
    
    ----------------------------------
    -- Show the debounced button state
    ----------------------------------
    led(15) <= speed_select;
end Behavioral;

basys3.xdc

set_property PACKAGE_PIN W5 [get_ports clk_100]	
set_property IOSTANDARD LVCMOS33 [get_ports clk_100]
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk_100]

set_property PACKAGE_PIN U18 [get_ports btn_raw]						
set_property IOSTANDARD LVCMOS33 [get_ports btn_raw]

set_property PACKAGE_PIN U16 [get_ports {led[0]}]					
set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]
set_property PACKAGE_PIN E19 [get_ports {led[1]}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}]
set_property PACKAGE_PIN U19 [get_ports {led[2]}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}]
set_property PACKAGE_PIN V19 [get_ports {led[3]}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}]
set_property PACKAGE_PIN W18 [get_ports {led[4]}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {led[4]}]
set_property PACKAGE_PIN U15 [get_ports {led[5]}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {led[5]}]
set_property PACKAGE_PIN U14 [get_ports {led[6]}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {led[6]}]
set_property PACKAGE_PIN V14 [get_ports {led[7]}]                    
set_property IOSTANDARD LVCMOS33 [get_ports {led[7]}]
set_property PACKAGE_PIN V13 [get_ports {led[8]}]					
set_property IOSTANDARD LVCMOS33 [get_ports {led[8]}]
set_property PACKAGE_PIN V3 [get_ports {led[9]}]					
set_property IOSTANDARD LVCMOS33 [get_ports {led[9]}]
set_property PACKAGE_PIN W3 [get_ports {led[10]}]					
set_property IOSTANDARD LVCMOS33 [get_ports {led[10]}]
set_property PACKAGE_PIN U3 [get_ports {led[11]}]					
set_property IOSTANDARD LVCMOS33 [get_ports {led[11]}]
set_property PACKAGE_PIN P3 [get_ports {led[12]}]					
set_property IOSTANDARD LVCMOS33 [get_ports {led[12]}]
set_property PACKAGE_PIN N3 [get_ports {led[13]}]					
set_property IOSTANDARD LVCMOS33 [get_ports {led[13]}]
set_property PACKAGE_PIN P1 [get_ports {led[14]}]					
set_property IOSTANDARD LVCMOS33 [get_ports {led[14]}]
set_property PACKAGE_PIN L1 [get_ports {led[15]}]					
set_property IOSTANDARD LVCMOS33 [get_ports {led[15]}]	

Personal tools