Ist es schwierig, Ihr erstes VHDL-Programm zu schreiben?

Ist es schwierig, Ihr erstes VHDL-Programm zu schreiben? Es ist schwer zu sagen, aber die Hauptsache hier ist die Motivation ...


Vielleicht hätte ich es schaffen können, diesen Moment zu verzögern, aber ein Nachbar bat mich, einen Rechteckimpulsgenerator herzustellen, damit er klar angezeigt und die Frequenz und Dauer des Impulses gesteuert werden kann.

Und mit einer Genauigkeit von 0,1 Mikrosekunden ...

Und meine Meinung fiel auf einen Schal mit CPLD (200 Rubel), auf dem sich Indikatoren und Knöpfe befanden. Sobald Sie anfangen sollten, mit so etwas zu arbeiten, dachte ich, und ...

Die Wahl, was VHDL oder Verilog schreiben soll, war nicht - obwohl ich alles in C schreibe, aber ich liebe Ada immer noch - also ist VHDL einzigartig. Nachdem ich die Einführung in FPGA gelesen hatte, wurde mir klar, dass nichts kompliziert sein würde (zumindest für eine so einfache Aufgabe).

Am Anfang war das Wort : Machen wir uns zu einem Generator. Die Frequenz des nativen Shreds beträgt 50 MHz, das heißt, wir werden sie auf 10 reduzieren, so dass das Schalten der Taktleitung in der Mitte und am Ende erfolgt. Folgendes ist passiert.

-- 100 ns signal generator process(clk) variable t:integer range 0 to 5 := 0; begin if rising_edge(clk) then t := t + 1; if t = 5 then t := 0; tact <= not tact; end if; if t = 2 then tact <= not tact; end if; end if; end process; 

Dann müssen Sie irgendwie anzeigen und verwalten. Wir haben zwei Werte - die Länge der Periode und die Länge des Impulses, so dass wir für die Länge der Periode 3 Vertrautheiten (unter Berücksichtigung von Zehnteln) und für die Länge der Periode - 3 zuweisen.

 shared variable period : integer range 0 to 1000 := 500; shared variable duty : integer range 0 to 1000 := 250; shared variable dig1:std_logic_vector(3 downto 0):="0000"; shared variable dig2:std_logic_vector(3 downto 0):="0101"; shared variable dig3:std_logic_vector(3 downto 0):="0010"; shared variable di1:std_logic_vector(3 downto 0):="0000"; shared variable di2:std_logic_vector(3 downto 0):="0000"; shared variable di3:std_logic_vector(3 downto 0):="0101"; 

Nun, zur Steuerung sind Signale von den Tasten geeignet, die am unteren Rand der Platine sichtbar sind - es gibt nur 4 davon,
Lassen Sie also zwei die Änderung der Periode bzw. des Impulses steuern, einer setzt das Vorzeichen der Änderung und ein anderer schaltet den Ausgang des Generators ein und aus ...

Hier ist das Management
 process(key1) begin if rising_edge(key1) then ready <= not ready; end if; end process; process(key3) begin if rising_edge(key3) then if key4 = '1' then inc_duty; else dec_duty; end if; end if; end process; process(key2) begin if rising_edge(key2) then if key4 = '1' then inc_period; else dec_period; end if; end if; end process; 


Im Management gibt es Inc / Dec-Verfahren, hier sind sie
 procedure inc_duty is begin if duty < period then duty := duty + 1; if dig1 = "1001" then dig1 := "0000"; if dig2 = "1001" then dig2 := "0000"; if dig3 = "1001" then dig3 := "0000"; else dig3 := dig3 + 1; end if; else dig2 := dig2 + 1; end if; else dig1 := dig1 + 1; end if; end if; end procedure; procedure dec_duty is begin if duty > 1 then duty := duty - 1; if dig1 = "0000" then dig1 := "1001"; if dig2 = "0000" then dig2 := "1001"; dig3 := dig3 - 1; else dig2 := dig2 - 1; end if; else dig1 := dig1 - 1; end if; end if; end procedure; procedure inc_period is begin if period < 1000 then period := period + 1; if di1 = "1001" then di1 := "0000"; if di2 = "1001" then di2 := "0000"; if di3 = "1001" then di3 := "0000"; else di3 := di3 + 1; end if; else di2 := di2 + 1; end if; else di1 := di1 + 1; end if; end if; end procedure; procedure dec_period is begin if period > 1 then period := period - 1; if di1 = "0000" then di1 := "1001"; if di2 = "0000" then di2 := "1001"; if di3 = "0000" then di3 := "1001"; else di3 := di3 - 1; end if; else di2 := di2 - 1; end if; else di1 := di1 - 1; end if; end if; end procedure; 


Es ist etwas lang und kompliziert (deshalb wird es minimiert), aber es ist ziemlich verständlich.

Nun, wir müssen es irgendwie anzeigen - wir haben einen Sieben-Segment-Indikator, und es gibt 6 davon (tatsächlich 8). Wir werden die Zeit und, um nicht mit einem Punkt zu leiden, in Zehntelsekunden anzeigen.

Lassen Sie sie durchlaufen und die aktuelle Ziffer anzeigen:

 process(tactX) begin case tactX is when"000"=> en_xhdl<="11111110"; when"001"=> en_xhdl<="11111101"; when"010"=> en_xhdl<="11111011"; when"011"=> en_xhdl<="11110111"; when"100"=> en_xhdl<="11101111"; when"101"=> en_xhdl<="11011111"; when"110"=> en_xhdl<="10111111"; when"111"=> en_xhdl<="01111111"; when others => en_xhdl<="01111111"; end case; end process; process(en_xhdl) begin case en_xhdl is when "11111110"=> data4<=dig1; when "11111101"=> data4<=dig2; when "11111011"=> data4<=dig3; when "11110111"=> data4<="1111"; when "11101111"=> data4<=di1; when "11011111"=> data4<=di2; when "10111111"=> data4<=di3; when "01111111"=> data4<="0000"; when others => data4<="1111"; end case; end process; process(data4) begin case data4 is WHEN "0000" => dataout_xhdl1 <= "11000000"; WHEN "0001" => dataout_xhdl1 <= "11111001"; WHEN "0010" => dataout_xhdl1 <= "10100100"; WHEN "0011" => dataout_xhdl1 <= "10110000"; WHEN "0100" => dataout_xhdl1 <= "10011001"; WHEN "0101" => dataout_xhdl1 <= "10010010"; WHEN "0110" => dataout_xhdl1 <= "10000010"; WHEN "0111" => dataout_xhdl1 <= "11111000"; WHEN "1000" => dataout_xhdl1 <= "10000000"; WHEN "1001" => dataout_xhdl1 <= "10010000"; WHEN OTHERS => dataout_xhdl1 <= "11111111"; END CASE; END PROCESS; 

Ich gebe ehrlich zu, ich habe einen Teil des Codes aus den Quellen gezogen, die mit einem Schal geliefert wurden - er ist sehr cool und klar geschrieben! en_xhdl - Dieses Signal steuert, welche Anzeige im Schaltzyklus leuchtet. dataout_xhdl1 - Dieses Signal schaltet die LEDs ein. Nun, data4 ist ein temporäres Register und speichert eine Ziffer.

Es bleibt ein Herz zu schreiben, das alles berücksichtigt - den Generator selbst. Hier ist taktX der Anzeigegenerator und cnt ist der Impulspositionszähler. Nun, lin ist das Signal des Generators selbst.

 process(tact) variable cntX : integer range 0 to 1000 := 0; variable cnt : integer range 0 to 1000 := 0; begin if rising_edge(tact) then if cntX = 0 then tactX <= tactX + 1; end if; cntX := cntX + 1; if cnt > period then cnt := 0; else cnt := cnt + 1; end if; if cnt = 0 then lin <= '0'; elsif cnt = duty then lin <= '1'; end if; end if; end process; 

Nun, es bleibt die Ausgabe der Daten - dies geschieht ständig, daher sollte es sich im parallelen Ausführungsblock befinden.

  cat_led <= dataout_xhdl1; en_led <= en_xhdl; led1 <= not ready; out1 <= lin when ready = '1' else '0'; out2 <= not lin when ready = '1' else '0'; 

Am Ende alle Prozesse zusammen blind machen - die resultierende Quarus Prime-Datei wurde positiv aufgenommen, kompiliert und gemeldet

 Top-level Entity Name v12 Family MAX II Device EPM240T100C5 Timing Models Final Total logic elements 229 / 240 ( 95 % ) Total pins 29 / 80 ( 36 % ) Total virtual pins 0 UFM blocks 0 / 1 ( 0 % ) 

Die mühsamste Phase bleibt bestehen, obwohl sie vollständig grafisch ist - um den Signalen bestimmte Pins zuzuweisen. Und das ist alles - es bleibt alles in das Gerät zu füllen und zu überprüfen! Interessanterweise haben wir es geschafft, innerhalb von 229 Zellen zu bleiben, so dass bereits 11 übrig waren - aber in Wirklichkeit wurde fast alles von den Schnittstellentasten und dem Display verschlungen. Tatsächlich kann der Generator in mehreren Zellen gestapelt werden - Intel hat ein Dokument, in dem beschrieben wird, wie man in 1 LUT stapelt - natürlich ohne Kontrolle ...

Beantworten Sie also die Frage nach der Überschrift - nein, es ist nicht schwierig, wenn Sie C oder Ada kennen und verstehen, wie digitale Elektronik funktioniert, und ja, es ist schwierig, wenn Sie keine Vorstellung von den grundlegenden Dingen haben ... Zumindest habe ich einen Tag gebraucht, um zu schreiben, und ich Ich habe mich sowohl über den Entwicklungsprozess als auch über ein funktionierendes Gerät sehr gefreut! Und der Nachbar ist glücklich :)

Source: https://habr.com/ru/post/de461621/


All Articles