kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Day by Day

(EN google-translate)

(PL google-translate)

Verzeichnis der im Verlauf des Semesters behandelten Themen

siehe auch day_by_day vom Sommersemester 2019: 69_FPGA/30_day_by_day

Donnerstag 18.03.2021

  • Einführung in das Thema Field Programmable Gate Arrays (FPGA)
  • Erste Schritte mit dem Board DLP-FPGA und der Entwicklungsumgebung ISE14.7 von xilinx

Links zu den passenden Inhalten auf kramann.info:


69_FPGA/01_Einfuehrung

69_FPGA/05_Beispiele/03_Mustervergleich


"Saal"-übung: UND-Gatter


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity and_gate is
    Port ( A : in  STD_LOGIC;
           B : in  STD_LOGIC;
           C : out  STD_LOGIC);
end and_gate;

architecture Behavioral of and_gate is

begin

C <= A and B;

end Behavioral;

Code 0-1: VHDL-Code zum UND-Gatter.

NET "A"  LOC = "P139" | PULLUP  | IOSTANDARD = LVCMOS33 ;
NET "B"  LOC = "P135" | PULLUP  | IOSTANDARD = LVCMOS33 ;
NET "C"  LOC = "P131" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;

Code 0-2: Constraints (.ucf-Datei) zum UND-Gatter.

Donnerstag 25.03.2021

  • Entleihen der Boxen mit Ihrer Hardware an der THB

Wenn Sie die Hardware haben, sollten Sie die Entwicklungsumgebung ISE 14.7 von Xilinx und die so genannte BitloadApp installieren und ein erstes Beispielprojekt erstellen und sehen, ob es sich auf den DLP-FPGA übertragen läßt.

  • Um Sie hierbei zu unterstützen, habe ich Videos vorbereitet, in denen diese Vorgänge angeschaut werden können.
  • Die Umsetzung erfolgte auf einem 64-Bit PC unter Windows 10.
  • Ich selber arbeite (auch in der Vorlesung) unter Linux/Xubuntu 20.04.
  • Die Videos sind unter argem Zeitdruck entstanden, also nicht sehr ansprechend, sollten aber ihren Zweck erfüllen.
  • Die Links, die in den Videos vorkommen, sowie der Quelltext eines Beispielprojektes finden Sie nachfolgend auch:

Damit Sie (freie) Software von Xilinx herunterladen und installieren können, müssen Sie sich bei Xilinx registrieren. Es macht Sinn, das zu allererst zu machen. das wird nicht im Video gezeigt. Während des Installationsprozesses werden Sie auch aufgefordert, sich eine Lizenz erstellen zu lassen. Das Lizenzfile wird Ihnen dann per E-Mail zugeschickt und auf das Dateisystem kopiert werden. Der Ort, wo das ist, muß der Installtion bekannt gemacht werden.

Ich habe probiert, die 14.7er-Version zu installieren, bei der explizit Windows 10 steht. Das hat nicht geklappt. Diese Version wurde unter Linux erstellt und ist in eine Virtual Machine eingebettet. Damit sie läuft, müssen Änderungen an den Einstellungen im BIOS vorgenommen werden. Dies fand ich nicht zumutbar, weshalb ich die Version unmittelbar davor genommen habe (auch 14.7). Diese war nativ für Windows 7 entwickelt worden, läuft aber auch unter Windows 10, sowohl unter 64Bit, als auch 32Bit. In dem Video wird gezeigt, wie diese Version installiert wird. Der Einfachheit gebe ich nachfolgend aber bereits die wichtigsten Links hierzu an:

Archiv mit den verschiedenen Entwicklungsumgebungen zum Downloaden bei Xilinx

Zu der "richtigen" 14.7-Version (die Zweite, wo NICHT Windows 10 steht) gehören vier gepackte Files. Deren Links gebe ich nachfolgend explizit an. Die sollten Sie alle gemeinsam in den Download-Ordner herunterladen:

Xilinx_ISE_DS_14.7_1015_1-1.tar (Hauptdatei, dessen Installationsfile greift sich die anderen Dateien automatisch. Letztere müssen dazu nicht entpackt werden, diese hier schon.)
Xilinx_ISE_DS_14.7_1015_1-2.zip.xz
Xilinx_ISE_DS_14.7_1015_1-3.zip.xz
Xilinx_ISE_DS_14.7_1015_1-4.zip.xz

Da auf das verwendete Board von Digikey "DLP-FPGA" nicht direkt aus der ISE14.7 heraus Programme übertragen werden können, muß mit ISE 14.7 eine Datei mit der Endung .bit erstellt werden. Diese wird mit einer Extrasoftware auf das Board übertragen. Diese Extrasoftware gibt es für Windows und Linux. Sie heißt BitloadApp und Sie können sie unter folgendem Link umsonst herunterladen:

Download der BitLoadApp: https://www.dlpdesign.com/fp34/

Diese Software wird einfach irgendwo entpackt und das Executable darin durch Doppelklicken gestartet. Die zu übertragende .bit-Datei sollten Sie vorher in den gleichen Ordner legen, wo auch dieses Executable liegt.

Hier folgen nun die Links zu den Videos, die die Installtion von ISE 14.7 unter Windows 10 zeigen und wie ein erstes Beispielprojekt umgesetzt werden kann. Dieses Beispielprojekt und auch die Notwendigen Einstellungen von ISE 14.7 finden Sie auch auf meiner Webseite:


Quelltext für das Beispielprojekt (blinkled.vhd und blinkled.ucf) und die Beschaltung des DLP-FPGA: 69_FPGA/05_Beispiele/01_Blinkende_LED

Screenshots zum Erstellen eines neuen Projektes für den DLP-FPGA mit ISE 14.7: 69_FPGA/21_XSE14

Video 1 (Teil1): Einführung https://youtu.be/hirAbmhThvA

Video 2 (Teil4): Herunteladen der benötigten Files https://youtu.be/1ceUsO36sH8

Video 3 (Teil5): Herunteladen der benötigten Files (Fortsetzung) https://youtu.be/hFDQj1Teh20

Video 4 (Teil6): Installtion (insb. Auswahl "WebPack") https://youtu.be/yTZssXbqvZM

Video 5 (Teil7): Rest Installation / Erstellen und kompilieren eines ersten Projektes https://youtu.be/_JFIOo7dukU

Video 6 (Teil8, letztes Video): Herunterladen und Verwenden der BitLoadApp, um die kompilierte Datei auf den FPGA zu übertragen https://youtu.be/SbOgoREXxyQ

Donnerstag 08.04.2021

Teil 1 (praktischer Teil)

  • Gemeinsam Bit-Datei "blink-LED übertragen"
  • Gemeinsam das Projekt UND-Gatter wiederholen und besprechen.
blinkendeled.zip -- ISE 14.7 - Projekt blinkendeled.
and_gate.zip -- ISE 14.7 - Projekt and_gate.
69_FPGA/03_DLP_FPGA -- siehe Bild 0-2: Zuordnung zwischen den Board-Pins und den FPGA-Chip-Pins (Xilinx Spartan 3E). Die Nummer der FPGA-Chip-Pins wird in den Programmen benötigt.
Übung

Die nachfolgende Übung kann aufgrund der bisherigen Kenntnisse umgesetzt werden.

  • Richten Sie ein neues Projekt für das DLP-FPGA-Board mit ISE 14.7 ein.
  • An Pin 12 (auf dem Board) und 14 (auf dem Board) sollen LEDs angeschlossen werden.
  • An Pin 22 (auf dem Board) soll ein Taster angeschlossen werden (Draht gegen Masse, also GND).
  • Wird Pin 22 auf Masse gesetzt, soll die LED bei Pin 14 (auf dem Board) leuchten und die bei Pin 12 (auf dem Board) aus sein.
  • Ohne Verbindung von Pin 22 (auf dem Board) mit Masse soll es umgekehrt sein, also die LED bei Pin 14 aus sein und die bei Pin 12 (auf dem Board) leuchten.

Hinweis: Das logische NICHT ist in VHDL not.

Teil 2 (theoretischer Teil)

  • Wiederholung der Grundarchitektur eines FPGA-ICs
  • Wiederholung der Programmstruktur bei VHDL
  • Analyse von Mustervergleich
69_FPGA/01_Einfuehrung
69_FPGA/05_Beispiele/03_Mustervergleich

Wie sähe der VHDL-Quelltext und die .ucf-Datei zu einem Programm aus, bei dem es zwei Mustervleicher gleichen Typs gäbe: Den, den wir kennen und einen zweiten, bei dem die Eingänge gegenüber gespiegelt auf der anderen Seite des Boards sitzen und die LED bei Pin 22?



Merke: Parallele Strukturen sind möglich und üblich beim FPGA.


Donnerstag 15.04.2021

Themen
  • Umgang mit Bitwörtern
  • Bitshiftoperationen
  • Übung: Lauflicht ... jetzt auch in dieser LV :O)
Binärzähler, der selber hochzählt -- 69_FPGA/05_Beispiele/03_Mustervergleich
Bitshiftoperationen -- 69_FPGA/11_VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity lauflicht is
    Port ( MEINECLOCK : in   STD_LOGIC;
           FUENFBIT   : out  STD_LOGIC_VECTOR(4 downto 0)
         );
end lauflicht;
-- Clock-In == 6MHz, Toggeln nach 3000000 Schritten ergibt 1Hz Blinkfrequenz.
architecture Behavioral of lauflicht is
    signal zaehler    : integer range 0 to 2999999 := 0;
	 signal wort : std_logic_vector(4 downto 0) := "00001";
    begin
        process begin
            wait until rising_edge(MEINECLOCK);
            if (zaehler<2999999) then
                zaehler <= zaehler+1;
            else
                zaehler <= 0;
                wort <= wort(3 downto 0) & wort(4);
            end if;
        end process;
		  
        FUENFBIT <= wort;
		  
    end Behavioral;

Code 0-3: Lauflicht VHDL-Code

## GCLK6 ist auf FPGA-Chip Pin 56
NET "MEINECLOCK" LOC = "P56";

NET "FUENFBIT<4>"   LOC = "P125";
NET "FUENFBIT<3>"   LOC = "P126";
NET "FUENFBIT<2>"   LOC = "P130";
NET "FUENFBIT<1>"   LOC = "P131";
NET "FUENFBIT<0>"   LOC = "P132";

NET "MEINECLOCK" IOSTANDARD = LVCMOS25;

NET "FUENFBIT<4>" IOSTANDARD = LVCMOS33; 
NET "FUENFBIT<3>" IOSTANDARD = LVCMOS33; 
NET "FUENFBIT<2>" IOSTANDARD = LVCMOS33; 
NET "FUENFBIT<1>" IOSTANDARD = LVCMOS33; 
NET "FUENFBIT<0>" IOSTANDARD = LVCMOS33; 

Code 0-4: Lauflicht, zugehörige UCF-Datei

Donnerstag 21.04.2021

Da die Syntax von VHDL und deren Bedeutung sich sehr von den ihnen bisher vertrauten Programmiersprachen abhebt, soll der Umgang damit in der heutigen LV weiter vertieft werden. Darum wird nichts Neues eingeführt, sondern es sollen statt dessen die nachfolgend beschriebenen drei Übungen bearbeitet werden.

Machen Sie dabei regen Gebrauch von den Sprachelementen, die Sie bisher kennengelernt haben. Schlagen Sie die bereits behandelten Beispiele nochmals nach.



Belassen Sie für die nachfolgenden Übungen so weit es geht den vorhandenen Aufbau mit den LEDs.



Übung 1

Analysieren Sie den Bitvergleicher, der von alleine die verschiedenen Muster durchgeht und passen Sie dieses Beispiel so an, dass es mit den bereits beim letzten mal angebrachten LEDs funktioniert.


Sie dazu: Version 2 - Automatischer Binärzähler, hier: 69_FPGA/05_Beispiele/03_Mustervergleich

Übung 2

Im Fach Mikrocontrollertechnik wurde eine "Fußgängerampel" programmiert: Zunächst leuchtet eine rote LED auf. Nach Betätigen eines Tasters leuchtet für eine Weile eine grüne LED auf, danach wieder nur die rote.

Diskutieren Sie die Möglichkeit diese Funktionalität mit einem VHDL-Programm zu realisieren.

Setzen Sie Ihre Idee um.


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ampel is
    Port ( MEINECLOCK : in  STD_LOGIC;
           TASTER : in  STD_LOGIC;
           GRUEN : out  STD_LOGIC;
           ROT : out  STD_LOGIC);
end ampel;

architecture Behavioral of ampel is
    signal logikpegel : std_logic := '0';
    signal ausgang    : std_logic := '0';
	 signal zaehler    : integer range 0 to 5999999 := 0;
begin
    process begin
    wait until rising_edge(MEINECLOCK);
	 -- Zaehler Null setzen, wenn Taste gedrückt:
	 if (logikpegel = '1') then
	     zaehler <= 0;
	 end if;
    -- Zaehlprozess
    if (zaehler<5999999) then
        zaehler <= zaehler+1;
		  ausgang <= '1'; -- Ampel soll grün sein
    else
		  ausgang <= '0'; -- Ampel soll rot sein	     
    end if;	 
    end process;    

    logikpegel <= not TASTER;
	 GRUEN <= ausgang;
	 ROT <= not ausgang;
end Behavioral;

Code 0-5: ampel.vhd (Musterlösung)

## GCLK6 ist auf FPGA-Chip Pin 56
NET "MEINECLOCK" LOC = "P56";
## IO_L05P_0 ist auf FPGA-Chip Pin 125
NET "GRUEN"   LOC = "P125";
NET "ROT"   LOC = "P126";

NET "MEINECLOCK" IOSTANDARD = LVCMOS25;
NET "TASTER"  LOC = "P135" | PULLUP  | IOSTANDARD = LVCMOS33 ;
NET "GRUEN"   IOSTANDARD = LVCMOS33; 
NET "ROT"   IOSTANDARD = LVCMOS33; 

Code 0-6: ampel.ucf (Constraints zur Musterlösung)

Test des Projektes

Bild 0-1: Test des Projektes

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity fussgaengerampel is
Port ( CLOCK : in STD_LOGIC;
MASSE : in STD_LOGIC;
LED_ROT : out STD_LOGIC;
LED_GRUEN : out STD_LOGIC
);
end fussgaengerampel;

architecture Behavioral of fussgaengerampel is
signal zaehler : integer range 0 to 5999999 := 0;
signal Ampelzaehler: integer range 0 to 4 := 0;
signal wort : std_logic_vector(1 downto 0);
signal A,B : std_logic;

begin

process begin
wait until rising_edge(CLOCK);
if (zaehler < 5999999) then
zaehler <= zaehler +1;
else zaehler <= 0;
if (Ampelzaehler < 4) then
Ampelzaehler <= Ampelzaehler +1;
else
Ampelzaehler <= 0;
end if;
end if;

end process;

--quasi_zaehler
wort <= conv_std_logic_vector(Ampelzaehler, 2);
A <= wort(0);
B <= wort(1);

LED_GRUEN <= (A and B and (not MASSE));
LED_ROT <= (not A) or (not B) or MASSE;


end Behavioral;

Code 0-7: alternative studentische Lösung

NET "CLOCK" LOC = "P56";

NET "CLOCK" IOSTANDARD = LVCMOS25;
NET "MASSE" = "P124" | PULLUP | IOSTANDARD = LVCMOS33 ;
NET "LED_ROT" LOC = "P105" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;
NET "LED_GRUEN" LOC = "P112" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ;

Code 0-8: Constraints zur studentischen Lösung.

Übung 3

Diskutieren Sie, wie sie mit VHDL ein Lauflicht programmieren können, bei dem ein Lichtpunkt hin und her wandert (Typ "Zylon").



Bei der Musterlösung bleibt die Ampel grün, wenn die Taste gedrückt bleibt. Kann das verhindert werden?


Donnerstag 29.04.2021

Themen

  • Module erstellen
  • Die Unisim-Library
  • D-Flip-Flop
  • Binärzähler mit Hilfe von D-Flip-Flops
Übung

Bilden Sie nachfolgendes Projekt von vorn nach. Prüfen Sie, ob das Verhalten dem erwarteten entspricht.

69_FPGA/08_Synchronisieren -- D-Flip-Flop
Übung

Reduzieren Sie die beiden nachfolgenden Projekte so, dass die Taktpulse zum Weiterzählen von Hand über einen Taster erfolgen.

69_FPGA/09_Uebung -- Schieberegister aus D-Flip-Flops
69_FPGA/12_UNISIM -- D-Flip-Flop aus UNISIM Library

Donnerstag 06.05.2021

Themen

  • Feedback-Runde
  • Nachbearbeitung der Übungen von letzter Woche
  • Unisim-Library-Element: LUT4

Nachbesprechung und Fertigstellung der Projekte von letzter Woche

Fußgängerampel
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ampel is
    Port ( MEINECLOCK : in  STD_LOGIC;
           TASTER : in  STD_LOGIC;
           GRUEN : out  STD_LOGIC;
           ROT : out  STD_LOGIC);
end ampel;

architecture Behavioral of ampel is
    signal logikpegel : std_logic := '0';
    signal ausgang    : std_logic := '0';
	 signal zaehler    : integer range 0 to 5999999 := 0;
begin
    process begin
    wait until rising_edge(MEINECLOCK);
	 -- Zaehler Null setzen, wenn Taste gedrückt:
	 if (logikpegel = '1') then
	     zaehler <= 0;
		  ausgang <= '1'; -- Ampel soll grün sein
	 end if;
    -- Zaehlprozess
    if (zaehler<5999999) then
        zaehler <= zaehler+1;
    else
		  ausgang <= '0'; -- Ampel soll rot sein	     
    end if;	 
    end process;    

    logikpegel <= not TASTER;
	 GRUEN <= ausgang;
	 ROT <= not ausgang;
end Behavioral;

Code 0-9: VHDL-Code zu einer Variation der Fußgängerampel.

## GCLK6 ist auf FPGA-Chip Pin 56
NET "MEINECLOCK" LOC = "P56";
## IO_L05P_0 ist auf FPGA-Chip Pin 125
NET "GRUEN"   LOC = "P125";
NET "ROT"   LOC = "P126";

NET "MEINECLOCK" IOSTANDARD = LVCMOS25;
NET "TASTER"  LOC = "P135" | PULLUP  | IOSTANDARD = LVCMOS33 ;
NET "GRUEN"   IOSTANDARD = LVCMOS33; 
NET "ROT"   IOSTANDARD = LVCMOS33; 

Code 0-10: Constraints zu einer Variation der Fußgängerampel.

Hand-geseteuertes Schieberegister

Vergleiche Hierzu die Quelltexte hier:

69_FPGA/08_Synchronisieren -- automatisch getaktetes Schieberegister aus selbst erstellten D-Flip-Flop-Instanzen.
69_FPGA/12_UNISIM -- automatisch getaktetes Schieberegister aus D-Flip-Flops der UNISIM-Library.
schieberegister2021.zip -- Musterlösung, Gesamtes Projekt zu "Hand-geseteuertes Schieberegister", erstellt mit ISE14.7

Eigentlich mit dem Ziel eine einfache Übungsaufgabe zu stellen, war gefordert, den vorhandenen Quelltext zu einem intern getakteten Schieberegister so umzuschreiben, das die Taktung über einen Taster von außen von Hand erfolgt.

Hierbei trat leider das Problem des Prellens des Tasters auf, wodurch stets mehr als ein Puls von außen kommend registriert wurde und damit der Schiebevorgang unkontrolliert läuft.

Um dieses Problem lösen zu können, muß ein weiterer Prozeß implementiert werden, der nach dem ersten herein kommenden Impuls durch den Clock-Taster den Eingang für eine gewisse Zeit nicht beachtet, damit nachfolgende Prellpulse unberücksichtigt bleiben. Im Zuge hier während des Unterrichts eine Lösung zu finden, hat sich herausgetellt, dass die Lösung dieses Problems nicht so trivial ist, wie das beispielsweise bei Verwendung eines Mikrocontrollers wäre.

Wesentlich zu beachten ist, dass bereits in jeder Flip-Flop-Instanz je ein Prozeß enthalten ist. Desweiteren wird um die temporäre Desensibilisierung des Tasters zu bewerkstelligen dann doch weiterhin die interne 6MHz-Clock verwendet, um genau diesen zeitlichen Prozeß zu handhaben.

Um die Warning, dass kein dedizierter Clock-Signaleingang verwendet wird weg zu bekommen, wird statt P142 besser P122 als Eingang verwendet. Dies ist bei der Verkabelung zu beachten!

Nochfolgend finden Sie eine funktionierende Lösung, die im Verlauf dieser LV vorgestellt und besprochen wird:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

---- Clock-Leitung nicht an vorgesehenem Pin führt zu:
---- 
---- in ucf nötig: NET "CLOCK" CLOCK_DEDICATED_ROUTE = FALSE;
----
---- WARNING:Place:1019 - A clock IOB / clock component pair have been found that are not placed at an optimal clock IOB /
---- clock site pair. The clock component <CLOCK_BUFGP/BUFG> is placed at site <BUFGMUX_X1Y10>. The IO component <CLOCK>
---- is placed at site <P142>. This will not allow the use of the fast path between the IO and the Clock buffer. This is
---- normally an ERROR but the CLOCK_DEDICATED_ROUTE constraint was applied on COMP.PIN <CLOCK.PAD> allowing your design
---- to continue. This constraint disables all clock placer rules related to the specified COMP.PIN. The use of this
---- override is highly discouraged as it may lead to very poor timing results. It is recommended that this error
---- condition be corrected in the design.

entity schieberegister is
    Port ( 
	        CLOCK6MHZ : in  STD_LOGIC;
	        CLOCK : in  STD_LOGIC; -- #### Name geändert in CLOCK
           RESET : in  STD_LOGIC;
           BITIN : in  STD_LOGIC;
           VIERBIT : out  STD_LOGIC_VECTOR (3 downto 0));
end schieberegister;

architecture Verhalten_Schieberegister of schieberegister is
    signal sig_d       : std_logic_vector (3 downto 0) := "0000";
    signal sig_q       : std_logic_vector (3 downto 0) := "0000";
	 signal clock1Hz    : std_logic := '0';
	 signal all_reset   : std_logic := '1';
	 
    signal zaehler     : integer range 0 to 2999999 := 0; 	 
begin
-- Erzeugen der 1Hz-Clock mit Hilfe eines Prozesses (vergl. Blink-LED)
-- #### Porzess ersetzen
   process begin
      wait until rising_edge(CLOCK6MHZ);
	   if( CLOCK='0' and zaehler=0) then
        clock1Hz <= '1';
        zaehler <= 299999;
      else		
        clock1Hz <= '0';
        --- NEU *** NEU **** testen!
        if(zaehler>0) then		
            zaehler <= zaehler-1;
        end if;
        --- NEU *** NEU ****
      end if;
   end process;
	
-- Vier D-FlipFlops instanziieren
	FLIP3: entity dflipflop
	    port map(D => sig_d(3), CLOCK => clock1Hz, RESET => all_reset, Q => sig_q(3));
	FLIP2: entity dflipflop
	    port map(D => sig_d(2), CLOCK => clock1Hz, RESET => all_reset, Q => sig_q(2));
	FLIP1: entity dflipflop
	    port map(D => sig_d(1), CLOCK => clock1Hz, RESET => all_reset, Q => sig_q(1));
	FLIP0: entity dflipflop
	    port map(D => sig_d(0), CLOCK => clock1Hz, RESET => all_reset, Q => sig_q(0));
-- Signalwege / Verbindungen laut Schaltplan beschreiben
   -- Verbindungen zwischen den D-FlipFlops und zum Eingangsschalter
   sig_d(0) <= not BITIN;
	sig_d(1) <= sig_q(0);
	sig_d(2) <= sig_q(1);
	sig_d(3) <= sig_q(2);
	-- Verbindungen zu den LEDs
	VIERBIT(3) <= sig_q(3);
	VIERBIT(2) <= sig_q(2);
	VIERBIT(1) <= sig_q(1);
	VIERBIT(0) <= sig_q(0);
	all_reset <= RESET;
end Verhalten_Schieberegister;

Code 0-11: VHDL-Code zu Schieberegister mit Clock über Taster und temporärer Desensibilisierung dieses Tasters.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity dflipflop is
    Port ( D : in  STD_LOGIC;
           CLOCK : in  STD_LOGIC;
           RESET : in  STD_LOGIC;
           Q : out  STD_LOGIC);
end dflipflop;

architecture Verhalten_Dflipflop of dflipflop is
    signal sig_d       : std_logic := '0';
    signal sig_clock   : std_logic := '0';
    signal sig_reset   : std_logic := '0';
    signal sig_q       : std_logic := '0';
begin
    process(sig_clock,sig_reset)
	 begin
	     if (sig_reset='1') then
		      sig_q <= '0';
		  elsif (sig_clock'event and sig_clock='1') then
		      sig_q <= sig_d;
		  end if;
    end process;
    sig_clock <= CLOCK;
    sig_reset <= not RESET; -- inverse Logik wg. externer Pullup
    sig_d     <= D;
    Q         <= sig_q;	 
end Verhalten_Dflipflop;

Code 0-12: Untergeordneter VHDL-Code des von Hand geschriebenen D-Flip-Flops.

## ERSETZT:   GCLK6 ist auf FPGA-Chip Pin 56
NET "CLOCK6MHZ" LOC = "P56";
NET "CLOCK6MHZ" IOSTANDARD = LVCMOS25;

## statt dessen einfacher Taster:
## NET "CLOCK"  LOC = "P142" | PULLUP | IOSTANDARD = LVCMOS33;
## dedizierten Clock-Eingang nehmen, um Warnung weg zu bekommen:
NET "CLOCK"  LOC = "P122" | PULLUP | IOSTANDARD = LVCMOS33;
## NET "CLOCK" CLOCK_DEDICATED_ROUTE = FALSE;

NET "VIERBIT<3>"   LOC = "P126";
NET "VIERBIT<2>"   LOC = "P130";
NET "VIERBIT<1>"   LOC = "P131";
NET "VIERBIT<0>"   LOC = "P132";

NET "VIERBIT<3>" IOSTANDARD = LVCMOS33; 
NET "VIERBIT<2>" IOSTANDARD = LVCMOS33; 
NET "VIERBIT<1>" IOSTANDARD = LVCMOS33; 
NET "VIERBIT<0>" IOSTANDARD = LVCMOS33; 

NET "RESET"  LOC = "P12"  | PULLUP | IOSTANDARD = LVCMOS33;

NET "BITIN"  LOC = "P135" | PULLUP | IOSTANDARD = LVCMOS33;

Code 0-13: Constraints zu Schieberegister mit Clock über Taster und temporärer Desensibilisierung dieses Tasters.

Übung
  • Analysieren Sie die obigen Musterlösungen.
  • Überprüfen Sie insbesondere, ob Sie die Desensibilisierung des Tasters verstehen (vergl. oben)

LUT4

69_FPGA/13_LUT
Übung -- Konfigurierbares Lauflicht mittels LUT4

Das Konzept "Lauflicht" soll auf die Verwendung von Lookup-Tabellen übertragen werden.

  • Bedenken Sie:
  • Sie haben vier LUT4.
  • Jedes dieser Elemente hat genau einen Ausgang.
  • Jeder dieser vier Ausgänge soll nach außen als eine LED des Lauflichts mit vier Elementen zu sehen sein.
  • An die vier LUT4-Elemete ist ein und derselbe Binärzähler angeschlossen.
  • Skizzieren Sie das Gesamtsystem mittels gedachter digitaler Baugruppen.
  • Für die Dauer von je vier Takten des Binärzählers soll erst die erste, dann die zweite, die dritte, die vierte und dann wieder die erste usw. LED lauchten.
  • Wie sind dann die "generic maps" der vier LUT4-Elemente zu instanziieren? Diskutieren Sie das untereinander.
  • Ein Taktzyklus des Binärzählers soll eine halbe Sekunde dauern.
  • Wie lange leuchtet dann nach dem voran erläuterten jede LED?
  • Setzen Sie das Projekt um.
  • Überlegen Sie sich andere Blinkmuster und wie dann die Generic-maps zu ändern sind. Stellen Sie diese Varianten später für alle vor.

Donnerstag 20.05.2021

Themen

  • UART-Schnittstelle
  • Emulation einer RS232-Verbindung
  • Benachrichtigungen an den PC bei veränderten Schaltzuständen
  • Senden von ganzen positiven Zahlen oder Null.
  • Überlegungen zur Modularisierung

In anderen Zusammenhängen, beispielsweise Mikrocontrollertechnik, haben Sie wahrscheinlich Bussysteme und insbesondere die UART-Schnittstelle kennengelernt.

Hier sind einige Angaben dazu als Wiederholung:

45_Mikro17/07_UART/02_UART
45_Mikro17/07_UART/03_RS232

Einfacher Test einer Emulation von RS232 mit einem FPGA vom Typ Artix7 und einer Taktquelle von 100MHz

Das nachfolgende Beispiel ist nicht für das FPGA-Board umgesetzt worden, auf dem in diesem Kurs gearbeitet wird. Aber es soll in der Übung danach für dieses angepaßt werden.

FPGA#2 -- Emulation einer einfachen UART/RS232 Verbindung an zwei digitalen Pins. Simples Sendebeispiel und simples Empfangsbeispiel als erster Test, dann Modularisierung mit Beispiel und Anleitung. Arduino dient als Zwischenstation zum PC. Eventuell Erweiterung hin zu einer Midi-Schnittstelle.
  • Um die Emulation testen zu können wird ein Mikrocontroller (Arduino-Micro-Board) als "Bridge" zwischen FPGA und PC verwendet.
  • Für das Senden vom FPGA zum Mikrocontroller sind die unterschiedlichen elektrischen Eigenschaften unkritisch.
  • Im umgekehrten Fall sollte ein Optokoppler oder ein Spannungsteiler eingesetzt werden, oder der sendende Mikrocontroller darf nicht zwischen High (+5Volt) und Low wechseln, sondern zwischen "Digitaler Eingang" und "Low und digitaler Ausgang". Letzteres setzt aber seinerseits eine Implementierung als Emulation auf der Mikrocontrollerseite voraus.

Funktion des nachfolgenden Beispiels:

  • Die Umsetzung erfolgt auf erdenklich einfachste Weise.
  • Senden der Buchstaben A, B, C, A, B, C, A, usw. im Ein-Sekunden Abstand durch den FPGA an den Mikrocontroller.
  • Verwendung des RS232-Protokolls mit einem Startbit, 8 Datenbits und keinem Stop-Bit und einer Pause von 2-Bit-High-Phase zwischen den Pakteten.
  • Übertragungsrate: 1200 Baud.
  • Beim Arduino-Mikrocontroller wird auf Serial1 empfangen und auf Serial0 an den PC weiter geleitet.
  • Bitmuster der zu senden Zeichen:
  • A=65="01000001", B=66="01000010", C=67="01000011".
  • FPGA-seitig kann somit auf einem digitalen Ausgang einfach zyklisch folgendes Bitmuster augegeben werden:
  • "110_10000010_110_01000010_110_11000010" (Führend: 2High-Pegel gefolgt vom Startbit, dann das Bitmuster des ASCII-Zeichens in umgekehrter Reihenfolge)
  • Bei einem 100MHz Takt muß für die bitweise Übertragung eine Vorteilung v von v=round(100000000/1200)= 83333 erfolgen.
  • Ausgang PMOD: AB18
  • 100MHz-Clock: R4 ...
...vergleiche hierzu: 68_nexys/05_Nexys_Video/02_PMOD
Hinweise zur Emulation: https://www.vs.inf.ethz.ch/edu/WS9900/VS/VernetSys5.pdf
  • Die Massen (GND) von Mikrocontroller und FPGA-Board müssen miteinander verbunden werden, um ein definiertes Potential auf der Datenleitung übertragen zu können.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity serial is
    Port ( MEINECLOCK : in   STD_LOGIC;
            TXD  : out  STD_LOGIC);
end serial;

architecture Behavioral of serial is
  --constant pattern: STD_LOGIC_VECTOR(0 to 32) := "110_10000010_110_01000010_110_11000010";
  -- !!!! to NICHT DOWNTO hier !!!!
  -- Pause zwischen Frames um 2 Zyklen verlängert: 11110 statt 110.	 
    constant pattern: STD_LOGIC_VECTOR(0 to 38) := "111101000001011110010000101111011000010";
    signal zaehler    : integer range 0 to 83332 := 0; --1200Baud
    signal index      : integer range 0 to 39 := 0;
    signal logikpegel : std_logic := '1'; -- Beim Start sicherer High-Pegel

begin
        process begin
            wait until rising_edge(MEINECLOCK);
            if (zaehler<83332) then
                zaehler <= zaehler+1;
            else
                zaehler <= 0;
                logikpegel <= pattern(index);
                index <= index +1;
                if (index=39) then
                     index <= 0;
                end if;	  
            end if;
        end process;
        TXD <= logikpegel;
end Behavioral;

Code 0-14: VHDL-File, das mit 1200Baud seriell ABCABCABC usw. sendet.

## 100MHz Clock auf Board
NET "MEINECLOCK" LOC = "R4";
## PMOD-Ausgang
NET "TXD"   LOC = "AB18";
NET "MEINECLOCK" IOSTANDARD = LVCMOS25;
NET "TXD"   IOSTANDARD = LVCMOS12; 

Code 0-15: Zugehörige Constraints

nexys_abc_serial.zip -- Projekt zur seriellen Übertragung von ABCABC... erstellt mit ISE14.7
//Leitet empfangene serielle
//Daten von Serial1 an Serial0 (PC) weiter.

void setup() 
{
   Serial.begin(9600);
   Serial1.begin(1200);
}
int zeichen = 32;
void loop() 
{
    if(Serial1.available())
    {
        Serial.write(Serial1.read());
    }    
}

Code 0-16: Arduino-Programm zum Empfangen und Weiterleiten der Daten

Verbindung zwischen Nexys-Video und Arduino-Micro. AB18->RXD, GND->GND

Bild 0-2: Verbindung zwischen Nexys-Video und Arduino-Micro. AB18->RXD, GND->GND

Ausgabe auf Serial Monitor in der Arduino IDE.

Bild 0-3: Ausgabe auf Serial Monitor in der Arduino IDE.

ENDE VON "FPGA#2 -- Emulation einer einfachen UART/RS232 Verbindung an zwei digitalen Pins. Simples Sendebeispiel und simples Empfangsbeispiel als erster Test, dann Modularisierung mit Beispiel und Anleitung. Arduino dient als Zwischenstation zum PC. Eventuell Erweiterung hin zu einer Midi-Schnittstelle."
Übung
  1. Analysieren Sie das obige Beispiel sorgfältig.
  2. Passen Sie obiges Beispiel so an, dass es auf Ihrem Board zusammen mit dem Arduino-Micro läuft.
  3. Variante: Sehen Sie vier Eingänge (Kabel /Schalter IN0,IN1,IN2,IN3 -- frei gewählte Namen, bitte sinnvolle Inputkanäle wählen) vor. Für jede Zustandsänderung soll ein Buchstabe an den PC geschickt werden: Wenn IN0 von LOW nach HIGH, sende 'A', von HIGH nach LOW sende 'B' usw.
  4. Die vier Eingänge repräsentieren ein Vier-Bit-Wort. Übertragen Sie bei jeder Änderung dessen dezimalen Wert an den PC.
  5. Machen Sie sich Gedanken zu einer Modularisierung der emulierten seriellen Schnittstelle. Stellen Sie Ihr Konzept vor. Falls die Zeit reicht: Setzen Sie es um.
Musterlösung zu 2): Passen Sie obiges Beispiel so an, dass es auf Ihrem Board zusammen mit dem Arduino-Micro läuft.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity serialdsp1 is
    Port ( MEINECLOCK : in  STD_LOGIC;
           TXD : out  STD_LOGIC);
end serialdsp1;

architecture Behavioral of serialdsp1 is
    constant pattern: STD_LOGIC_VECTOR(0 to 38) := "111101000001011110010000101111011000010";
    signal zaehler    : integer range 0 to 4999 := 0; --1200Baud
    signal index      : integer range 0 to 39 := 0;
    signal logikpegel : std_logic := '1'; -- Beim Start sicherer High-Pegel
begin
        process begin
            wait until rising_edge(MEINECLOCK);
            if (zaehler<4999) then
                zaehler <= zaehler+1;
            else
                zaehler <= 0;
                logikpegel <= pattern(index);
                index <= index +1;
                if (index=39) then
                     index <= 0;
                end if;	  
            end if;
        end process;
        TXD <= logikpegel;
end Behavioral;

Code 0-17: VHDL-Queltext (ABC zyklisch seriell übertragen mittels DSPFPGA mit 1200Baud)

## GCLK6 ist auf FPGA-Chip Pin 56
NET "MEINECLOCK" LOC = "P56";
## IO_L05P_0 ist auf FPGA-Chip Pin 125
NET "TXD"   LOC = "P125";

NET "MEINECLOCK" IOSTANDARD = LVCMOS25;
NET "TXD"   IOSTANDARD = LVCMOS33; 

Code 0-18: Constraints (.ucf-Datei).

serialdsp1.zip -- Obiges Projekt erstellt mit ISE14.7 für Spartan3E / DSPFPGA.
//Leitet empfangene serielle
//Daten von Serial1 an Serial0 (PC) weiter.

void setup() 
{
   Serial.begin(9600);
   Serial1.begin(1200);
}
int zeichen = 32;
void loop() 
{
    if(Serial1.available())
    {
        Serial.write(Serial1.read());
    }    
}

Code 0-19: Quelltext Arduino-seitig (ArduinoMicro)

Plan der Verbindungen zwischen Mikrocontroller und FPGA.

Bild 0-4: Plan der Verbindungen zwischen Mikrocontroller und FPGA.

Foto der Verbindungen zwischen Mikrocontroller und FPGA.

Bild 0-5: Foto der Verbindungen zwischen Mikrocontroller und FPGA.

Ausgabe über den Seriellen Monitor (Teil der Arduino-IDE)

Bild 0-6: Ausgabe über den Seriellen Monitor (Teil der Arduino-IDE)

Teillösung 3): Je nach IN0 wird das ein- oder andere Muster gesendet

Wichtig: Die Variable hilfe wird benötigt, um nur dann zwischen den zu sendenden Mustern zu wechseln, wenn das letzte vollständig übertragen wurde.


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity serial is
Port ( MEINECLOCK : in STD_LOGIC;
TXD : out STD_LOGIC;
In0 : in STD_LOGIC;
In1 : in STD_LOGIC;
In2 : in STD_LOGIC;
In3 : in STD_LOGIC);
end serial;

architecture Behavioral of serial is
--constant pattern: STD_LOGIC_VECTOR(0 to 32) := "110_10000010_110_01000010_110_11000010";
-- !!!! to NICHT DOWNTO hier !!!!
-- Pause zwischen Frames um 2 Zyklen verlängert: 11110 statt 110.
constant pattern0: STD_LOGIC_VECTOR(0 to 12) := "1111010000010"; --A
constant pattern1: STD_LOGIC_VECTOR(0 to 12) := "1111001000010"; --B
constant pattern2: STD_LOGIC_VECTOR(0 to 12) := "1111011000010"; --C
constant pattern3: STD_LOGIC_VECTOR(0 to 12) := "1111000100010"; --D


signal zaehler : integer range 0 to 4999 := 0; --1200Baud //Berechnung des taktes ... taktfrequenz des Bords geteilt durch gewünschte Baudrate -- also 6000000/1200=5000 (da wir bei 0 beginnen also 4999)
signal index : integer range 0 to 13 := 0;
signal logikpegel : std_logic := '1'; -- Beim Start sicherer High-Pegel
signal hilfe : std_logic := '0';

begin
   process begin
   wait until rising_edge(MEINECLOCK);
   if (zaehler<4999) then
      zaehler <= zaehler+1;
   else
      if (hilfe='1') then
         logikpegel <= pattern0(index);
      else --if (hilfe='0') then
          logikpegel <= pattern1(index);
      end if;
      index <= index +1;
      if (index=13) then
          index <= 0;
          if (In0='1') then
              hilfe<='1';
          else
              hilfe<='0';
          end if;
      end if;

      zaehler <= 0;
    end if;

end process;
TXD <= logikpegel;
end Behavioral;

Code 0-20: VHDL-Datei

## 6MHz Clock auf Board
NET "MEINECLOCK" LOC = "P56";

##Output
NET "TXD" LOC = "P126" | IOSTANDARD = LVCMOS33;

##Input
NET "In0" LOC = "P135" | PULLUP | IOSTANDARD = LVCMOS33 ;
NET "In1" LOC = "P139" | PULLUP | IOSTANDARD = LVCMOS33 ;
NET "In2" LOC = "P140" | PULLUP | IOSTANDARD = LVCMOS33 ;
NET "In3" LOC = "P142" | PULLUP | IOSTANDARD = LVCMOS33 ; 

Code 0-21: UCF-Datei

Donnerstag 27.05.2021

Themen

Fortsetzung der Umsetzung einer seriellen Datenübertragung, insbesondere:

  • Analyse der Teillösung von letzter Woche.
  • Gemeinsame Diskussion zu prinzipiellen Varianten zur Anzeige eines aktuell eingestellten Bitmusters.
  • Individuelle Umsetzung weiterer Lösungsvarianten und deren Vorstellung.

Die Arbeit heute ist ergebnisoffen. Der "selbstbewußte" Umgang mit der Programmiersprache VHDL soll so etwas gefördert werden.

Zu klären:

  • Welche Möglichkeiten können gefunden werden, zwischen verschiedenen zu sendenden Bitmustern umzuschalten?
  • Wie kann man erreichen nur Bei Änderungen etwas zu senden?
  • Wie kann die Übertragung von ASCII-Zeichen modularisiert und vereinfacht in der Verwendung werden?
Eine Lösung, wie das Pattern als ASCII-Zeichen, z.B. 1100 übertragen werden kann
Diskutieren Sie Lösungsmöglichkeiten für folgende Weiterentwicklungen:

Fall1: Bei Zustandsänderungen an den 4 Eingängen wird nur einmalig 
einmal ein Buchstabe gesendet.

1. Ansatz: Abfrage von rising/falling-edge nutzen, um nur
genau in diesen Augenblicken etwas zu senden.

... nachgelesen: Rising/Falling-edge
reserviert für Clocks / ungeeignet für Auswertung
von Schaltern und Tastern.

Problem: Ansätz, bei denen mehr als ein
Pattern gleichzeitig gesendet werden müßte.

Idee: Arduino sagt FPGA, dass er aufhören soll zu senden,
wenn ein Buchstabe empfangen wurde.

2. Ansatz: 4 Schleifen, 4 Hilfsvariablen...
Keine Lösungsidee das alles zusammenzubringen.
Keine Idee, dass nur 1 A gesendet wird und nicht dauernd
welche.

 

Fall2a: Zyklisch wird der komplette 4-Bit-Zustand an den 
Mikrocontroller gesendet 1110 1110 1110...

Lösung (wenn auch aufwändig):
Alle 16 möglichen Pattern als zu sendende Bitfolge
bereitstellen und über den Index, der aus den
4Bit in diesem Fall gewonnen wird auswählen.
Flexibilisierung:
Statt alle Muster komplett bereit zu halten,
bauen wir die Muster nach Bedarf zusammen.
nach dem Prinzip hier:
--Verknüpfung zweier Vierbit-Worte zu einem 8-Bit-Wort
wort3 <= wort1 & wort2;
http://www.kramann.info/69_FPGA/11_VHDL/index.php
Ich halte bereit:
Pattern um 1 zusenden als ASCII-Zeichen: P1
Pattern um 0 zusenden als ASCII-Zeichen: P0
je nach Bitmuster am Eingang baue ich "kurz vor dem Senden"
aus 4 solcher Varianten mein zu sendendes Pattern zusammen.

Beispiel:
Ich möchte 1011: zu_senden <= P1 & P0 & P1 & P1;

if(IN0='0') DANN zu_senden <= P0 SONST zu_senden <= P1; 
if(IN1='1') DANN zu_senden <= zu_senden & P0 SONST zu_senden <= zu_senden & P1; 
...

Fall2b: wie a) aber statt des Patterns wird eine diesem 
entsprechende Dezimalzahl zyklisch gesendet.


Code 0-22: Ergebnis der vorangehenden Diskussion

Musterlösung
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity serialpatternsend is
    Port ( MEINECLOCK : in  STD_LOGIC;
           TXD : out  STD_LOGIC;
           IN0 : in  STD_LOGIC;
           IN1 : in  STD_LOGIC;
           IN2 : in  STD_LOGIC;
           IN3 : in  STD_LOGIC);
end serialpatternsend;

architecture Behavioral of serialpatternsend is
    -- pattern: hier wird eine Folge von pnull und peins verkettet, am Anfang High-Pegel, 4*13Bit=52 Einser
	 -- Problem: "71. Size of concat operation is different than size of the target."
	 -- deshalb Hilfspattern der richtigen Länge vorbereiten:
    signal pattern13: STD_LOGIC_VECTOR(0 to 12) := "1111111111111";
    signal pattern26: STD_LOGIC_VECTOR(0 to 25) := "11111111111111111111111111";
    signal pattern39: STD_LOGIC_VECTOR(0 to 38) := "111111111111111111111111111111111111111";
	 signal pattern52: STD_LOGIC_VECTOR(0 to 51) := "1111111111111111111111111111111111111111111111111111";
	 
	 --4er Muster plus Leerzeichen danach!
    signal pattern: STD_LOGIC_VECTOR(0 to 64) := "11111111111111111111111111111111111111111111111111111111111111111";
    constant pnull: STD_LOGIC_VECTOR(0 to 12) := "1111000001100"; -- ASCII-Code von 0 ist 48
    constant peins: STD_LOGIC_VECTOR(0 to 12) := "1111010001100"; -- ASCII-Code von 1 ist 49
    constant leerzeichen: STD_LOGIC_VECTOR(0 to 12) := "1111000000100"; -- ASCII-Code von Leerzeichen ist 32
    signal zaehler    : integer range 0 to 4999 := 0; --1200Baud
    signal index      : integer range 0 to 65 := 0;
    signal logikpegel : std_logic := '1'; -- Beim Start sicherer High-Pegel
    signal SIGIN0 : std_logic := '0'; 
    signal SIGIN1 : std_logic := '0'; 
    signal SIGIN2 : std_logic := '0'; 
    signal SIGIN3 : std_logic := '0'; 
begin
        process begin
            wait until rising_edge(MEINECLOCK);
            if (zaehler<4999) then
                zaehler <= zaehler+1;
            else
                zaehler <= 0;
                logikpegel <= pattern(index);
                index <= index +1;
                if (index=65) then
                     index <= 0;
							--Beginn neuer Teil!:							
							-- ausserdem Pattern neu zusammenbauen, gemäß 
							-- Zustand an den Eingängen:
							if (SIGIN0='1') then
							    pattern13 <= peins;
							else	 
							    pattern13 <= pnull;
							end if;
							if (SIGIN1='1') then
							    --pattern26 <= pattern13 & peins;
							    pattern26 <= peins & pattern13;
							else	 
							    --pattern26 <= pattern13 & pnull;
							    pattern26 <= pnull & pattern13;
							end if;
							if (SIGIN2='1') then
							    --pattern39 <= pattern26 & peins;
							    pattern39 <= peins & pattern26;
							else	 
							    --pattern39 <= pattern26 & pnull;
							    pattern39 <= pnull & pattern26;
							end if;
							if (SIGIN3='1') then
							    --pattern52 <= pattern39 & peins;
							    pattern52 <= peins & pattern39;
							else	 
							    --pattern52 <= pattern39 & pnull;
							    pattern52 <= pnull & pattern39;
							end if;
							--pattern <= pattern52 & leerzeichen;
							pattern <= leerzeichen & pattern52;
							--Ende neuer Teil!
                end if;	  
            end if;
        end process;
        TXD <= logikpegel;
		  SIGIN0 <= IN0;
		  SIGIN1 <= IN1;
		  SIGIN2 <= IN2;
		  SIGIN3 <= IN3;
end Behavioral;

Code 0-23: Musterlösung: Bitmuster am Eingang wird in zu sendendes Pattern mit 4 Zeichen + Leerzeichen umgewandelt.

## GCLK6 ist auf FPGA-Chip Pin 56
NET "MEINECLOCK" LOC = "P56";
## IO_L05P_0 ist auf FPGA-Chip Pin 125
NET "TXD"   LOC = "P125";

NET "MEINECLOCK" IOSTANDARD = LVCMOS25;
NET "TXD"   IOSTANDARD = LVCMOS33; 

NET "IN0"  LOC = "P135" | PULLUP  | IOSTANDARD = LVCMOS33 ;
NET "IN1"  LOC = "P139" | PULLUP  | IOSTANDARD = LVCMOS33 ;
NET "IN2"  LOC = "P140" | PULLUP  | IOSTANDARD = LVCMOS33 ;
NET "IN3"  LOC = "P142" | PULLUP  | IOSTANDARD = LVCMOS33 ;

Code 0-24: Constraints zum gleichen Projekt.

Screenshot: Links Kamerabild der erweiterten Schaltung mit Dipschaltern, hier auf 1001 gesetzt. Rechts: Serial-Monitor liefert auch Muster 1001.

Bild 0-7: Screenshot: Links Kamerabild der erweiterten Schaltung mit Dipschaltern, hier auf 1001 gesetzt. Rechts: Serial-Monitor liefert auch Muster 1001.

//Leitet empfangene serielle
//Daten von Serial1 an Serial0 (PC) weiter.

void setup() 
{
   Serial.begin(9600);
   Serial1.begin(1200);
}
long x=0;
int c=32;
void loop() 
{
    if(Serial1.available())
    {
        c = Serial1.read();
    }    
    if(x%1000==0)
    {
        Serial.write(c);
        Serial.write('\r');
        Serial.write('\n');
    }    
    x++;
}

Code 0-25: Veränderter Arduino-Code, der nur alle tausend Zeichen etwas anzeigt.

Donnerstag 03.06.2021


WICHTIG: Gruppenaufteilung für Probe-E-Test festlegen!


Themen

  • Gelegenheit, inhaltliche Fragen und Wünsche etwas zu wiederholen zu äußern
  • Endlicher Automat
  • Verbesserung der Programmstruktur des seriellen Senders
  • Verallgemeinerung des Anwendungsbereiches des seriellen Senders
  • Modularisierung für seriellen Sender

Vorstellung des Konzepts innerer Zustände eines Systems


https://en.wikipedia.org/wiki/Finite-state_machine (passender als de-Version unten)
https://de.wikipedia.org/wiki/Endlicher_Automat

Anwendungsfall: Innere Zustände sind bei der seriellen Datenübertragung:

  • Gerade wird noch ein Datenpaket übermittelt.
  • Gerade wird kein Datenpaket übermittelt.

Andere Beispiele:

  • Fußgängerampel: Während der Grünphase, soll diese nicht durch erneutes Drücken verlängert werden können. Innerer Zustand: grün und verbleibende Dauer oder rot-Phase.

Weitere Themen

  • Vereinfachung / Variation der Lösung zum seriellen Senden eines Bitmusters aus der letzten LV.
  • Modularisierung von Codeblöcken: Wiederholung D-Flip-Flop / Übertragung auf seriellen Sender.
69_FPGA/09_Uebung -- siehe "Lösung zu Aufgabe 3" ... D-Flip-Flop als Modul.

Diskussion: Flag als inneren Zustand einführen, das sagt: Hier ist etwas Neues zum senden. Oder: Veränderung im Gesamtzustand erkennen und nur dann senden. Zuerst: als ein einziges Programm. Später: als Modul umsetzen.

Hinweise / Übung

9:00-10:00 Uhr erste Gruppe
Fritsche 
Mielke 
Seela
Zuber
Wenzel
Gebauer

alle anderen, auch wer nicht da ist: 2. Gruppe
10:30Uhr zweite Gruppe
bis 11:30Uhr 

Übung1: gleich lange Hilfsvariablen hilf0..3 einführen.
Übung2: Zyklisch im Sekundentakt Ziffern 0..9 senden
Übung3: wie Ü2, aber das zyklische Senden ist ein Testfall für
die allgemeinere Fähigkeit einzelne ASCII-Zeichen zu senden.

Code 0-26: Hinweise / Übung

Musterlösung zu Übung 1
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity serial is
    Port ( MEINECLOCK : in  STD_LOGIC;
           TXD : out  STD_LOGIC;
           IN0 : in  STD_LOGIC;
           IN1 : in  STD_LOGIC;
           IN2 : in  STD_LOGIC;
           IN3 : in  STD_LOGIC);
end serial;

architecture Behavioral of serial is
    -- pattern: hier wird eine Folge von pnull und peins verkettet, am Anfang High-Pegel, 4*13Bit=52 Einser
	 -- Problem: "71. Size of concat operation is different than size of the target."
	 -- deshalb Hilfspattern der richtigen Länge vorbereiten:
    signal hilf0: STD_LOGIC_VECTOR(0 to 12) := "1111111111111";
    signal hilf1: STD_LOGIC_VECTOR(0 to 12) := "1111111111111";
    signal hilf2: STD_LOGIC_VECTOR(0 to 12) := "1111111111111";
    signal hilf3: STD_LOGIC_VECTOR(0 to 12) := "1111111111111";
	 
	 --4er Muster plus Leerzeichen danach!
    signal pattern: STD_LOGIC_VECTOR(0 to 64) := "11111111111111111111111111111111111111111111111111111111111111111";
    constant pnull: STD_LOGIC_VECTOR(0 to 12) := "1111000001100"; -- ASCII-Code von 0 ist 48
    constant peins: STD_LOGIC_VECTOR(0 to 12) := "1111010001100"; -- ASCII-Code von 1 ist 49
    constant leerzeichen: STD_LOGIC_VECTOR(0 to 12) := "1111000000100"; -- ASCII-Code von Leerzeichen ist 32
    signal zaehler    : integer range 0 to 4999 := 0; --1200Baud
    signal index      : integer range 0 to 65 := 0;
    signal logikpegel : std_logic := '1'; -- Beim Start sicherer High-Pegel
    signal SIGIN0 : std_logic := '0'; 
    signal SIGIN1 : std_logic := '0'; 
    signal SIGIN2 : std_logic := '0'; 
    signal SIGIN3 : std_logic := '0'; 
begin
        process begin
            wait until rising_edge(MEINECLOCK);
            if (zaehler<4999) then
                zaehler <= zaehler+1;
            else
                zaehler <= 0;
                logikpegel <= pattern(index);
                index <= index +1;
                if (index=65) then
                     index <= 0;
							--Beginn neuer Teil!:							
							-- ausserdem Pattern neu zusammenbauen, gemäß 
							-- Zustand an den Eingängen:
							if (SIGIN0='1') then
							    hilf0 <= peins;
							else	 
							    hilf0 <= pnull;
							end if;
							if (SIGIN1='1') then
							    --pattern26 <= pattern13 & peins;
							    hilf1 <= peins;
							else	 
							    --pattern26 <= pattern13 & pnull;
							    hilf1 <= pnull;
							end if;
							if (SIGIN2='1') then
							    --pattern39 <= pattern26 & peins;
							    hilf2 <= peins;
							else	 
							    --pattern39 <= pattern26 & pnull;
							    hilf2 <= pnull;
							end if;
							if (SIGIN3='1') then
							    --pattern52 <= pattern39 & peins;
							    hilf3 <= peins;
							else	 
							    --pattern52 <= pattern39 & pnull;
							    hilf3 <= pnull;
							end if;
							--pattern <= pattern52 & leerzeichen;
							pattern <= leerzeichen & hilf3 & hilf2 & hilf1 & hilf0;
							--Ende neuer Teil!
                end if;	  
            end if;
        end process;
        TXD <= logikpegel;
		  SIGIN0 <= IN0;
		  SIGIN1 <= IN1;
		  SIGIN2 <= IN2;
		  SIGIN3 <= IN3;
end Behavioral;

Code 0-27: Übung1 VHDL-Code (gleichlange Hilfsvariablen hilf0..3)

Musterlösung Ü2 (nicht getestet!)
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values

-- wegen der arithmetrischen Operationen:
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity serialziffern is
    Port ( MEINECLOCK : in  STD_LOGIC;
           TXD : out  STD_LOGIC);
end serialziffern;

architecture Behavioral of serialziffern is
    --Benutzer des Sendemoduls
    signal xwert      : integer range 0 to 9 := 0; --das, was gesendet werden soll
	 
	 --Sendemodul:
    signal logikpegel : std_logic := '1'; -- Beim Start sicherer High-Pegel
    signal zaehler    : integer range 0 to 4999 := 0; --1200Baud
	 signal zeichen    : integer range 0 to 255 := 32; --zu sendendes ADCII-Zeichen
    signal fertig     : std_logic := '1'; -- '1'=> bereit für neues Zeichen
    signal neu        : std_logic := '1'; -- '1'=> neues Zeichen liegt vor
    signal index      : integer range 0 to 13 := 0; -- immer nur ein Zeichen senden
    constant leerzeichen: STD_LOGIC_VECTOR(0 to 7) := "00000100"; -- ASCII-Code von Leerzeichen	 
    signal ascii: STD_LOGIC_VECTOR(0 to 7) := leerzeichen; 
    signal pattern: STD_LOGIC_VECTOR(0 to 12) := "1111000000100";
begin
	 
    process begin
        wait until rising_edge(MEINECLOCK);
        if (zaehler<4999) then
            zaehler <= zaehler+1;
        else
		      zaehler <= 0;
				-- drei Möglichkeiten:
				-- 1) ist fertig, es liegt neues Zeichen an
				-- 2) ist fertig, es liegt kein neues Zeichen an
				-- 3) sendet noch Rest von Zeichen
				
				if (fertig = '0') then
				    logikpegel <= pattern(index);
				    index <= index +1;
					 -- wechsel des inneren Zustands bei Überlauf von index:
					 if (index=13) then
					     index <= 0; --bereit für neuen Sendezyklus
						  fertig <= '1'; --bereit neues Zeichen zum senden zu bekommen
					 end if;
				else -- wenn gerade nichts gesendet wird...
				    -- ... und ein neues Zeichen bereit liegt
					 if (neu='1') then
					     -- neues Zeichen in den puffer übernehmen
						  ascii <= conv_std_logic_vector(zeichen,ascii'length);
						  -- Bitreihenfolge umdrehen (?)
						  --ascii <= ascii(0) & ascii(1) & ascii(2) & ascii(3) & ascii(4) & ascii(5) & ascii(6) & ascii(7);
						  -- zu sendendes Pattern bilden, immer mit High-Pegel enden!
						  pattern <= "11" & ascii & "110";
						  fertig <= '0'; --senden im nächsten Zyklus starten
						  neu <= '0'; --Bereitschaft für neues Zeichen signalisieren
					 else
					     -- wenn kein neues Zeichen bereitliegt, dann
						  -- neues Zeichen bereit stellen.
						  -- Dieser Teil kommt später in einen anderen Prozess!
						  -- er repräsentiert die Benutzung des Sendemoduls.
						  -- Genau hier macht dann in Zukunft das Sendemodul gar nichts!
						  -- im andere Prozeß wird dann geprüft: neu='0' 
						  
                    --Benutzer des Sendemoduls
						  
						  -- Aktuelle Ziffer zum Senden vorbereiten:
						  zeichen <= 48+xwert;
						  
						  -- Verändern des aktuellen Wertes
                    if (xwert<9) then
                        xwert <= xwert+9;
                    else
		                  xwert <= 0;	
                    end if;								
					 end if;
				end if;
	     end if;
    end process;
TXD <= logikpegel;
end Behavioral;

Code 0-28: Musterlösung Ü2 (nicht getestet!)

studentische Teillösung
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;

entity MehrZiffern is
Port ( CLOCK : in STD_LOGIC;
TxD : out STD_LOGIC;
IN0 : in STD_LOGIC;
IN1 : in STD_LOGIC;
IN2 : in STD_LOGIC;
IN3 : in STD_LOGIC);
end MehrZiffern;

architecture Behavioral of MehrZiffern is

signal hilf0: STD_LOGIC_VECTOR(0 to 12) := "1111111111111";
signal hilf1: STD_LOGIC_VECTOR(0 to 12) := "1111111111111";
signal hilf2: STD_LOGIC_VECTOR(0 to 12) := "1111111111111";
signal hilf3: STD_LOGIC_VECTOR(0 to 12) := "1111111111111";

--4er Muster plus Leerzeichen danach!
-- signal pattern: STD_LOGIC_VECTOR(0 to 64) := "11111111111111111111111111111111111111111111111111111111111111111";
signal pattern: STD_LOGIC_VECTOR (0 to 25) := "11111111111111111111111111";

constant pnull: STD_LOGIC_VECTOR(0 to 12) := "1111000001100"; -- ASCII-Code von 0 ist 48
constant peins: STD_LOGIC_VECTOR(0 to 12) := "1111010001100"; -- ASCII-Code von 1 ist 49

constant leerzeichen: STD_LOGIC_VECTOR(0 to 12) := "1111000000100"; -- ASCII-Code von Leerzeichen ist 32
signal zaehler : integer range 0 to 4999 := 0; --1200Baud
signal index : integer range 0 to 25 := 0;
signal logikpegel : std_logic := '1'; -- Beim Start sicherer High-Pegel
signal SIGIN0 : std_logic := '0';
signal SIGIN1 : std_logic := '0';
signal SIGIN2 : std_logic := '0';
signal SIGIN3 : std_logic := '0';

-- 0 bis 9 vereinbaren??
signal zahl: integer range 0 to 9 :=0;
signal Zahlen: STD_LOGIC_VECTOR (0 to 7) := "11111111";
--constant pnull: STD_LOGIC_VECTOR(0 to 12) := "1111000001100"; 0
--constant peins: STD_LOGIC_VECTOR(0 to 12) := "1111010001100"; 1
--constant pzwei: STD_LOGIC_VECTOR(0 to 12) := "1111001001100"; 2
--constant pdrei: STD_LOGIC_VECTOR(0 to 12) := "1111011001100"; 3
--constant pvier: STD_LOGIC_VECTOR(0 to 12) := "1111000101100"; 4
--constant pfuenf: STD_LOGIC_VECTOR(0 to 12) := "1111010101100"; 5
--constant psechs: STD_LOGIC_VECTOR(0 to 12) := "1111001101100"; 6
--constant psieben: STD_LOGIC_VECTOR(0 to 12) := "1111011101100"; 7
--constant pacht: STD_LOGIC_VECTOR(0 to 12) := "1111000011100"; 8
--constant pneun: STD_LOGIC_VECTOR(0 to 12) := "1111010011100"; 9

signal zahl1999: integer range 0 to 1999 := 0;

begin
process begin
wait until rising_edge(CLOCK);
if (zaehler<4999) then
zaehler <= zaehler+1;
else
zaehler <= 0;

logikpegel <= pattern(index);
index <= index +1;
if (index=26) then
index <= 0;

if (zahl1999<1999) then
zahl1999 <= zahl1999 +1;
else
zahl1999 <= 0;


Zahlen <= conv_std_logic_vector(zahl + 48 , Zahlen'length);
zahl <=zahl + 1;
if(zahl = 9) then zahl <= 0; end if;
--Zahlen <= Zahlen(0) & Zahlen(1) & Zahlen(2) & Zahlen(3) & Zahlen(4) & Zahlen(5) & Zahlen(6) & Zahlen(7);
Zahlen <= Zahlen(7) & Zahlen(6) & Zahlen(5) & Zahlen(4) & Zahlen(3) & Zahlen(2) & Zahlen(1) & Zahlen(0);
end if;


end if;
pattern <= Zahlen & "01111" & leerzeichen;
end if;
end process;
TXD <= logikpegel;
SIGIN0 <= IN0;
SIGIN1 <= IN1;
SIGIN2 <= IN2;
SIGIN3 <= IN3;
end Behavioral;

Code 0-29: studentische Teillösung.