ฉันมีบอร์ด Xilinx FPGA พร้อมคริสตัล 50MHz ฉันต้องหารมันลงไปที่ 2Hz ใน VHDL ฉันจะทำสิ่งนี้ได้อย่างไร
ฉันมีบอร์ด Xilinx FPGA พร้อมคริสตัล 50MHz ฉันต้องหารมันลงไปที่ 2Hz ใน VHDL ฉันจะทำสิ่งนี้ได้อย่างไร
คำตอบ:
โดยทั่วไปมีสองวิธีในการทำเช่นนี้ สิ่งแรกคือการใช้แกนซินธิไซเซอร์นาฬิกาพื้นเมือง 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 ที่ฉันมี มันเป็นแค่ทางลัดสำหรับการประกาศบิต "อื่น ๆ " ทั้งหมดให้เป็นค่าทั่วไปแทนที่จะใช้บางอย่างเช่น "0000000000000000000000 .... " ฯลฯ
ใช้พรีสเกลนาฬิกา
ค่าพรีเซลเลอร์ของคุณจะเป็นของคุณ (clock_speed / ที่ต้องการ_clock_speed) / 2 ดังนั้น (50Mhz (50,000,000) / 2hz (2)) / 2 = 12,500,000 ซึ่งในรูปแบบเลขฐานสองจะเป็น 1011111010111100000000000
ง่ายขึ้น: (50,000,000) / 2) / 2 = 12,500,000 แปลงเป็นไบนารี่ -> 1011111010111100000000000
นี่คือรหัสของสิ่งที่ต้องทำ: ใช้ newClock สำหรับทุกสิ่งที่คุณต้องการ 2hz สำหรับ ...
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'
ถึง prescaler / 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
จากนั้นคุณจะสามารถระบุความถี่ที่คุณต้องการ:
ตัวคูณ = อินพุต - สัญญาณ - frecuency / output-prescaler-frecuency
CE = เปิดใช้งานนาฬิกา ควรเป็นพัลส์แบบกว้างหนึ่งนาฬิกา (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;