Forum: FPGA, VHDL & Co. ADC IP für AD7961 funktioniert nach synthese nicht


von Dirk N. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich versuche seit ein paar Tagen einen ADC anzusteuern, welcher mit 
einem externen Trigger für die Wandlung funktionieren soll. Der Chip ist 
ein AD7961, beziehungsweise AD7960, welcher dann 18 bit hat aber sonst 
gleich ist.

Für das conversion-timing und die Wartezeit bis zum MSB habe ich zwei 
state-machines gebaut, die soweit ok funktionieren.
Der conversion clock wird dann aktiviert und die Antwort des ADC sowohl 
im Daten- als auch Clock-Signal mit der Sync-Clock synchronisiert.

Das Einlesen der Daten jedoch funktioniert nicht im späteren Design (die 
Ausgaben des ILA von Vivado sind leider auch nicht weiter zu 
gebrauchen).
Eine Simulation des VHDL-Code allein funktioniert auch, nicht jedoch die 
Simulation mit dem Ergebnis aus der Synthese.

Ich würde mich freuen, wenn jemand mal ein Auge drauf werfen könnte, 
vielleicht gibt es etwas, das ich eklatant falsch mache. Hab dafür den 
Code samt Testbench hier reingepackt.

Vielen Dank schonmal

von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

Also ich vermisse schonmal die IBUFDS. Da ich den Baustein selber 
verwende baue ich dir mal ne kleine Testbench, kommt also nachher an 
dieser Stelle.

Edith hat die Dateien hochgeladen, das simuliert in Vivado einen Sinus 
Sweep. data ist dabei 18 Bit Signed.

: Bearbeitet durch User
von Dirk N. (Gast)


Lesenswert?

Die IBUFDS hab ich extern eingebunden, war mir etwas flexibler mit allem 
drum und dran. Die Chips können ja auch nicht-differenzielle 
Ansteuerung, was man ja für niedrige Frequenzen noch gut nehmen kann.

Gustl, bei Dir läuft das alles sehr straight in einem Rutsch durch. Ich 
hab es durch den niedrigen Systemtakt von 100 MHz zum synchronisieren 
und den 50 MHz Datenclock etwas schwieriger, wenn ich wenigstens 3 Msps 
schaffen will. Daher diese Verschachtelung von state machines.

Der Fehler scheint in der letzten State Machine zu sein. Nach der 
Synthese läuft der Zähler für die empfangenen Bits genau ein mal hoch, 
dann wird er nicht mehr resettet. Vor der Synthese ist es kein Problem.

von Gustl (Gast)


Lesenswert?

Naja du kannst intern einen 250 MHz Takt machen, dann die Daten in einen 
DC FIFO schreiben und mit 100 MHz daraus lesen. Ein Clock Domain 
Crosssing ist sowieso drinnen.

von Gustl B. (-gb-)


Lesenswert?

So, noch ein kleiner Nachtrag:

Bei Prozessen in VHDL gibt es verschiedene Wege der Beschreibung.

Wenn das ein getakteter Prozess sein soll der NUR mit einer Taktflanke 
abläuft, dann kannst du

process begin
wait until rising_edge(clk);
...
end process;

schreiben. Das ist gleichbedeutend mit

process (clk) begin
  if rising_edge(clk) then
    ...
  end if;
end process;

Wenn du noch Kombinatorik mit drinnen hast, also der Prozess auch dann 
neu "evaluiert" werden soll wenn sich andere Signale ändern, dann 
müssen diese zusätzlichen Signale auch in der Sensitivitätsliste 
auftauchen.
Für die Synthese ist das nicht wichtig, da wird die Sensitivitätsliste 
ignoriert, aber das ist für die Simulation wichtig. Wenn du also 
möchtest, dass Simulation und Hardware übereinstimmen, dann müssen alle 
Signale die den Prozell anstoßen in die Sensitivitätsliste.

Bei deinem Prozess

clock_out: process (sync_clk, enableclkout)
begin
  DCOp <= enableclkout AND clk;
end process;

muss also clk mit hinein in die Liste, sync_clk hat da aber nichts 
drinnen verloren.

Genauso weiter unten bei

synchronisation : process (sync_clk, clk, dclkin, conv, din)
begin
  if rising_edge(sync_clk) then
    ...
  end if;
end process;

da sollte nur sync_clk in der Liste stehen.

Man fährt in der Regel gut damit möglichst alles getaktet zu 
beschreiben. Also getaktete Prozesse und Kombinatorik wenn man sie 
braucht ohne Prozess. Klar, gibt Ausnahmen, aber bisher konnte ich meine 
Designs so schreiben.

Zu der Sache mit dem Takt:
Du könntest auch bei deinen 100 MHz DDR IOs verwenden, dann bekommst du 
auch zumindest 100 MHz SPI hin. Für > 3 MSample/s würde das genügen.

von Dirk N. (Gast)


Lesenswert?

Danke für Deine Tipps!
Die Sache mit einem externen 200 MHz-Takt hatte ich versucht, das hat 
aber dann leider gar nicht mehr funktioniert, jedoch hatte ich keinen 
dualclock FIFO eingesetzt.

Ich werde mal die Sensitivitätslisten überarbeiten und schaue mal wie es 
dann aussieht. Vielleicht komme ich so ja schon zu einem Hinweis, was 
ich falsch mache. Wie gesagt, scheint es ja nur die letzte SM zu 
betreffen.

von Gustl B. (-gb-)


Lesenswert?

Welchen Baustein verwendest du denn? Auch für den AD7961 steht im 
Datenblatt typischerweise 250 MHz SPI Takt.

Ich sehe gerade, dass ich das auch nicht richtig gemacht habe, ich 
verwende einen SPI Takt von 125 MHz. Funktioniert trotzdem aber wohl 
nicht so gut weil die Pause nicht so lang ist. Korrekt wäre wenn man da 
wirklich DDR IOs nimmt oder das gleich mit SerDes macht.

von Achim S. (Gast)


Lesenswert?

Dirk N. schrieb:
> Wie gesagt, scheint es ja nur die letzte SM zu
> betreffen.

in deinem letzten Prozess (data_process) hast du eine wilde Mischung von 
taktsynchroner Logik innerhalb eines kombinatorischen Prozesses.

        CASE data_state IS
            WHEN init =>
                count_bits <= 0;
            WHEN read =>
                IF rising_edge(sync_clk) THEN
        ................

Darauf hat auch Gustl schon hingewiesen. Lass sowas sein. Mach den 
Prozess isgesamt getaktet oder insgesamt kombinatorisch. Wenn es ein 
getakteter Prozess ist, dann sollte "oberhalb der Taktung" bestenfalls 
ein asynchroner Reset stehen, aber keine ausführliche kombinatorische 
Logik.

Ansonsten:

ich würde das Reinrotieren der Datenbits ins Ergebniswort mit einem 
Schieberegister machen (ein SPI-Register ist im wesentlichen ein 
Schieberegister), du verwendest stattdessen einen großen Mutliplexer
              case count_bits is
                when  0  => dataregister(15)  <=data_in_synced(1);
                when  1  => dataregister(14)  <= data_in_synced(1);
                when  2  => dataregister(13)  <= data_in_synced(1);

Und hier
        elsif (clk = '1' and clk'event) then
            state_clkout <= next_state_clkout;
            case state_clkout is
                when idle => enableclkout <= '0';                --
                             clkout_counter <= 1;
                             if trigger_msb = '1' then
                               next_state_clkout <= clocking;  --

versuchst du wohl die Zwei-Prozess-Schreibweise von FSM auf einen 
Prozess zusammenzuziehen. Da du dabei beide Signale state_clkout und 
next_state_clkout in einem getakteten Prozess zuweist, bekommst du bei 
jedem State-Übergang wahrscheinlich einen Takt zusätzlicher Latenz, die 
du eigentlich nicht willst

Würdest du next_state_clkout in einem anderen, kombinatorischen Prozess 
zuweisen, dann hättest du die normale Zwei-Prozess-Schreibweise von FSMs 
(ohne zusätzliche Latenz). Wenn du die Zuweisung aber innerhalb des 
getakteten Prozesses stattfindet, in dem du auch die Zuweisung zu 
state_clkout machst, müsstest du ohne next_state_clkout arbeiten. Also 
statt
if trigger_msb = '1' then
  next_state_clkout <= clocking;  --

direkt schreiben
if trigger_msb = '1' then
  state_clkout <= clocking;  --


Ob die Abtastung des Datensignals (getaktet mit sync_clk, kombiniert mit 
einer Flankentetektion von data_clk_synced ) vom Timing her aufgeht, bin 
ich mir nicht sicher. Ich könnte mir vorstellen, dass du manchmal das 
Datenbit vom "falschen" Taktzyklus einliest

Denn wenn sync_clk und dclkin keine feste Phasenbeziehung haben wirst du 
manchmal mit
    data_clk_synced <= data_clk_synced(0) & dclkin; schon die fallende 
Flanke detektieren während
    data_in_synced <= data_in_synced(0) & din; noch die Daten des 
vorherigen dcklin-Zyklus speichert.

von Gustl B. (-gb-)


Lesenswert?

Die Angaben zur SPI Übertragung sind eher schwammig im Datenblatt:
https://www.analog.com/media/en/technical-documentation/data-sheets/AD7960.pdf
Der letzte Absatz auf Seite 19 sagt aus, dass man die 18 Clock Pulse (16 
Pulse bei AD7961) bis t_CLKL der nächsten Wandlung angelegt haben muss. 
t_CLKL sind 160 ns. Bei 5 MSps dauert eine Wandlung 200 ns. Man hat also 
von diesen 200 ns die 160 ns Zeit für die 18 oder 16 Pulse. Wann man 
nach CNV damit anfangen darf ist nicht spezifiziert. Sondern es steht da 
wann das MSB (das als erstes herausgetaktet wird) spätestens verfügbar 
ist - und zwar nach t_MSB = 200 ns. Man könnte also mit den 18 oder 16 
Taktpulse auch schon während CNV high ist anfangen.
Laut Datenblattzeichnung überlappt auch t_Acquisition mit dem Auslesen, 
da muss man also keine Ruhe einhalten auf den digitalen Leitungen.

Wenn das so stimmt, dann kann man auch einen deutlich niedrigeren Takt 
fahren als die im Datenblatt typischerweise angegebenen 250 MHz. Das 
mache ich auch und verwende aktuell 125 MHz. Aber geht noch weniger?
Beim AD7960 muss man in 160 ns 18 Pulse anlegen. Wobei t_CLKL nur sagt 
wann die Clock wieder low sein muss, das sind also 17,5 Taktperioden.
160 ns / 17,5 = 9,14... ns entspricht einem Takt von 109 MHz.
Beim AD7961 muss man nur 15,5 Taktperioden in den 160 ns schaffen.
160 ns / 15,5 = 10,32.. ns entspricht einem Takt von 97 MHz.

Man kann also den AD7961 mit vollen 5 MSps betreiben wenn man einen 100 
MHz SPI Takt verwendet. Wenn man auch nur einen 100 MHz Takt im FPGA 
verwenden will, dann braucht man dazu ein ODDR um den Takt auszugeben.

Ich werde da mal was basteln und wieder eine Testbench anhängen wenn das 
fehlerfrei simuliert.

von Dirk N. (Gast)


Lesenswert?

Gustl, guter Hinweis mit den 250 MHz Clock. Da es keine Mindestzeit in 
der Tabelle gab, habe ich das erst mal ignoriert. Im Kommentar zur clock 
period gibt es noch einen Hinweis auf die Mindestfrequenz: "For the 
maximum CLK± period, the window available to read data is tCYC − tMSB + 
tCLKL".
Habe aber diese Periodendauer jetzt für meinen Fall noch nicht 
berechnent.

Ich hab ich mal nach den DDR IOs bei Xilinx gesucht, aber noch nichts 
gefunden.

Achim, danke für Deine Ausführliche Erklärung. Wäre es also besser, 
alles asynchron zu machen? Es müsste eigentich Phasensynchron sein, da 
ich für den ADC-Clock die halbe Frequenz der Sync-Clock verwende.

von Dirk N. (Gast)


Lesenswert?

Wir haben wohl gerade den gleichen Teil des Datenblatts gelesen, Gustl. 
Hatte nur noch meinen Beitrag nicht abgeschickt. Aus dem Grund, den Du 
beschreibst betreibe ich den ADC mit maximal 3 MHz. Im Normalfall werde 
ich zunächst weniger haben, will es erst einmal zum Laufen bringen und 
ggf. später schneller werden.

von Achim S. (Gast)


Lesenswert?

Dirk N. schrieb:
> Wäre es also besser, alles asynchron zu machen?

auf keinen Fall.

du könntest alles synchron machen.

wenn du z.B. für die zwei-Prozess Schreibweise einige rein 
kombinatorische Prozesse hättest, wäre das auch ok. aber 
deine"gemischten" Prozesse sind nicht im k.

von Achim S. (Gast)


Lesenswert?

Achim S. schrieb:
> sind nicht im k

... sint nicht ok.

von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

So, jetzt hab ich das auch für den AD7961 (16 Bits) und zwar mit 100 MHz 
Clock und ODDR. Simulation sieht gut aus, aber ich kann das nicht auf 
Hardware testen weil ich hier einen AD7960 habe.

Dirk N. schrieb:
> Ich hab ich mal nach den DDR IOs bei Xilinx gesucht, aber noch nichts
> gefunden.

Wie das geht siehst du in der AD7961.vhd ist eigentlich recht einfach. 
IDDR brauchst du hier nicht wenn du den DCO verwendeset um die Daten 
entgegenzunehmen.

: Bearbeitet durch User
von Dirk N. (Gast)


Lesenswert?

Ich bin etwas weiter gekommen, habe die letzte Statemachine entfernt und 
habe einfach den Enableclkout-Status für die Fallunterscheidung genutzt, 
ob neue Daten gelesen werden oder die alten gehalten werden. Dadurch 
klappt das Zählen der Bits schon einmal. Was ich leider noch nicht 
messen konnte sind aussagekräftige Signale aus der Schaltung mit dem 
ILA, da muss ich noch mal neu Implementieren.

Hatte rausgefunden, dass sich die SM aufhängt, weil einmal 
data_next_state und dann data_state da stehen. Da hatte ich mich selbst 
verwirrt, dann den Überblick verloren und bin letztendlich dran 
verzweifelt.
Data_next_state hatte im idle-State gar keine Relevanz, weshalb sich das 
Ganze dann aufgehängt hat.

von Duke Scarring (Gast)


Lesenswert?

Dirk N. schrieb:
> Hatte rausgefunden, dass sich die SM aufhängt, weil einmal
> data_next_state und dann data_state da stehen
Ja, ich weiß auch nicht, warum diese unübersichtliche 
state/state_next-Schreibweise an Hochschulen noch so oft propagiert 
wird.

Bei mir gibt es i.d.R. einen state-type und dazu das passende 
state-Signal:
1
    type state_t is (IDLE, START, SHIFT);
2
...
3
    process
4
    begin
5
        wait until rising_edge( clk);
6
        case state is
7
            when IDLE =>
8
                -- warte auf irgend ein Signal
9
            when START =>
10
                -- tue dies
11
            when SHIFT =>
12
                -- tue das
13
        end case;
14
    end process;
15
...

Oberste Priorität ist es (bei mir) den Code schnell wieder verstehen zu 
können, wenn ich da nach 14 Tagen, drei Monaten oder fünf Jahren mal 
wieder ran muß.

Duke

von Dirk N. (Gast)


Lesenswert?

Gustl, ich habe festgestellt, dass man beim Wandeln Probleme bekommt 
wenn man zu schnell ausliest. Also die tMSB muss wohl eingehalten 
werden. Ansonsten kommen in den obersten Bits noch Werte der unteren aus 
der letzen Konvertierung mit. Scheinbar ein Problem, das aus internen 
Schieberegistern im ADC herrührt.
Ich habe den zeitlichen Versatz hergestellt und dann erst mal korrekte 
Ergebnisse bekommen.

Was ich noch nicht hinbekommen habe ist eine externe Triggerung des 
Wandlers...

von Gustl B. (-gb-)


Lesenswert?

Dirk N. schrieb:
> Also die tMSB muss wohl eingehalten werden.

Ja nun, das sind maximal 200 ns, also bei 5 MSps genau eine Wandlung. 
Man liest also immer das Ergebnis der letzten Wandlung und nicht das der 
Aktuellen. Macht bei mir keinen Ärger.

Ich stelle mir das so vor: Der ADC legt nach t_CLKL das Ergebnis der 
aktuellen Wandlung auf sein Ausgangsregister. Und spätestens nach t_MSB 
ist es dort und kann herausgetaktet werden. Man hat also die Zeit von 
steigender Flanke CNV bis t_CLKL Zeit um das Ergebnis abzuholen. Das ist 
aber das Ergebnis der vorangegangenen Wandlung.

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.