Xilinx FPGA에서 VHDL에서 50MHz를 2Hz로 나누는 방법


13

자일링스 FPGA 보드와 50MHz 크리스털이있다. VHDL에서 2Hz로 나눌 필요가 있습니다. 어떻게해야합니까?


13
그래서 실제로 무엇을 시도 했습니까?
매트 영

Xilinx 시계 관리자 IP를 사용하지 않는 이유는 무엇입니까?
Arturs Vancans 2013 년

답변:


19

기본적으로 두 가지 방법이 있습니다. 첫 번째는 Xilinx 기본 클록 합성기 코어를 사용하는 것입니다. 이것의 장점 중 하나는 Xlinx 도구가 시계를 그대로 인식하고 필요한 경로를 통해 라우팅한다는 것입니다. 이 도구는 모든 타이밍 제약 조건도 처리합니다 (이 경우 2Hz 클록이므로 실제로 적용 할 수 없음).

두 번째 방법은 느린 클럭주기의 절반이 지날 때까지 카운터를 사용하여 더 빠른 클럭 펄스 수를 계산하는 것입니다. 예를 들어, 느린 클록주기의 한 클록주기를 구성하는 고속 클록 펄스의 수는 50000000/2 = 25000000입니다. 클록주기의 절반을 원하므로 반주기마다 25000000/2 = 12500000입니다. . (각 높거나 낮은 기간).

VHDL의 모습은 다음과 같습니다.

library IEEE;
use IEEE.STD_LOGIC_1164.all;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.all;

entity scale_clock is
  port (
    clk_50Mhz : in  std_logic;
    rst       : in  std_logic;
    clk_2Hz   : out std_logic);
end scale_clock;

architecture Behavioral of scale_clock is

  signal prescaler : unsigned(23 downto 0);
  signal clk_2Hz_i : std_logic;
begin

  gen_clk : process (clk_50Mhz, rst)
  begin  -- process gen_clk
    if rst = '1' then
      clk_2Hz_i   <= '0';
      prescaler   <= (others => '0');
    elsif rising_edge(clk_50Mhz) then   -- rising clock edge
      if prescaler = X"BEBC20" then     -- 12 500 000 in hex
        prescaler   <= (others => '0');
        clk_2Hz_i   <= not clk_2Hz_i;
      else
        prescaler <= prescaler + "1";
      end if;
    end if;
  end process gen_clk;

clk_2Hz <= clk_2Hz_i;

end Behavioral;

참고 사항 :

  • 리셋하는 동안 생성 된 클럭은 0입니다. 이것은 일부 응용 프로그램에는 적합하지만 다른 응용 프로그램에는 적합하지 않으며 시계에 필요한 것에 따라 다릅니다.
  • 생성 된 클럭은 Xilinx 합성 툴에 의해 일반 신호로 라우팅됩니다.
  • 2Hz는 매우 느립니다. 잠시 시뮬레이션하는 데 시간이 걸립니다. 적은 양의 코드이므로 1 초 동안 시뮬레이션하는 것이 비교적 빠르지 만 코드 추가를 시작하면 2Hz의 클럭주기를 시뮬레이션하는 데 걸리는 시간이 상당히 길어질 수 있습니다.

편집 : clk_2Hz_i는 출력 신호를 버퍼링하는 데 사용됩니다. VHDL은 출력 일 때 할당 오른쪽의 신호를 사용하지 않습니다.


1
나쁘지 않은,하지만 당신은 / 그래서, 정수와 부호없는 비교 추가 할 수 있습니다 if prescaler = 50_000_000/4 then ...그리고 prescaler <= prescaler + 1;조금 더 간단 할 것이다.
Brian Drummond

@StaceyAnne 이것을 시도하면 " 'clr_o'out '객체를 읽을 수 없습니다.'buffer '또는'inout '을 사용하십시오'라는 메시지가 나타납니다.
회피

@evading, 출력에 버퍼가 필요합니다. VHDL은 clk_2Hz출력 이라는 사실을 좋아하지 않지만이 줄에서 값을 읽습니다 clk_2Hz <= not clk_2Hz;. 수정 프로그램에서 편집했습니다.
stanri

+1 좋은 예입니다. 그러나 여기 내 무지가 나타나는 곳이 있습니다 (VHDL에 처음 임). 차이점은 무엇이며 prescaler <= (others => '0');그리고 prescaler <= '0';?
cbmeeks

NVM! 나는 others가지고있는 VHDL 책을 읽을 때 사용 했던 것을 완전히 놓쳤다 . "000000000000000000 ...."등과 같은 것을 사용하는 대신 모든 "기타"비트를 공통 값으로 선언하기위한 지름길입니다.
cbmeeks

9

클럭 프리스케일러를 사용하십시오.

프리스케일러 값은 (clock_speed / desired_clock_speed) / 2이므로 (50Mhz (50,000,000) / 2hz (2)) / 2 = 12,500,000이며 이진수는 101111101011110000100000입니다.

더 간단히 말하면 (50,000,000) / 2) / 2 = 12,500,000 이진수로 변환-> 101111101011110000100000

해야 할 일의 코드는 다음과 같습니다. 2hz가 필요한 곳에 newClock을 사용하십시오.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ClockPrescaler is
    port(
        clock   : in STD_LOGIC; -- 50 Mhz
        Led     : out STD_LOGIC
    );
end ClockPrescaler;

architecture Behavioral of ClockPrescaler is
    -- prescaler should be (clock_speed/desired_clock_speed)/2 because you want a rising edge every period
    signal prescaler: STD_LOGIC_VECTOR(23 downto 0) := "101111101011110000100000"; -- 12,500,000 in binary
    signal prescaler_counter: STD_LOGIC_VECTOR(23 downto 0) := (others => '0');
    signal newClock : std_logic := '0';
begin

    Led <= newClock;

    countClock: process(clock, newClock)
    begin
        if rising_edge(clock) then
            prescaler_counter <= prescaler_counter + 1;
            if(prescaler_counter > prescaler) then
                -- Iterate
                newClock <= not newClock;

                prescaler_counter <= (others => '0');
            end if;
        end if;
    end process;


end Behavioral;

0.5Hz와 1Hz 중 하나의 클럭을 생성하는 것처럼 보입니까? (시계 기간이 프리스케일러이므로 * 2?). 또한 slvs를 추가하고 있기 때문에 "+"는 오류를 발생시킵니다. 어쨌든이 방법으로 add의 overflow 속성을 사용하는 것이 확실하지 않습니다. 왜 newClock : std_logic := '0'프리스케일러 / 2로 올라가서 할당하지 newClk <= not newClk않겠습니까?
stanri

고마워, 내 논리는 조금 벗어났다. 나는 테스트 된 코드와 제안 사항 중 일부를 사용하여 초기 게시물을 업데이트했습니다. :)
MLM

Ugh-모든 1과 0과 그것이 실제로 무엇인지 말하는 주석! 왜 컴파일러를 사용하여 그렇게하지 않습니까 ??? 어쨌든 정수를 사용하지 않는 이유는 무엇입니까?
Martin Thompson

틀릴 수도 있지만 ": = (others => '0')"과 같이 arhitecture에서 신호를 정의 할 때 기본값을 사용하는 것은 합성 할 수 없다고 생각합니다.
Arturs Vancans 2014 년

합성 가능하지만 기본적으로 Xilinx, Altera 또는 Lattice와 같은 SRAM 기반 FPGA에서만 작동합니다.
Yann Vernier

8

일반적으로 실제로 느린 것을 클럭하고 싶지 않고 올바른 속도로 활성화를 만들고 로직에서 사용하십시오.

 if rising_edge(50MHz_clk) and enable = '1' then

따라서 활성화를 만들 수 있습니다.

process 
   variable count : natural;
begin
   if rising_edge(50MHz_clk) then
       enable <= '0';
       count := count + 1;
       if count = clock_freq/desired_freq then
          enable <= '1';
          count := 0;
       end if;
    end if;
end process;

자체 문서화 코드를 사용하여 클럭 주파수와 원하는 활성화 주파수를 사용하여 두 개의 상수를 만듭니다.


3

Xilinx primitice 디지털 시계 관리자 IP를 사용하는 것이 좋습니다 .

원하는 주파수를 지정할 수있는 그래픽 설정 인터페이스가 있습니다. 원하는 출력을 주파수로하는 컴포넌트를 생성합니다.

IP 마법사에서 찾을 수 있습니다.

여기에 이미지 설명을 입력하십시오

그런 다음 원하는 주파수를 지정할 수 있습니다. 여기에 이미지 설명을 입력하십시오


0

계수 = 입력 신호 주파수 / 출력-프리스케일러 주파수.

CE = 클록 활성화. 사용하지 않을 경우 1 클럭 (clk) 폭의 펄스이거나 높아야합니다.

Q = 원하는 주파수를 갖는 하나의 클럭 폭 펄스의 출력 신호.

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;

entity prescaler is

  generic (
    FACTOR : integer);

  port (
    clk : in  std_logic;
    rst : in  std_logic;
    CE  : in  std_logic;
    Q   : out std_logic);

end prescaler;

architecture for_prescaler of prescaler is
  signal counter_reg, counter_next : integer range 0 to FACTOR-1;
  signal Q_next: std_logic;
begin  -- for_prescaler

  process (clk, rst)
  begin  -- process
    if rst = '1' then                   -- asynchronous reset (active low)
      counter_reg <= 0;
    elsif clk'event and clk = '1' then  -- rising clock edge
      counter_reg <= counter_next;
    end if;
  end process;

  process (counter_reg, CE)
  begin  -- process
    Q_next <= '0';
     counter_next <= counter_reg;
     if CE = '1' then
        if counter_reg = FACTOR-1  then
          counter_next <= 0;
           Q_next <= '1';
         else
           counter_next <= counter_reg + 1;
        end if;
      end if;
  end process;

  process (clk, rst)
  begin  -- process
    if rst = '1' then                   -- asynchronous reset (active low)
      Q <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      Q <= Q_next;
    end if;
  end process; 

end for_prescaler;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.