Hallo!
Ich arbeite gerade an einer Finite State Machine, welche einen Satz von
Befehlen dekodieren soll, dann den Befehl ausführen und zum Schluss den
Programmzähler auf den nächsten Befehl setzen.
Dummerweise scheint an diesem System irgendetwas fehlerhaft zu sein, vor
Allem in Bezug auf die beiden SPI-Befehle. Der Zugriff auf das
SPI-System als solches funktioniert grunsätzlich gut, jedoch nicht aus
der State-Machine heraus. Interessanterweise läuft die State Machine an,
wenn man die SPI-Befehle auskommentiert und stattdessen nur den
Programmcounter erhöht. Jedoch kommt das System auch dann scheinbar nur
bis zu dem längeren Wartebefehl.
Ich habe den Eindruck, dass das gesamte System vom Grundaufbau her
fehlerhaft ist, ggf. könnte der Fehler auch an Timing-Problemen liegen.
Zum Teil ändern sich bedeutende Systemeigenschaften, wenn ich irgendein
Signal ändere, das eigentlich nur kleinere Auswirkungen haben sollte.
Ich komme an dieser Stelle schlichtweg nicht weiter (ich kenne mich auch
kaum mit den Timing-Constraints aus (für ein gutes Tutorial wäre ich
dankbar)), und würde mich freuen, wenn jemand Fehler finden würde.
Die FSM (Ich möchte hier nicht das komplette Projekt posten, da es den
Rahmen sprengen würde, kann aber gerne noch gewünschte Programmteile
nachliefern):
> main: process(
Aha, ein Softwerker, der auf Hardware umsteigt...
> main: process(CLK, Reset, Schiebe_rdy_rec, Schiebe_start, SPI_RDY, SDI)
Dieser Pozess ist komplett synchron und somit lediglich auf den Takt
sensitiv. In dieser Sensitivliste steht also viel zuviel Zeug. Das ist
zwar "nur" ein Schönheitsfehler, zeigt aber ein leichtes Unverständnis
auf.
> variable programmcounter: integer range 0 to Anzahl_befehle := 0;> variable zaehler_prog : integer := 0;> variable ...> variable ...> variable ...
Softwerker nehmen gern Variablen (weil der Name geläufig ist!).
Allerdings haben diese Dinger in einer Hadrwarebeschreibung anderes
Verhalten und auch mal unschöne Auswirkungen wie der
Beitrag "Variable vs Signal" aufzeigt.
Martin S. schrieb:> Dummerweise scheint an diesem System irgendetwas fehlerhaft zu sein
Was sagt die Simulation?
> ggf. könnte der Fehler auch an Timing-Problemen liegen.
Hast du Timing-Constraints angegeben? Weiß die Toolchain wenigstens, was
du für einen Takt hast?
> Zum Teil ändern sich bedeutende Systemeigenschaften, wenn ich irgendein> Signal ändere, das eigentlich nur kleinere Auswirkungen haben sollte.
Hört sich nach asynchronen bzw. nicht einsynchronisierten Signalen an.
Woher kommt z.B. das Schiebe_rdy_rec oder Schiebe_start?
@ Martin S. (maklin)
>Ich arbeite gerade an einer Finite State Machine, welche einen Satz von>Befehlen dekodieren soll, dann den Befehl ausführen und zum Schluss den>Programmzähler auf den nächsten Befehl setzen.
Kleiner Tip. Nutze symbolische Namen für die States, das macht die Sache
DEUTLICH lesbarer.
>Dummerweise scheint an diesem System irgendetwas fehlerhaft zu sein,
Wie stellst du das fest?
>Ich habe den Eindruck, dass das gesamte System vom Grundaufbau her>fehlerhaft ist, ggf. könnte der Fehler auch an Timing-Problemen liegen.
Rätselraten. Du musst messen und prüfen. Simulation, Oszi,
Logicanalyzer, in der Reihenfolge.
>Zum Teil ändern sich bedeutende Systemeigenschaften, wenn ich irgendein>Signal ändere, das eigentlich nur kleinere Auswirkungen haben sollte.
Rumstochern. Noch schlimmer.
>Ich komme an dieser Stelle schlichtweg nicht weiter (ich kenne mich auch>kaum mit den Timing-Constraints aus (für ein gutes Tutorial wäre ich>dankbar)),
Als ganz einfache Massnahme reicht es, die Frequenz des Taktes
anzugeben. Das ist leicht, schau in deine Hilfe der Tools. Wenn dann
keine asynchronen Sauerein und vergessene Synchronisationen drin sind
(naja, die Hoffnung stirbt zuletzt), sollte es reichen.
> und würde mich freuen, wenn jemand Fehler finden würde.
Das ist kein Ingenieurbüro.
MfG
Falk
Zugegebenermaßen, trotz des langen Posts fehlen noch viele Informationen
meinerseits. Ich werde die Kommentare der Reihe nach beantworten und
dadurch etwas Klarheit bringen:
Kommentare von Lothar Miller:
> Aha, ein Softwerker, der auf Hardware umsteigt...
Grundsätzlich bin ich bei der Thematik VHDL schon seit knapp einem Jahr
dabei. Jedoch handelte es sich größtenteils um reine Simulationen,
welche von Anfang an nie den Sinn hatten, synthetisiert zu werden. Somit
sind die eigentlichen, synthetisierbaren Projekte relativ wenige. Eines
war z.B. das Ping-Pong-Spiel für den PC-Monitor, über welches wir ja
noch vor kurzem in einem anderen Thread gesprochen hatten.
> In dieser Sensitivliste steht also viel zuviel Zeug. Das ist
zwar "nur" ein Schönheitsfehler, zeigt aber ein leichtes Unverständnis
auf.
Genau genommen waren in den Sensitivlisten bis vor Kurzem nur die
Clock-Signale. Irgendwo hatte ich Beispiele gesehen, in denen alle vom
Prozess gelesenen Signale in der Liste enthalten waren, sodass ich es
einfach mal ausprobiert hatte. Aber dann kann ich die zu vielen (und aus
meiner Sicht auch unübersichtlichen) Signale herausnehmen.
> Softwerker nehmen gern Variablen (weil der Name geläufig ist!).
Allerdings haben diese Dinger in einer Hadrwarebeschreibung anderes
Verhalten und auch mal unschöne Auswirkungen wie der
Beitrag "Variable vs Signal" aufzeigt.
Dieser Beitrag hat mir sehr weitergeholfen. Ich werde versuchen,
möglichst alle Variablen zu entfernen, und dann vom Ergebnis berichten.
Für mich war es bislang so:
Variablen: innerhalb einzelner Prozesse, ggf. auch in einem
Clock-Durchgang mehrere Variablenoperationen nacheinander.
Signale: Verbindungen zwischen Prozessen und nach außen hin
> Was sagt die Simulation?
Die Simulation ist schon seit Tagen problemlos, daher verzweifelte ich
auch so an der ganzen Sache.
> Hast du Timing-Constraints angegeben? Weiß die Toolchain wenigstens, was
du für einen Takt hast?
Ja grundsätzlich schon, wobei ich auf dem Gebiet sehr unerfahren bin
(btw.: Hast du die Email bekommen?). Es gibt eine Clock-Angabe:
NET "CLK" TNM_NET = CLK;
TIMESPEC TS_CLK = PERIOD "CLK" 24 MHz HIGH 50% INPUT_JITTER 60 ps;
(Die Angabe "INPUT_JITTER" habe ich mehr oder weniger aus einem (nicht
so nützlichem) Tutorial abgeschrieben, ich muss mich dringend auf dem
Gebiet der Constraints informieren.)
> Hört sich nach asynchronen bzw. nicht einsynchronisierten Signalen an.
Woher kommt z.B. das Schiebe_rdy_rec oder Schiebe_start?
Diese Signale gehen zu einem Prozess, welcher ein High- oder Low-Signal
und ein Taktsignal an ein Schieberegister geben. Dieser Prozess ist
grunsätzlich auch über das Clock-Signal angebunden.
Kommentare von Falk Brunner:
> Kleiner Tip. Nutze symbolische Namen für die States, das macht die Sache
DEUTLICH lesbarer.
Ich habe versucht die Befehle als 12-Bit-Vector-Arrays aufzubauen. Wenn
die Befehle Namen bekommen würden, dann müsste ich 2 Arrays definieren,
eines mit dem jeweiligen Namen und eines mit dem Befehlsdaten. Ich weiß
nicht, ob das nicht umständlicher wird...
>> Dummerweise scheint an diesem System irgendetwas fehlerhaft zu sein,> Wie stellst du das fest?>> Ich habe den Eindruck, dass das gesamte System vom Grundaufbau her
fehlerhaft ist, ggf. könnte der Fehler auch an Timing-Problemen liegen.
> Rätselraten. Du musst messen und prüfen. Simulation, Oszi,
Logicanalyzer, in der Reihenfolge.
Folgendes habe ich gemacht: Simulation (wie bereits erwähnt lief diese
problemlos) sowie Oszilloskopmessungen. Am Oszilloskop konnte man ein
plötzliches Beenden der (eigentlich unenedlich widerholenden)
SPI-Übertragung feststellen. Das Ende kam zu einem zufälligem Zeitpunkt,
jedoch meist im ms-Bereich nach dem Begin der Endlosschleife. Dabei
wurde grundsätzlich das letzte SPI-Byte vollständig übertragen, jedoch
blieb das System im Befehl "0010" (SPI_rec) an der Position
zaehler_prog=2 hängen, obwohl das SPY_rdy bereits vom SPI-Modul auf '1'
gesetzt wurde (herausgefunden über Debug-Signale, die ich am Oszilloskop
überprüft habe). Huh, das war wohl eine etwas klarere Fehlerbeschreibung
:-)
> Rumstochern. Noch schlimmer.
Ja, wenn die klassischen Methoden zuende gehen, dann gehts bei mir
Öfters so weiter...;-)
> Als ganz einfache Massnahme reicht es, die Frequenz des Taktes
anzugeben. Das ist leicht, schau in deine Hilfe der Tools. Wenn dann
keine asynchronen Sauerein und vergessene Synchronisationen drin sind
(naja, die Hoffnung stirbt zuletzt), sollte es reichen.
Siehe oben in der Antwort zu Lothar Miller.
Vielen Dank schonmal an euch beide, dass ihr euch die Zeit genommen habt
in den Code zu schauen!!
Martin S. schrieb:> Ja grundsätzlich schon, wobei ich auf dem Gebiet sehr unerfahren bin> (btw.: Hast du die Email bekommen?).
Ja, aber ich habe leider keine Literaturempfehlung zum Thema
Constraints. Das Thema ist ein relativ hartes Stück Brot, auf dem du so
lange herumprobieren und herumkauen mußt, bis du es schlucken kannst...
Zum Glück gibt es eigentlich nur 4 Arten von Timing Constraints:
1) Laufzeit vom Eingang zum Flipflop
2) Laufzeit von Flipflop zu Flipflop (das ist das Period Constraint)
3) Laufzeit vom Flipflop zum Ausgang
4) Laufzeit vom Eingang zum Ausgang (Kombinatorik)
Kompliziert wird es erst durch Gruppenbildung und dadurch, dass bei
verschiedenen Implementierungsschritten Signale wegoptimiert werden
können...
Martin S. schrieb:> Genau genommen waren in den Sensitivlisten bis vor Kurzem nur die> Clock-Signale. Irgendwo hatte ich Beispiele gesehen, in denen alle vom> Prozess gelesenen Signale in der Liste enthalten waren, sodass ich es> einfach mal ausprobiert hatte. Aber dann kann ich die zu vielen (und aus> meiner Sicht auch unübersichtlichen) Signale herausnehmen.
Nein, es geht nicht ums wahlfreie Rein- oder Rausnehmen von Signalen,
sondern, dass du siehst, was da rein gehört und was nicht.
Vorneweg: nur die Simulation braucht die Sensitivliste!
Und dann müssen in der Sensitivliste alle die Signale sein, die eine
Neuberechnung des Prozesses nötig machen. In einem komplett synchronen
Prozess ist das nur der Takt, denn nur wenn sich der Takt ändert werden
neue Werte berechnet. In einem kombinatorischen Prozess müssen dann alle
Eingangssignale rein, und alle Signale, deren Änderung einen Augangswert
ändern.
Die Synthese wird sich herzlich wenig um die Liste scheren und fehlende
Signale einfach ergänzen.
Aber Achtung! Zu früh gefreut: dieser Automatismus führt dazu, dass mit
einer unvollständigen Liste die Simulation und die Hardware nicht mehr
zusammenpassen!
Martin S. schrieb:> Dieser Beitrag hat mir sehr weitergeholfen. Ich werde versuchen,> möglichst alle Variablen zu entfernen, und dann vom Ergebnis berichten.
Auch hier bitte nicht einfach blind alle Variablen entfernen, sondern
verstehen, wo du damit Probleme bekommen kannst und wirst. Ganz kritisch
sind vor allem SPEICHERNDE Variablen in längeren Prozessen:
[/vhdl]
variable for_prog_cnt : integer range 0 to Anzahl_befehle := 0; --
Merke, wo er im Programm steht, wenn for kommt.
variable while_prog_cnt : integer range 0 to Anzahl_befehle := 0;
-- Merke, wo er im Programm steht, wenn for kommt.
[vhdl]
Denn dann gibt es ein "vorher" und ein "nachher" innerhalb des
Prozesses, und evtl. müsste der Prozess neu berechnet werden, kann das
aber nicht, weil ja Variablen nicht in die Sensitivliste aufgenommen
werden können...
Und wehe, innerhalb des Prozesses wird mal etwas umgestellt (einfach
mal eine Zeile von oben nach unten kopiert), dann kann es sein, nichts
geht mehr...
Wo Variablen problemlos verwendet werden können und gern gesehen sind,
ist dort, wo es gilt, eine komplizierte Berechnung in kleinere Schritte
aufzuteilen. So etwa wie bei lokalen (aber nicht statischen) Variablen
in C.
>> Woher kommt z.B. das Schiebe_rdy_rec oder Schiebe_start?> Diese Signale gehen zu einem Prozess, welcher ein High- oder Low-Signal> und ein Taktsignal an ein Schieberegister geben. Dieser Prozess ist> grunsätzlich auch über das Clock-Signal angebunden.
Dann sind diese Signale eigentlich problemlos...
>Zum Teil ändern sich bedeutende Systemeigenschaften, wenn ich irgendein>Signal ändere, das eigentlich nur kleinere Auswirkungen haben sollte.> Genau genommen waren in den Sensitivlisten bis vor Kurzem nur die> Clock-Signale. Irgendwo hatte ich Beispiele gesehen, in denen alle vom> Prozess gelesenen Signale in der Liste enthalten waren, sodass ich es> einfach mal ausprobiert hatte. Aber dann kann ich die zu vielen (und aus> meiner Sicht auch unübersichtlichen) Signale herausnehmen.> Was sagt die Simulation?> Die Simulation ist schon seit Tagen problemlos, daher verzweifelte ich> auch so an der ganzen Sache.
Oje, die Simulation und die Synthese sind zwei unterschiedliche Sachen.
Mach erst mal deine Sensitivliste richtig und simulier dann nochmal
Gruss
Ralf
Also die Simulation funktioniert in beiden Fällen, also sowohl mit den
vielen Signalen in der Senitiv-Liste, als auch nur mit dem CLK-Signal.
Ich habe zudem nun die Variablen gegen Signale ersetzt, jedoch bleibt
das Verhalten so wie vorher. Es gibt 4 Digital-Analyzer-Aufnahmen im
Anhang des Posts, die ich hier beschreiben möchte. Die Bilder sind mit
80 Mhz aufgenommen, ein Debugsignal gibt mir Auskunft über die MSB der
Befehlsliste, dem Wert von zaehler_prog sowie das Reset- und CLK-Signal.
Die Clock wird mit 24 MHZ betrieben, daher wird sie bei 80 MHZ in
unterschiedlichen Längen bezeichnet, obwohl der Quarz natürlich ein
normales Signal ausgibt.
Bild 1 (SPI_geht_1.png):
Da SDI vom externen ADC auf 0 gezogen wird, kann der Zustand
wait_spi_rdy verlassen werden. Es folgt ein Wartebefehl (0101), welcher
im "zaehler_prog=1"-Zustand herunterzählt...
Bild 2 (SPI_geht_2.png):
Das Warten ist beendet, der Zustand SPI_rec wird aufgerufen. Dabei kann
das SPI gestartet werden (zaehler_prog von 0 nach 1), und es wird eine
Bestätigung vom SPI empfangen ((zaehler_prog von 1 nach 2). Nun muss im
Zustand 2 gewartet werden, bis das SPI fertig ist.
Bild 3 (SPI_geht_3.png):
Das SPI ist fertig. Aus irgendeinem unbekannten Grund wird in der Mitte
des CLK-Signaltals (!) kurzzeitig die Debug-Ausgabe auf 0000 gezogen,
dann geht es nach der nächsten positiven Flanke wie gewünscht weiter mit
dem Wartebefehl.
Bild 4 (SPI_Fehler.png):
Hier nun die Stelle, an der das merkwürdige Verhalten auftritt (siehe
auch kleine Leiste am unteren Bildrand). Der Zustand wait_spy_rdy wird
wegen der fallenden SDI-Flanke beendet und SPI_rec begonnen. Jedoch wird
kurzzeitig von SPI_rec (zaehler_prog=0) zum Wartebefehl gesprungen,
welcher aber wohl wegen wait_zaehler=0 schnell wieder beendet wird und
zum folgenden SPI_rec übergegangen wird. Was man hier nicht gut erkennen
kann: Es wird tatsächlich ein letztes Byte über SPI übertragen, d.h. das
SPI konnte gestartet werden (ein letztes Mal...).
Das nachfolgende wechselnde SDI-Signal (siehe unterer Bildrand) wird vom
ADC generiert.
Interessantes Nebenphänomen: Wenn man statt der ADCs an SDI einfach GND
anschließt, so funktioniert das Ganze problemlos, es kommt zu keinem
Absturz. Es wäre also naheliegend, eine bestimmte SDI-Wertkombination
als Absturzursache zu nehmen, jedoch wird die Simualtion mit einem
aufzählendem SDI-Signal betrieben, und hier stürzt auch nichts ab.
Martin S. schrieb:> Bild 1 (SPI_geht_1.png):> Da SDI vom externen ADC auf 0 gezogen wird,
Ein externes Signal! Achtung, ROTE FLAGGE!!!
> kann der Zustand wait_spi_rdy verlassen werden.
Ist SDI synchron eingetaktet?
Martin S. schrieb:> Interessantes Nebenphänomen: Wenn man statt der ADCs an SDI einfach GND> anschließt, so funktioniert das Ganze problemlos, es kommt zu keinem> Absturz. Es wäre also naheliegend, eine bestimmte SDI-Wertkombination> als Absturzursache zu nehmen, jedoch wird die Simualtion mit einem> aufzählendem SDI-Signal betrieben, und hier stürzt auch nichts ab.
Das ist ein bekannter Effekt. Der Hintergrund ist dieser da:
http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.htmlMathi schrieb:> Werden asynchrone Signale in Deiner Zustandsmachine abgefragt?
Die können durchaus auch versteckte Wege über ein höheres Modul in
andere (scheinbar synchrone) Signale finden...
Es ist einfach so: JEDES externe Signal für sich muss auf Synchronität
bewertet und ggs. eingetaktet werden.
Vielen Vielen Dank! Das asynchrone SDI war der Fehler. Ein einfaches FF
ganz am Anfang davor geschaltet, und schon klappt es wunderbar.
Und ich habe wohl einen elementaren Punkt zum Thema FPGA dazugelernt.
Martin S. schrieb:> Und ich habe wohl einen elementaren Punkt zum Thema FPGA dazugelernt.
Ja, das hast du. Ich würde fast sagen, das ist die Fehlerquelle, die am
meisten Ärger bringt und Zeit kostet. Und vor allem: es gibt keinen
Automatismus, der dir diese Arbeit (Aufspüren von asynchronen Signalen)
abnimmt.
Deshalb schon ganz zu Beginn mein Verdacht:
Lothar Miller schrieb:>> Zum Teil ändern sich bedeutende Systemeigenschaften, wenn ich irgendein>> Signal ändere, das eigentlich nur kleinere Auswirkungen haben sollte.> Hört sich nach asynchronen bzw. nicht einsynchronisierten Signalen an.