Forum: FPGA, VHDL & Co. Feedback erstes VHDL-Projekt


von Fabian N. (flyget)



Lesenswert?

Hallo Zusammen,

Wir haben hier jetzt mal ein erstes Projekt auf einem FPGA zum laufen 
bekommen. Nun würden wir uns freuen, wenn die Profis mal drüber schauen 
würden und die ganz groben Schnitzer aufzeigen könnten.

Rahmenbedingungen:
In dem Projekt handelt es sich um eine Winkelerfassung mit 
Quadratur-Ausgabesignal. Da das ganze recht zügig mit etwa ~40Hz rotiert 
und eine Auflösung von min. 0,1° haben soll sind wir auf einen FPGA 
(Dev-board mit Cyclon IV, später MAX10) gegangen.
Aus dem Analogteil kommen drei Rechtecksignale mit 4MHz, einmal 
"Referenz", einmal "Winkel" und einmal "Winkel_90"(mit konstant 90° 
Phasenversatz zum Winkelsignal). Der Phasenversatz zwischen Referenz und 
Winkelsignal entspricht einem Winkel von maximal 10°. Insgesamt gibt es 
für eine volle Umdrehung also 36 mal diesen 10° Bereich.

Im ersten Schritt werden die Signale einsynchronisiert und daraus über 
einen NCO ein etwas geglättetes Signal im FPGA erzeugt. Dann wird aus 
dem Referenz- und dem Winkelsignal ein XOR gebildet und dieses mit 
200MHz gezählt.
Anschließend wird daraus ein Zählwert von 0-3600 generiert und das 
Quadratursignal entsprechend erzeugt (Schritt vor, Schritt zurück).

Es gibt ja doch ein paar Fallstricke beim ersten FPGA-Projekt, Latches, 
Timing, .... soweit bekannt und verstanden wurde das berücksichtigt. Es 
gibt aber sicher trotzdem Verbesserungspotential.
Grundsätzlich läuft die Sache inzwischen und jetzt geht es an den 
Feinschliff. Besonders interessant wäre für uns:

- Fehler/unsaubere Programierung beseitigen
- Höhere Auflösung, d.h. schnellerer Zähler
- Glättung des Signals durch mehr Mittelung

Vielen Dank für eure Mühe und frohe Festtage!
Fabian

P.S. Um die ganze Sache mit nur einer Clock-Domain (200MHz) zum laufen 
zu kriegen, wurden diverse Zwischenregister eingefügt und das ganze 
manchmal "sequentiell" (signal "step") programmiert (ja ich weiß... 
beschrieben). Nur als Vorwarnung, dass die ganzen FPGA Experten hier 
nicht gleich vom Stuhl fallen;-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Fabian N. schrieb:
> Im ersten Schritt werden die Signale einsynchronisiert
Das ist ein netter Schuss ins Knie:
1
    if rising_edge(clk) then  
2
        input_1     <= input_async_1; -- einsynchronisieren durch FlipFlop
3
        input_1_inv <= not input_async_1;
Nimm mal an, dass die beiden Flipflops input_1 und input_1_inv so 
verdrahtet werden, dass die Laufzeiten t1 und t2 vom asynchronen Eingang 
zu den beiden Flipflops unterschiedlich lang sind:
1
        
2
                                 t1->kurz                    
3
  input_async_1 -------o---------------------------------|D FF1 input_1 
4
                       |       _____       _____      clk|>
5
                       |      |     |     |     |
6
                       |      |     |     |     |
7
                       |      |     |     |     |
8
                       |      |     |     |     |
9
                       |      |     |     |     |        
10
                       |______|     |_____|     '-------O|D FF2 input_1_inv
11
                       t2->lang                       clk|>
Was passiert dann einmal pro Minute, Stunde, Tag, Woche, wenn sich der 
Pegel am input_async_2 etwa mit der Taktflanke ändert?
1
                    ____      ____      ____      ____      ____         
2
clk            ____|    |____|    |____|    |____|    |____|    |___    
3
                      _______________            :     _____________
4
input_async_1 _______|       :       |________________|    :
5
                     :t1     :         :         :         :
6
                      v_______________ :         :      ____________
7
D von FF1     ________|      :        |________________|   :
8
                     :t2     :         :         :         :
9
              __________v    :         : ________________  :
10
D inv von FF2           |_______________|        :       |__________               
11
                             :_________:         :         :________
12
Q von FF1     _______________|         |___________________|            =input_1
13
              _______________:                    :________:
14
Q von FF2                    |____________________|        |_____=input_1_inv
15
                                         ?????????
16
                                        beide gleich
Richtig: beide Flipflops haben für 1 Taktzyklus den gleichen Pegel.
Und dann kommt es drauf an, wie der Rest der Schaltung auf so einen 
Fehler reagiert.

Hintergrund:
http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.html

Also: zuallererst ganz am Anfang das Signal einsynchronisieren. Und 
dann synchron weiterverarbeiten und ggfs. duplizieren/negieren.
Und damit nicht die Toolchain dieses Einsynchronisierflipflop 
"automatisch" verdoppelt, würde ich da 2 Sync-Flipflops hintereinander 
schalten.

Aber warum machst du eigentlich aus 1 Eingang 2 Signale?
Du kannst beim Portmapping ja auch invertierte Signale verdrahten.


Das hier sieht mir auch nach einen Fehler aus:
integer range -1023 to 1023;
Ich hätte da erwartet:
integer range -1024 to 1023;

Und wofür ist der Automat in qdec_output_counter? Brauchst du da die 
Verzögerung von 4 Takten vom Start bis zum Ergebnis vom o_qdec_counter?

Das input_xor wäre mir kein eigenes Modul wert. Da werden doch nur 2 
Bits miteeinander verXORt, das geht doch mit 1 Zeile auch einfach dort, 
wo man es braucht.

: Bearbeitet durch Moderator
von Sigi (Gast)


Lesenswert?

Zur Form:

- Registrierte Signale (d.h. FFs) evtl. schon beim
  Definieren Wert zuordnen, nicht erst beim Reset im
  Prozess.
- Wertezuweisungen an Signale (z.B. im Reset-Teil) besser
  per vordefinierter Konstante, statt per "0000...0000".
  Z.B. hat eine Typänderung mehrere Editierschritte zur folge
  und ist somit fehleranfälliger.
- Reset-Signale in der Abhängigkeitsliste beim Prozess-Start
  ist bei dir überflüssig: du resettest immer synchron (gut!).
- In einigen Prozessen hast du den Reset-Teil am Anfang,
  in anderen am Ende: mach alle Reset-Teile am Anfang.
- Einige Prozesse verwenden Variablen: darauf kann man
  idR verzichten, macht auch das Debuggen im Simulator
  einfacher.
- Instantiierungen der Unterkomponenten bitte nur per
  Names-Parameter, und jeweils ein Port je Zeile:
     a => upper_a,
     b => upper_b,
     etc.
- etc.

Zum Design:
- Ich habe nicht die Zeit, alles zu überschauen, aber grob
  von der Funktionalität würde ich sagen, dass einiges zu
  kompliziert ausgedrückt wurde, evtl. auch die Zuordnung
  in die einzelnen Komponenten. Aber es geht auch viel schlechter.
- Nichtverwendete Pins (insbes. Outputs) bitte mitdefinieren
  und geeignet zuordnen (z.B. SRAM-#WE per <= "1").

von Fabian N. (flyget)


Lesenswert?

Vielen Dank euch beiden und sorry für die späte Rückmeldung!

@Lothar
Ja, das mit der Eintaktung war natürlich ne grandiose Leistung... In dem 
Moment wo ich deinen Satz angefangen habe zu lesen, ist es mir dann auch 
schon gedämmert... ist beseitigt.
Die Integer-Range passt natürlich auch nicht und ob die 4 Takte im 
qdec_output_counter nötig sind, prüfe ich nochmal. Möglicherweise sind 
die auch nur ein Überbleibsel von anderen/vorhergehenden Versionen, wo 
ich diese benötigt habe.

@Sigi
Du hast recht, da sind einige Code-technische Unsauberkeiten (Reset an 
Anfang/Ende gemischt, ...)die werden alle noch beseitigt. Primär ging es 
mir um die FPGA-typischen Fallstricke wenn man von der µC-Schiene kommt.
Die Sache mit der "Instantiierungen der Unterkomponenten..." hab ich 
noch nicht ganz verstanden. Was meinst du hiermit?

@all
Gibt es noch Ideen/Vorschläge wie ich mehr Auflösung generieren könnte? 
Also im Prinzip wie ich mehr Zählwerte zwischen den beiden Flanken des 
eingetakteten Rechtecksignals bzw. dem NCO bekomme? Ich denke mit der 
allgemeinen Taktfrequenz hochgehen wird nur noch geringfügig gehen, der 
Max10 kann glaub auch gar nicht mehr viel schneller.
Gibt es da irgendwelche schnelleren FPGA-Peripherals die man für sowas 
verwenden kann? Oder eben weitere Ideen?

Vielen Dank schonmal und beste Grüße,
Fabian

von Klakx (Gast)


Lesenswert?

Fabian N. schrieb:
> Also im Prinzip wie ich mehr Zählwerte zwischen den beiden Flanken des
> eingetakteten Rechtecksignals bzw. dem NCO bekomme?

Das klingt nach dem klassischen Problem: Wie erhöhe ich die Samplerate?

a)
Wenn sich der System-Takt nicht mehr erhöhen lässt, dann kann man mit 
mehreren Phasen des Taktes abtasten.

Z.B. Diese 4 Takte per DCM/PLL erzeugen: 200 MHz +0°, +90°, +180°,+270°. 
Das erhöht die Abtastrate um den Faktor 4. Die Auswertelogik wird 
natürlich etwas komplizierter.

Etwas einfacher:
Mit einem IDDR-FF tastest du beide Flanken ab und bekommst immerhin 
schon den Faktor 2.

b) ISERDES (Xilinx, Intel hat sicher etwas ähnliches). Diese lassen sich 
wesentlich höher Takten und geben dir die Werte parallel.

c) externes-Samplemodul oder GTX-Serdes (CDR wird arretiert)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.