Hi!
Habe mir vor Kurzem ein Eval-Board mit Spartan-6 von Digilent besorgt,
nun hänge ich beim Synthesetool von Xilinx fest.
Ich würde gerne meinen Rs232-Receiver/Transmitter (bzw. eig. UART)
testen, indem ich Daten vom PC aufs Board schicke, dort parallelisiere
und seriell wieder zurückschicke. Receiver und Transmitter habe ich
bereits getrennt verifiziert, und auf meinem Altera-Board läuft alles
klaglos.
Scheinbar kann die ISE von Xilinx aber nicht mit meiner "doppelten"
Instanzierung eines Strobe-Generators umgehen (siehe Screenshot). Beide
Strobe-Gens werden immer mit den selben Parametern (in dem Fall
Baudrate) instanziert. Ich benötige aber 2 verschiedene Strobe-Gens...
einen für Rx, den anderen für Tx.
Erstelle ich nun eine exakte Kopie meiner entity "StrobeGen" und nenne
sie "StrobeGen2", und instanziere 1x "StrobeGen" (z.b. im Tx-Pfad) und
1x "StrobeGen2" (im Rx-Pfad), funktioniert alles tadellos.
Das Problem liegt jetzt also nicht am RxTx selbst, sondern an den
instanzierten Strobe-Generatoren, die sich nicht mit unterschiedlichen
Parametern (generics) instanzieren lassen.
Danke im Voraus,
Stefan
Ich hab ISE bisher nur mit Verilog benutzt, und dort funktioniert das.
Vielleicht ein VHDL-Problem?
Vielleicht irgendwas bei der Parameterübergabe falsch?
Habe die entity und die beiden Instanzierungen mal raufgestellt... bei
Altera funktionierts auf jeden Fall, die Simulation in ModelSim ist auch
ohne Fehler.
iStart hat einen default-wert von '1', daher muss der nicht zugewiesen
werden.
Fehlermeldungen und Warnings bekomme ich keine (irgendwie seltsam), das
Problem besteht darin, dass der Tx-StrobeGen die selbe CycleTime wie der
Rx-StrobeGen bekommt, obwohl ich 2 verschiedene Werte übergebe:
1 sec / (gBaudRate * 2) beim Rx,
1 sec / (gBaudRate) beim Tx.
Es handelt sich in meinen Augen aber eher um ein allgemeines Problem,
das (bei mir) nur in der ISE auftritt.
P.S.: die zwei verschiedenen Parameter kommen daher, dass ich die
Rx-Daten in der 'Mitte' des aktuellen Bits abtasten möchte, um die
Fehleranfälligkeit zu minimieren. Bei Erkennung der fallenden Flanke im
Rx (=StartBit) wird der Rx-StrobeGen angeworfen (R.StartStbGen = '1'),
dann befindet sich jeder zweite Strobe in der Mitte des aktuellen Bits.
Fpga Kuechle schrieb:> IMHO weist du beiden den selben Wert zu> gClkFrequency => gClkFrequency>> das muss also gleich sein.>> wolltest du das eine mit> gClkFrequency => 2 * gClkFrequency> schreiben?
ClkFrequency ist Absicht, ich bewege mich ja nur in einer Clock-Domain
(und die Frequenz wird in dem Fall nur für die Berechnung der
Counter-Breite im StrobeGen verwendet).
> Bei> gStrobeCycleTime => 1 sec / (gBaudRate * 2)> könnte man mal> gStrobeCycleTime => 1.0 sec / (gBaudRate * 2.0)> antesten.
Soeben versucht, ohne Erfolg (auch mit den 1_000_000_000 ns). Und wie
gesagt, bei 2 verschieden benannten StrobeGens (entity StrobeGen1 und
entity StrobeGen2, in den Dateien StrobeGen1.vhd und StrobeGen2.vhd)
läufts tadellos.
Das Problem muss also mMn bei einer Einstellung in der Synthese bzw.
beim Compiler liegen.
Schau mal wieviel Bits die Zähler der beiden Instanzen haben.
Der Ausdruck:
constant cClkCycPerStrobeCyc : natural :=
gClkFrequency / (1 sec / gStrobeCycleTime);
wird eine wahnsinnig hohe Zahl geben, die vermutlich auf 32 Bit
beschränkt wird.
Da:
gClkFrequency : natural := 100E6;
gStrobeCycleTime : time := 256E3
ist
100E6 / (1 / 256E3)
100E6 * 256E3 = 1E8 * 256E3 ? 256E11
und das würde eigentlich 45 Bits erfordern.
Die Konstanten sind eigentlich nicht richtig in Bezug auf die Einheiten.
Mach das korrekt und dann überprüfe die Berechnung nochmal.
Hoppla, da ist mir beim rumprobieren an den Sourcen was schiefgegangen,
bevor ich sie hochgeladen habe (wollte den ursprünglichen Zustand
wiederherstellen)...
gClkFrequency : natural := 100E6;
gStrobeCycleTime : time := 256E3
kann ja gar nicht funktionieren, 'time' vs. 'natural' (256E3)...
da würde dann eigentlich
gStrobeCycleTime : time := 1 sec / 256E3
hingehören, also wäre das Ergebnis für cClkCycPerStrobeCyc nicht
100E6 * 256E3 = 1E8 * 256E3 = 256E11, sondern
100E6 / 256E3 = 1E8 / 256E3 = 390,
daraus folgt der ClkCounter(9 downto 0) für die Standard-Generics.
Sorry, mein Fehler...
Fpga Kuechle schrieb:> Rechnet LogDualis so wie gewünscht?> MfG
Ja, LogDualis hab' ich überall in Verwendung - und wenn es nicht so
wäre, würde der Lösungsansatz "StrobeGen1 und StrobeGen2" nichts daran
ändern...
VHDL ist für die Synthese nicht einheitlich umgesetzt oder definiert.
Wenn es also bei Altera funktioniert, heisst es nich loange nicht, das
das Xilinx auch so tut.
Type time gilt pauschal als nicht synthesefähig. Das kann man zwar von
Fall zu fall unterschiedlich sehen, mit Vermeiden ist man aber auf der
sicheren Seite. In Package zum Vergleich wäre noch der einzige Platz für
sowas, aber nicht in Generics oder in berechnungen für bitbreiten.
Kann gut gehen, muss aber nicht.
Was in deinem Design passiert ist sollte dir der Synthese report
verraten (*.syr). Insbesonders was für counter synthetisiert werden.
Als Alternative zu den den Unsigned counter kannst du auch integer
counter mit range verwenden, das erspart den Logdualis zu berechnen der
Bitbreite.
(http://iweb.tntech.edu/oelkeelany/4110F10/lectures/ece4110_lecture_28.ppt
p.8)
MfG,
Fpga Kuechle schrieb:> Als Alternative zu den den Unsigned counter kannst du auch integer> counter mit range verwenden
Das macht den Code auch erst so richtig schön lesbar. Und am besten die
ganzen Zeiten aus der Berechnung rauslassen, weil es da bei der
Umsetzung durchaus Unterschiede macht, ob mit ps, ns oder sec gerechnet
wird!
Ich mache sowas einfach alles mit integer und nehme die Einheiten
implizit an (als Kommentar):
http://www.lothar-miller.de/s9y/categories/42-RS232
Lothar Miller schrieb:> Fpga Kuechle schrieb:>> Als Alternative zu den den Unsigned counter kannst du auch integer>> counter mit range verwenden> Das macht den Code auch erst so richtig schön lesbar. Und am besten die> ganzen Zeiten aus der Berechnung rauslassen, weil es da bei der> Umsetzung durchaus Unterschiede macht, ob mit ps, ns oder sec gerechnet> wird!>> Ich mache sowas einfach alles mit integer und nehme die Einheiten> implizit an (als Kommentar):> http://www.lothar-miller.de/s9y/categories/42-RS232
Gutes beispiel. Persönlich definiere ich für den integercounter einen
eigenen typ und verwende für den Grenzwert 'high und 'low statt nackter
Zahlen.
Also
1
subtypet_rxbitcntisintegerrange0to9;
2
signalrxbitcnt:t_rxbitcnt:=t_rxbitcnt'high;
3
4
--..
5
6
ifrxbitcnt=t_rxbitcnt'highthen
7
rxbitcnt<=t_rxbitcnt'low;
8
--..
Um den Zähler zu verlängern/verkürzen muss dann der Code nur an einer
Stelle (der typedef) angefasst werden.
MfG,
Fpga Kuechle schrieb:> Um den Zähler zu verlängern/verkürzen muss dann der Code nur an einer> Stelle (der typedef) angefasst werden.
Hmmm, sieht elegant aus, hat mir aber schon fast eine zu starke Tendenz
in Richtung "implizite Annahme"...
Denn genau an dieser Stelle
1
if(txcnt<(Quarz_Taktfrequenz/Baudrate)-1)then
liest sich der explizite Einfluss der Taktfrequenz und der Baudrate auf
den Zählerstand irgendwie beruhigender als die Annahme, dass der 'high
schon richtig gesetzt sein wird:
1
if(txcnt<txcnt'high)then
Und spätestens beim recht klaren
1
rxcnt<=((Quarz_Taktfrequenz/Baudrate)-1)/2;
wirds dann doch undurchsichtig
1
rxcnt<=rxcnt'high/2;
Da ist dann schon einiges an Systemkenntnis nötig, damit man da nicht
wieder nachschauen muss, was denn so erreicht wird.
Fpga Kuechle schrieb:> Um den Zähler zu verlängern/verkürzen muss dann der Code nur an einer> Stelle (der typedef) angefasst werden.
Das ist auch bei meiner "ausführlichen" Version so (Anpassung der
Generics oder der Konstanten), aber ich finde die Verwendung der
Attribute 'low und 'high auf diese Art auch recht elegant. Ich hatte das
bisher hauptsächlich in generischen Funktionen gemacht, weil man die ja
"nur" einmal richtig zum Laufen bringen muss und dann nicht mehr
anschaut... ;-)
Lothar Miller schrieb:> Fpga Kuechle schrieb:> liest sich der explizite Einfluss der Taktfrequenz und der Baudrate auf> den Zählerstand irgendwie beruhigender als die Annahme, dass der 'high> schon richtig gesetzt sein wird:>
1
>if(txcnt<txcnt'high)then
2
>
>>> Und spätestens beim recht klaren>
1
>rxcnt<=((Quarz_Taktfrequenz/Baudrate)-1)/2;
2
>
> wirds dann doch undurchsichtig>
1
>rxcnt<=rxcnt'high/2;
2
>
> Da ist dann schon einiges an Systemkenntnis nötig, damit man da nicht> wieder nachschauen muss, was denn so erreicht wird.
Ja man muss die Parameter schon kennen. Oder schnell nachschauen können
-> die Typdef ins package und diese ausdrucken und an den Moni hängen.
Oder mehr info in den typ namen packen: t_txcnt_SysClk_per_Baud.
Oder Kommentar schreiben. Kollege hatte mal den Anspruch, das auch ein
Project-Manager anhand des VHDL-Codes das System verstehen kann...
MfG,
Fpga Kuechle schrieb:> Oder Kommentar schreiben.
Nichts ist veralteter als ein eben hingeschriebener Kommentar... ;-)
> Kollege hatte mal den Anspruch, das auch ein Project-Manager anhand> des VHDL-Codes das System verstehen kann...
An diesem Tag lernte ich alles, was man über das Scheitern wissen muss.
Fpga Kuechle schrieb:> Type time gilt pauschal als nicht synthesefähig. Das kann man zwar von> Fall zu fall unterschiedlich sehen, mit Vermeiden ist man aber auf der> sicheren Seite. In Package zum Vergleich wäre noch der einzige Platz für> sowas, aber nicht in Generics oder in berechnungen für bitbreiten.> Kann gut gehen, muss aber nicht.
Das war also das Problem... der Datentyp 'time' wird anscheinend einfach
ignoriert, deshalb wurde 2 mal der selbe StrobeGen instanziert...
und mehr wars auch schon gar nicht :)
Vielen Dank an alle für eure Mühe!
Liebe Grüße,
Stefan