자일링스 FPGA 보드와 50MHz 크리스털이있다. VHDL에서 2Hz로 나눌 필요가 있습니다. 어떻게해야합니까?
자일링스 FPGA 보드와 50MHz 크리스털이있다. VHDL에서 2Hz로 나눌 필요가 있습니다. 어떻게해야합니까?
답변:
기본적으로 두 가지 방법이 있습니다. 첫 번째는 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;
참고 사항 :
편집 : clk_2Hz_i는 출력 신호를 버퍼링하는 데 사용됩니다. VHDL은 출력 일 때 할당 오른쪽의 신호를 사용하지 않습니다.
if prescaler = 50_000_000/4 then ...
그리고 prescaler <= prescaler + 1;
조금 더 간단 할 것이다.
clk_2Hz
출력 이라는 사실을 좋아하지 않지만이 줄에서 값을 읽습니다 clk_2Hz <= not clk_2Hz;
. 수정 프로그램에서 편집했습니다.
prescaler <= (others => '0');
그리고 prescaler <= '0';
?
others
가지고있는 VHDL 책을 읽을 때 사용 했던 것을 완전히 놓쳤다 . "000000000000000000 ...."등과 같은 것을 사용하는 대신 모든 "기타"비트를 공통 값으로 선언하기위한 지름길입니다.
클럭 프리스케일러를 사용하십시오.
프리스케일러 값은 (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;
newClock : std_logic := '0'
프리스케일러 / 2로 올라가서 할당하지 newClk <= not newClk
않겠습니까?
일반적으로 실제로 느린 것을 클럭하고 싶지 않고 올바른 속도로 활성화를 만들고 로직에서 사용하십시오.
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;
자체 문서화 코드를 사용하여 클럭 주파수와 원하는 활성화 주파수를 사용하여 두 개의 상수를 만듭니다.
Xilinx primitice 디지털 시계 관리자 IP를 사용하는 것이 좋습니다 .
원하는 주파수를 지정할 수있는 그래픽 설정 인터페이스가 있습니다. 원하는 출력을 주파수로하는 컴포넌트를 생성합니다.
IP 마법사에서 찾을 수 있습니다.
그런 다음 원하는 주파수를 지정할 수 있습니다.
계수 = 입력 신호 주파수 / 출력-프리스케일러 주파수.
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;