Tôi có một bo mạch Xilinx, với tinh thể 50 MHz. Tôi cần chia nó xuống 2Hz trong VHDL. Làm thế nào để tôi làm điều này?
Tôi có một bo mạch Xilinx, với tinh thể 50 MHz. Tôi cần chia nó xuống 2Hz trong VHDL. Làm thế nào để tôi làm điều này?
Câu trả lời:
Về cơ bản, có hai cách để làm điều này. Đầu tiên là sử dụng lõi tổng hợp đồng hồ gốc Xilinx. Một trong những lợi thế của điều này là các công cụ Xlinx sẽ nhận ra đồng hồ như vậy và định tuyến nó thông qua các con đường cần thiết. Các công cụ cũng sẽ xử lý mọi ràng buộc về thời gian (không thực sự áp dụng trong trường hợp này, vì đó là đồng hồ 2Hz)
Cách thứ hai là sử dụng bộ đếm để đếm số xung đồng hồ nhanh hơn cho đến khi một nửa thời gian đồng hồ chậm hơn của bạn trôi qua. Ví dụ, đối với trường hợp của bạn, số xung đồng hồ nhanh tạo nên một chu kỳ đồng hồ của chu kỳ đồng hồ chậm là 50000000/2 = 25000000. Vì chúng tôi muốn nửa chu kỳ đồng hồ, đó là 25000000/2 = 12500000 cho mỗi nửa chu kỳ . (thời lượng của mỗi mức cao hay thấp).
Đây là những gì nó trông giống như trong 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;
Những điều cần lưu ý:
EDIT: clk_2Hz_i được sử dụng để đệm tín hiệu đầu ra. VHDL không muốn sử dụng tín hiệu ở bên phải của bài tập khi nó cũng là đầu ra.
if prescaler = 50_000_000/4 then ...
và prescaler <= prescaler + 1;
sẽ đơn giản hơn một chút.
clk_2Hz
là một đầu ra, nhưng giá trị của nó đang được đọc trong dòng này clk_2Hz <= not clk_2Hz;
. Tôi đã chỉnh sửa trong bản sửa lỗi.
prescaler <= (others => '0');
và là prescaler <= '0';
gì?
others
đã được sử dụng khi đọc một cuốn sách VHDL mà tôi có. Đây chỉ là một phím tắt để khai báo tất cả các bit "khác" thành một giá trị chung thay vì sử dụng một cái gì đó như "000000000000000000 ....", v.v.
Sử dụng một bộ đếm trước đồng hồ.
Giá trị bộ đếm trước của bạn sẽ là (clock_speed / wish_clock_speed) / 2 vì vậy (50Mhz (50.000.000) / 2hz (2)) / 2 = 12.500.000 mà trong nhị phân sẽ là 101111101011110000100000.
Đơn giản hơn: (50.000.000) / 2) / 2 = 12.500.000 chuyển đổi thành nhị phân -> 101111101011110000100000
Đây là một số mã về những việc cần làm: Sử dụng newClock cho bất cứ điều gì bạn cần 2hz cho ...
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'
, đếm đến prescaler / 2 và gán newClk <= not newClk
?
Bạn thường không thực sự muốn xem bất cứ thứ gì chậm, chỉ cần tạo một kích hoạt ở tốc độ chính xác và sử dụng nó trong logic:
if rising_edge(50MHz_clk) and enable = '1' then
do đó bạn có thể tạo kích hoạt:
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;
tạo một vài hằng số với tần số đồng hồ của bạn và tần số cho phép bạn muốn và đi xa, với mã tự ghi để khởi động.
Tôi muốn đề nghị sử dụng IP quản lý đồng hồ kỹ thuật số Xilinx primitice .
Nó có giao diện cài đặt đồ họa nơi bạn có thể chỉ định tần số bạn muốn. Nó sẽ tạo ra một thành phần với đầu ra mong muốn của bạn dưới dạng tần số.
Nó có thể được tìm thấy trong IP Wizard;
Và sau đó bạn sẽ có thể chỉ định tần suất nào bạn muốn:
Yếu tố = đầu vào-tín hiệu-frecuency / đầu ra-prescaler-frecuency.
CE = Đồng hồ kích hoạt. Nó nên là một xung rộng một xung nhịp (clk) hoặc cao nếu không được sử dụng.
Q = Tín hiệu đầu ra của xung rộng một xung nhịp với độ chính xác mong muốn.
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;