J'ai une carte FPGA Xilinx, avec un cristal 50 MHz. Je dois diviser cela à 2 Hz en VHDL. Comment puis-je faire cela?
J'ai une carte FPGA Xilinx, avec un cristal 50 MHz. Je dois diviser cela à 2 Hz en VHDL. Comment puis-je faire cela?
Réponses:
Fondamentalement, il existe deux façons de procéder. La première consiste à utiliser le cœur du synthétiseur d'horloge natif Xilinx. L'un des avantages de ceci est que les outils Xlinx reconnaîtront l'horloge en tant que telle et la dirigeront à travers les voies requises. Les outils géreront également toutes les contraintes de synchronisation (pas vraiment applicables dans ce cas, car il s'agit d'une horloge de 2 Hz)
La deuxième façon consiste à utiliser un compteur pour compter le nombre d'impulsions d'horloge plus rapides jusqu'à ce que la moitié de votre période d'horloge plus lente se soit écoulée. Par exemple, pour votre cas, le nombre d'impulsions d'horloge rapide qui composent une période d'horloge d'un cycle d'horloge lente est 50000000/2 = 25000000. Puisque nous voulons une demi-période d'horloge, c'est 25000000/2 = 12500000 pour chaque demi-cycle . (la durée de chaque haut ou bas).
Voici à quoi cela ressemble en 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;
A noter:
EDIT: clk_2Hz_i est utilisé pour mettre en mémoire tampon le signal de sortie. VHDL n'aime pas utiliser un signal à droite d'une affectation lorsqu'il s'agit également d'une sortie.
if prescaler = 50_000_000/4 then ...
et ce prescaler <= prescaler + 1;
serait un peu plus simple.
clk_2Hz
s'agit d'une sortie, mais pourtant sa valeur est lue sur cette ligne clk_2Hz <= not clk_2Hz;
. J'ai édité le correctif.
prescaler <= (others => '0');
et prescaler <= '0';
?
others
était utilisé lors de la lecture d'un livre VHDL que j'ai. C'est juste un raccourci pour déclarer tous les "autres" bits à une valeur commune au lieu d'utiliser quelque chose comme "000000000000000000 ....", etc.
Utilisez un détartreur d'horloge.
Votre valeur de pré-échelle sera votre (vitesse_horloge / vitesse_horloge souhaitée) / 2 donc (50Mhz (50,000,000) / 2hz (2)) / 2 = 12,500,000 qui en binaire serait 1011111010111100000000000.
Plus simplement: (50 000 000) / 2) / 2 = 12 500 000 converti en binaire -> 101111101011110000100000
Voici un code de quoi faire: Utilisez newClock pour tout ce dont vous avez besoin de 2hz pour ...
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'
, compter jusqu'à prescaler / 2 et assigner newClk <= not newClk
?
En général, vous ne voulez pas cadencer quelque chose de lent, créez simplement une activation au taux correct et utilisez-le dans la logique:
if rising_edge(50MHz_clk) and enable = '1' then
vous pouvez créer l'activer ainsi:
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;
créez quelques constantes avec votre fréquence d'horloge et la fréquence d'activation souhaitée et vous partez, avec du code auto-documenté pour démarrer.
Je préférerais plutôt utiliser l' IP du gestionnaire d'horloge numérique de primitice Xilinx .
Il a une interface de paramètres graphiques où vous pouvez spécifier quelle fréquence vous voulez. Il générera un composant avec votre sortie souhaitée comme fréquence.
Il peut être trouvé dans IP Wizard;
Et puis vous pourrez spécifier quelle fréquence voulez-vous:
Facteur = fréquence-signal-entrée / fréquence-prescaler-sortie.
CE = Horloge activée. Il doit s'agir d'une impulsion large d'une horloge (clk) ou élevée si elle n'est pas utilisée.
Q = Signal de sortie d'une impulsion large d'horloge avec la fréquence souhaitée.
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;