Forum: FPGA, VHDL & Co. Serielle Ausgabe (VHDL)


von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Hallo,

erstmal sorry für den dürftigen Threadnamen, nur mir viel nix besseres 
dazu ein. Ich habe folgendes Problem, ich muss eine PLL mit 24 Bit 
initialisieren und dazu CLK, DATA und STROBE entsprechend ansteuern, 
also immer DATA anlegen, t_setup warten, CLK hochziehen, t_hold warten, 
CLK runter und wieder von vorne, anschließend nach der letzten CLK noch 
STROBE für eine entsprechende Zeit hochziehen um die Daten zu 
übernehmen.

Ich war schon wieder dabei eine FSM dafür zu bauen als ich mir überlegt 
habe ob es nicht auch einfacher (ohne Unmengen an Text zu schreiben) 
geht. Dann hatte ich die Idee das Ganze mit einem getakteten Prozess 
(Statements hintereinander mit wait until rising_edge; leider auch viel 
Geschreibsel) oder einen Counter (wo ich auf das Setzen bestimmter 
Bitmuster reagiere) zu machen.

Darum meine Frage, wie würdet Ihr das machen, oder eventuell noch ne 
Idee die ich übersehen hab und einfacher ist?

von VHDL hotline (Gast)


Lesenswert?

Tim T. schrieb:
> Dann hatte ich die Idee das Ganze mit einem getakteten Prozess
> (Statements hintereinander mit wait until rising_edge; leider auch viel
> Geschreibsel)

Mehrere wait until rising_edge in einem Prozess wird dein Sythesizer 
nicht unterstützen.

Tim T. schrieb:
> oder einen Counter (wo ich auf das Setzen bestimmter
> Bitmuster reagiere) zu machen.

Das ist auch eine FSM, nur mit Zählerwerten als Zustandsnamen.

Tim T. schrieb:
> wie würdet Ihr das machen

FSM. Wieviel "Geschreibsel" das ist, hängt davon ab, was deine FSM macht 
bzw. wie geschickt du es implementierst.

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


Lesenswert?

VHDL hotline schrieb im Beitrag #6138587:
> Mehrere wait until rising_edge in einem Prozess wird dein Sythesizer
> nicht unterstützen.
Kommt auf den Synthesizer und die Aufgabe an. Im Prinzip ging das mit 
ISE schon vor 10 Jahren:
http://www.lothar-miller.de/s9y/archives/47-wait-im-Prozess.html

Tim T. schrieb:
> oder einen Counter (wo ich auf das Setzen bestimmter Bitmuster reagiere)
> zu machen.
Dein "Counter (wo du auf das Setzen bestimmter Bitmuster wartest)" ist 
im Prinzip auch nur eine längere Schreibweise für "FSM". Also kannst du 
es auch gleich mit einer FSM machen, die die nötigen Zustände und 
Pegelwechsel so abhandelt, dass es auch nach einem halben Jahr noch 
jeder versteht.

Sieh dir mal die SPI-Schnitte als Grundlage an:
http://www.lothar-miller.de/s9y/categories/45-SPI-Master
Das Modell dort so abgespeckt, dass nur dein "Modus" abgehandelt wird, 
und du bist fertig.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> VHDL hotline schrieb im Beitrag #6138587:
>> Mehrere wait until rising_edge in einem Prozess wird dein Sythesizer
>> nicht unterstützen.
> Kommt auf den Synthesizer und die Aufgabe an. Im Prinzip ging das mit
> ISE schon vor 10 Jahren:
> http://www.lothar-miller.de/s9y/archives/47-wait-im-Prozess.html

Stimmt, die Seite hab ich irgendwann schon mal gesehen^^

> Tim T. schrieb:
>> oder einen Counter (wo ich auf das Setzen bestimmter Bitmuster reagiere)
>> zu machen.
> Dein "Counter (wo du auf das Setzen bestimmter Bitmuster wartest)" ist
> im Prinzip auch nur eine längere Schreibweise für "FSM". Also kannst du

Das es alles irgendeine Art FSM ist, ist mir schon klar, dachte nur als 
Counter wäre es weniger zu Texten.

> es auch gleich mit einer FSM machen, die die nötigen Zustände und
> Pegelwechsel so abhandelt, dass es auch nach einem halben Jahr noch
> jeder versteht.

Glaube dass ist das Killerargument, ich hab oft schon am nächsten Morgen 
Probleme mit sowas...

> Sieh dir mal die SPI-Schnitte als Grundlage an:
> http://www.lothar-miller.de/s9y/categories/45-SPI-Master
> Das Modell dort so abgespeckt, dass nur dein "Modus" abgehandelt wird,
> und du bist fertig.

Habs jetzt erstmal so gelöst, muss mir nur noch was für den Reset 
überlegen:
1
InitPLL : process(clk_100mhz)
2
 begin
3
  if (rising_edge(clk_100mhz)) then
4
5
    case state is
6
         when start =>    idt_sclk    <= '0';
7
                  idt_data   <= '0';
8
                  idt_strobe  <= '0';
9
                  i <= 23;
10
                  state <= setup;
11
                      
12
         when setup =>    idt_sclk <= '0';
13
                  idt_data <= idt_config(i);
14
                  state <= hold;
15
16
      when hold =>    idt_sclk <= '1';
17
                  if (i = 0) then
18
                    state <= strobe1;
19
                  else
20
                    i <= i - 1;
21
                    state <= setup;
22
                  end if;
23
      
24
      when strobe1 =>  idt_sclk <= '0';
25
                  idt_data <= '0';
26
                  idt_strobe  <= '1';
27
                  state <= strobe2;
28
                
29
      when strobe2 =>  state <= strobe3;
30
31
      when strobe3 =>  state <= strobe4;
32
                  
33
      when strobe4 =>  state <= done;
34
                  
35
         when done =>     idt_strobe  <= '0';
36
                  state <= done;
37
38
      end case;
39
    
40
  end if;
41
 end process;

von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

Tim T. schrieb:
> CLK, DATA und STROBE entsprechend ansteuern,
> also immer DATA anlegen, t_setup warten, CLK hochziehen, t_hold warten,
> CLK runter und wieder von vorne, anschließend nach der letzten CLK noch
> STROBE für eine entsprechende Zeit hochziehen um die Daten zu
> übernehmen.

Das kling für mich sehr nach einem einfachen Schieberegister mit 
zusätzlichem Latch wie das SN74HC595.

Ich hänge hier mal Code ran der 8 Bits überträgt und dann einen Puls für 
das Latch ausgibt. Das kannst du sehr wahrscheinlich einfach anpassen.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Gustl B. schrieb:
> Tim T. schrieb:
>> CLK, DATA und STROBE entsprechend ansteuern,
>> also immer DATA anlegen, t_setup warten, CLK hochziehen, t_hold warten,
>> CLK runter und wieder von vorne, anschließend nach der letzten CLK noch
>> STROBE für eine entsprechende Zeit hochziehen um die Daten zu
>> übernehmen.
>
> Das kling für mich sehr nach einem einfachen Schieberegister mit
> zusätzlichem Latch wie das SN74HC595.

Jop, dürften 3 Schieberegister hintereinander mit Latch sein.

> Ich hänge hier mal Code ran der 8 Bits überträgt und dann einen Puls für
> das Latch ausgibt. Das kannst du sehr wahrscheinlich einfach anpassen.

Genau sowas ging mir als Counter Variante durch den Kopf, aber stimmt 
schon die Lesbarkeit leidet da etwas...

: Bearbeitet durch User
von Christoph Z. (christophz)


Lesenswert?

VHDL hotline schrieb im Beitrag #6138587:
> Tim T. schrieb:
>> wie würdet Ihr das machen
>
> FSM. Wieviel "Geschreibsel" das ist, hängt davon ab, was deine FSM macht
> bzw. wie geschickt du es implementierst.

Einen Editor benutzen, der einem beim Schreiben von VHDL unterstützt, 
damit das meiste von diesem "Geschreibsel" der Editor einfügt und nicht 
von dir getippt werden muss.

Mein persönlicher Favorit ist immer noch der VHDL Modus von Emacs, aber 
es gibt noch andere Editoren, die einem anständig unterstützen können 
(Die Editoren die mit den EDA Tools mitkommen sind alle schlecht, wohl 
weil kein Entwickler bei diesen Firmen diese nutzen würden).

von VHDL hotline (Gast)


Lesenswert?

Tim T. schrieb:
> Habs jetzt erstmal so gelöst, muss mir nur noch was für den Reset
> überlegen:

Wow, das war jetzt ja echt viel Geschreibsel... ;-) .

Falls du einen Xilinx-FPGA verwendest und die FSM nur einmal beim 
FPGA-Start laufen soll, kannst du den Resetzustand der FSM gleich in die 
Signaldeklaration schreiben, also
1
signal state : t_state := start;

Deine strobe-Zustände am Ende kannst du sinnvollerweise auch mit einem 
Zähler zusammenfassen, wie vorher beim hold.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

VHDL hotline schrieb im Beitrag #6138733:
> Tim T. schrieb:
>> Habs jetzt erstmal so gelöst, muss mir nur noch was für den Reset
>> überlegen:
>
> Wow, das war jetzt ja echt viel Geschreibsel... ;-) .

Ging mir allgemein darum wie man das am besten angeht, zugegeben hier 
wars diesmal nicht so schwer wobei ich mir immernoch was für einen 
sinnvollen Reset überlegen muss.

>
> Falls du einen Xilinx-FPGA verwendest und die FSM nur einmal beim
> FPGA-Start laufen soll, kannst du den Resetzustand der FSM gleich in die
> Signaldeklaration schreiben, also
>
>
1
> signal state : t_state := start;
2
>

Ist bekannt und auch so im Source, aber ganz so einfach ist es hierbei 
nicht, wollte schon zwischendurch einen Reset auslösen können.

>
> Deine strobe-Zustände am Ende kannst du sinnvollerweise auch mit einem
> Zähler zusammenfassen, wie vorher beim hold.

Da es nur 4 Clocks waren, fand ich es so einfacher, aber sonst ja.

von Gustl B. (-gb-)


Lesenswert?

Was soll der Reset denn überhaupt machen? Ich könnte mir vorstellen, 
dass der Reset einen definierten Defaultwert ausgibt und in die PLL 
schreibt.
Aber dazu braucht man doch keinen Reset in dieser Komponente sondern 
übergibt ihr einfach den auszugebenden Defaultwert. Ich sehe da keinen 
Grund für einen Reset.

von VHDL hotline (Gast)


Lesenswert?

Tim T. schrieb:
> wobei ich mir immernoch was für einen
> sinnvollen Reset überlegen muss.

Tim T. schrieb:
1
> when done =>     idt_strobe  <= '0';
2
>                   state <= done;
3
                   if (reset = 1) then
4
                      state <= start;
5
                   end if;

Vielleicht so? Wobei Gustl B. ja schon geschrieben hat, dass die 
Resetfunktion nicht so richtig klar ist.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

VHDL hotline schrieb im Beitrag #6138766:
> Tim T. schrieb:
>> wobei ich mir immernoch was für einen
>> sinnvollen Reset überlegen muss.
>
> Tim T. schrieb:
>
>
1
>> when done =>     idt_strobe  <= '0';
2
>>                   state <= done;
3
>                    if (reset = 1) then
4
>                       state <= start;
5
>                    end if;
6
>
>
> Vielleicht so? Wobei Gustl B. ja schon geschrieben hat, dass die
> Resetfunktion nicht so richtig klar ist.

Wenn ich mich darauf beschränke das der Reset nur ausgelöst werden darf 
wenn die Initialisierung druch ist, dann ja, einsynchronisiert ist der 
Reset eh, aber was mache ich wenn es einen Grund für einen Reset gibt 
bevor das Ding fertig initialisiert ist?
Das Zweite ist, wie reagiert die PLL darauf wenn während der 
Initialiserung einfach nochmal von vorne angefangen wird, leider 
schweigt sich das Datenblatt dazu aus, ich gehe aber einfach mal von 
einem 24 Bit Schieberegister aus, wo die Bits des ersten 
Teilinitialisierung einfach hinten Rausfallen und dann die neuen Daten 
gelatcht werden. Ein gezieltes Reset über einen dedizierten Pin ist 
leider nicht möglich, der entsprechende Pin der PLL ist nicht zum FPGA 
geführt.

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


Lesenswert?

Tim T. schrieb:
> wollte schon zwischendurch einen Reset auslösen können.
Was soll der Reset bewirken? Woher kommt der Reset? Was passiert sonst 
noch bei dem Reset? Kannst du statt eines Resets nicht einfach das FPGA 
neu laden?

Tim T. schrieb:
> leider schweigt sich das Datenblatt dazu aus
Leider wissen wir nicht, welches Datenblatt du meinst. Ausser, dass es 
wahrscheinlich eine PLL von IDT ist...

: Bearbeitet durch Moderator
von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Tim T. schrieb:
>> wollte schon zwischendurch einen Reset auslösen können.
> Was soll der Reset bewirken? Woher kommt der Reset? Was passiert sonst
> noch bei dem Reset? Kannst du statt eines Resets nicht einfach das FPGA
> neu laden?

Hauptgrund (eigentlich der Einzige) für einen Reset könnte ein Fehler 
auf einer der Versorgungsspannungen sein, die werden kontinuierlich 
getestet und melden das dem FPGA, der daraufhin eine entsprechende 
Behandlung ausführt.
Im Zweifelsfall wird auch der FPGA neu geladen, ja aber nicht unbedingt 
bei allen Fehlern, nur wenn die FPGA Versorgung betroffen ist, aber dann 
ist es eh egal.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Tim T. schrieb:
>> leider schweigt sich das Datenblatt dazu aus
> Leider wissen wir nicht, welches Datenblatt du meinst. Ausser, dass es
> wahrscheinlich eine PLL von IDT ist...

ICS307M-02LF von IDT

https://www.idt.com/document/dst/307-02-datasheet


OK, in dem Datenblatt steht auch der entscheidende Satz: "The ICS307 can 
be reprogrammed at any time during operation."

: Bearbeitet durch User
von Gustl B. (-gb-)


Lesenswert?

Über #PDTS könntest du den Chip selbst doch auch resetten wenn ich das 
richtig sehe?!

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Gustl B. schrieb:
> Über #PDTS könntest du den Chip selbst doch auch resetten wenn ich das
> richtig sehe?!

Das ist eine Gute Frage, egal wie oft ich den 2. Satz über den Powerdown 
auch lese, ich komme einfach nicht dahinter was er eigentlich sagen 
will...

Satz 1:
"When the PDTS pin is pulled low, the chip will enter the power-down 
mode, where the output clocks are tri-stated and the rest of the chip is 
powered down."

Satz 2:
"The chip can be programmed during power-down mode, however, if the chip 
is programmed during operation and enters power-down mode, the registers 
will return to their settings and not reset when exiting power-down mode 
(PDTS pin is pulled high)."

Wobei ich mittlerweile eine Tendenz dazu hab, das der Chip nach dem 
Powerdown wieder die vorherigen Werte annimmt und nicht resettet wird, 
aber sicher bin ich mir da nicht.

Aber unabhängig davon ist der PDTS auch nicht am FPGA, also eigentlich 
auch egal.

: Bearbeitet durch User
von Gustl B. (-gb-)


Lesenswert?

Du hast Recht, das ist wirklich kein Reset. Also bleibt dir nur als 
"Reset" die Defaultwerte hineinzuschreiben.

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


Lesenswert?

Tim T. schrieb:
> ich gehe aber einfach mal von einem 24 Bit Schieberegister aus, wo die
> Bits des ersten Teilinitialisierung einfach hinten Rausfallen und dann
> die neuen Daten gelatcht werden.
Es werden die zuletzt eingeschobenen 24 Bit gelatcht. Die "Note" im 
"Programming Example" zeigt das dann auch an:
1
As show in Figure 2, after these 24 bits are clocked into the ICS307-02, taking STROBE high will send this data to the internal latch and the CLK output will lock within 10 ms.
2
3
Note: If STROBE is in the high state and SCLK is pulsed, DATA is clocked directly to the internal latch...
Es gibt ein SCLK-taktgesteuertes Schieberegister und ein pegelabhängiges 
STROBE-Latch. Im Schieberegister werden einfach die Daten 
durchgeschoben. Wenn STROBE während des Schiebens aktiv ist, ist das 
Latch transparent und jedes Bit bringt neue Überraschungen.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> Tim T. schrieb:
>> ich gehe aber einfach mal von einem 24 Bit Schieberegister aus, wo die
>> Bits des ersten Teilinitialisierung einfach hinten Rausfallen und dann
>> die neuen Daten gelatcht werden.
> Es werden die zuletzt eingeschobenen 24 Bit gelatcht. Die "Note" im
> "Programming Example" zeigt das dann auch an:
>
1
> As show in Figure 2, after these 24 bits are clocked into the ICS307-02, 
2
> taking STROBE high will send this data to the internal latch and the CLK 
3
> output will lock within 10 ms.
4
> 
5
> Note: If STROBE is in the high state and SCLK is pulsed, DATA is clocked 
6
> directly to the internal latch...
7
>
> Es gibt ein SCLK-taktgesteuertes Schieberegister und ein pegelabhängiges
> STROBE-Latch. Im Schieberegister werden einfach die Daten
> durchgeschoben. Wenn STROBE während des Schiebens aktiv ist, ist das
> Latch transparent und jedes Bit bringt neue Überraschungen.

Ja, den Teil hatte ich auch gesehen (und das Bild vom Block Diagram), 
daher auch die Idee das einfach immer die letzten 24 Bit vor dem Strobe 
übernommen werden könnten. Manchmal gehen die Amerikaner mir mit ihrer 
unpräzisen Ausdrucksweise schon auf den Wecker... Hätten ja auch einfach 
schreiben können das die letzten 24 in den Chip getakteten Bits beim 
Strobe übernommen werden, evtl. mit dem Hinweis das wenn weniger als 24 
Bits in den Chip getaktet wurden die fehlenden Bitstellen im 
Schieberegister mit undefiniertem Müll gefüllt sind.

Also werde ich jetzt in jeden State wohl einfach ne Reset Abfrage machen 
und dann jeweils zum Start State verzweigen, wobei das natürlich wieder 
genau die Art vom stupidem rumtexten ist, die ich gerne vermeiden würde.
Oder hat jemand dazu noch ne elegantere Idee?

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


Lesenswert?

Tim T. schrieb:
> Also werde ich jetzt in jeden State wohl einfach ne Reset Abfrage machen
Ich würde das Verhalten von Signalen in Prozessen vorteilhaft anwenden 
und es basierend auf deinem Code einfach so machen:
1
InitPLL : process(clk_100mhz)
2
  begin
3
    if (rising_edge(clk_100mhz)) then
4
5
     case state is
6
       :
7
       :
8
     end case;
9
    
10
     if reset = '1' then -- letzte Zuweisung "gewinnt"
11
       state <= start;
12
     end if;
13
14
   end if;
15
 end process;

: Bearbeitet durch Moderator
von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Oh man, klar wieder total das Brett vorm Kopf gehabt. Danke Dir

Und im übrigen auch den Anderen hier im Thread, insbesondere auch die 
Lösung mit dem Zähler von Gustl B. werde ich mir bei Gelegenheit mal 
genauer anschauen.

: Bearbeitet durch User
von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

Die Idee mit dem Zähler ist Folgende:

Der Zähler(n-1 downto 0) ist n Bits lang. Und zählt nach oben.

Jetzt werden die obersten Zähler(n-1 downto n-X) Bits als Adresse für 
das auszugebende Bit, und das Bit Zählers(n-X-1) als "Takt" verwendet. 
Die Bits Zähler(n-X-2 downto 0) sind dann noch übrig und dienen als 
Taktteiler. Dann kann man den Zähler schön bequem mit Systemtakt 
betreiben und bekommt trotzdem einen deutlich niedrigeren Takt für das 
Schieberegister.

Beispiel:
Du willst 24 Bits ausgeben. Das sind also schon 5 Bits für die Adresse.
Dann das eine Bit für den Takt.
Und dann haben wir jetzt als Beispiel 100 MHz Systemtakt und wollen aber 
nur maximal 8 MHz Takt für das Schieberegister. Das bedeutet wir teilen 
die 100 durch 8, bekommen 12,5 und nehmen die nächste Zweierpotenz, 16, 
das sind 4 Bits. Das 4. Bit vom LSB aus ist also der neue Takt (das sind 
dann 6,25 MHz) und die 3 niederwertigsten Bits sind die Taktteiler.
Der Zähler muss insgesamt mindestens 5+4=9 Bits lang sein.
Es bietet sich an einen Alias für die Adresse zu verwenden und intern 
ein Register das bei einem Startsignal den Inhalt überreicht bekommt. Da 
der Zähler bei mir nach oben zählt, aber das MSB zuerst ausgegeben 
werden soll, habe ich intern das TX_Reg als ein 0 to 23 beschrieben.
Zusätzlich gibt es noch ein Ready als Ausgang der sagt wann 
fertiggeschoben ist.
Das gibt es jetzt hier als Anhang, es wird nach 200 ns für einen Takt 
lang Start auf '1' gesetzt und die Daten x"ABCDEF" übergeben. Danach 
wird herausgeschoben und am Ende einmal das Latch gepulst.
Damit man auch beobachten kann was passiert gibt es mehrere Bausteine:
1. Die Komponente die die Daten bekommt mit dem Startsignal und die dann 
herausschiebt. Ich habe sie SR_24Bit genannt.
2. Den IC Baustein, also das Schieberegister in das hineingeschoben 
wird, das ist quasi dein PLL Baustein, hier SR_24Bit_IC genannt.
3. Die SR_24Bit_bench, das ist die Testbench die die Komponente im FPGA 
mit dem IC verbindet und der Komponente einmal die 24 Datenbits 
überreicht.
Die ZIP Datei enthält das schön als Xilinx Vivado Projekt.

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.