Hallo, nachdem ich nun die ersten 200 Seiten vom Reichardt/Schwarz gelesen habe, ist es an der Zeit mal mit ein wenig eigenem Code zu beginnen. Eine Teilaufgabe: Übertragung einiger Datensätze von einem uC auf den FPGA, über einen 8 Bit breiten Bus, getaktet durch ein CLK-Signal vom uC. Im Prinzip kein Problem, ich schicke zunächst einen Code, der angibt welchen Konfigurationswert ich schreiben will, danach den Wert. Das sieht dann wohl ganz grob so aus: p1: process (CLK) begin if rising_edge(CLK) case COMMAND is when C0 => D0 <= DATA; when C1 => D1 <= DATA; ... end case; end if; end process p1 Soweit kein Problem, auch wenn ich vielleicht einige Syntax-Fehler getippt habe und sicher noch vieles beachten muss. Nur: Ich habe ca. 20 Konfigurationswerte, die ich wahlweise setzen will, also auch 20 when Statements. Irgendwo anders werden die Werte dann abgefragt, etwa if D1 == 100 then ... Nun könnte man ja auf die Idee kommen, die Werte statt in gewöhnlichen Registern im Block- oder Distributed-RAM abzulegen, der Code wäre dann kürzer: p1: process (CLK) begin RAM(COMMAND) <= Data; end process p1 if RAM(C1) == 100 then ... Bei einem uC würde man es so machen, Zugriff auf ein ARRAY-Element mit konstantem Index entspricht ja praktisch dem Zugriff auf eine gewöhnliche Variable. Aber bei VHDL? "RAM(C1) == 100" (C1 ist Konstante) könnte schon deutlich aufwendiger/langsamer sein als "D1 == 100"... Und noch eine kurze Anschussfrage: Wenn ich Block- oder Distributed-RAM im FPGA verwende, etwa 16 bit breit. Kann ich dann einen Unterbereich ansprechen, etwa die unteren 8 Bit? Vielleicht mit RAM(ADR) (7 downto 0) <= "01010101" Gruß Stefan
Beckenrandschwimmer schrieb: > Übertragung einiger Datensätze von einem uC auf den FPGA, über > einen 8 Bit breiten Bus, getaktet durch ein CLK-Signal vom uC. Getaktet durch ein Taktsignal vom uC, das komplett unabhängig ist vom FPGA-Mastertakt? Dann solltest du dir einen Mechanismus zum sauberen Taktdomänenübergang ausdenken. > könnte schon deutlich aufwendiger/langsamer sein als "D1 == 100"... Warum? Das wird der Synthesizer schon richten ;-) Und: was spricht gegen Ausprobieren? > Wenn ich Block- oder Distributed-RAM im FPGA verwende, etwa 16 bit breit. > Kann ich dann einen Unterbereich ansprechen, etwa die unteren 8 Bit? Nein. Du mußt immer die gesamte Breite des Ports beschreiben. Wenn du dort nur die unteren Bits manipulierst, dann wird für die oberen einfach der alte Wert oder ein Defaultwert ('0') genommen.
Hallo Lothar Miller, erstmal danke für die Antwort. >Und: was spricht gegen Ausprobieren? Zunächst bin ich grundsätzlich nicht so der Probiertyp -- lieber erstmal Lesen, Nachdenken, nochmal Lesen, dann evtl. Google Suche und Fragen. Ausprobieren dann ganz zum Schluss, wenn man es verstanden hat. In diesem Fall hätte ich das Probieren durchaus etwas vorgezogen -- nur habe ich dieses Xilinx Webpack derzeit nicht installiert und muss den Umgang damit demnächst auch noch etwas üben. >Getaktet durch ein Taktsignal vom uC, das komplett unabhängig ist vom >FPGA-Mastertakt? Dann solltest du dir einen Mechanismus zum sauberen >Taktdomänenübergang ausdenken. Ja, das ist wahr und mir klar. Wobei aber immer nur einer der Takte aktiv ist. Entweder der uC kommuniziert mit dem FPGA, dann ist der langsame Takt vom uC aktiv. Oder der FPGA liest Daten vom ADC und legt sie im RAM ab, dann setzt der FPGA ein RECORDING Flag -- der uC schweigt. >> könnte schon deutlich aufwendiger/langsamer sein als "D1 == 100"... >Warum? Das wird der Synthesizer schon richten ;-) Das ist genau der Punkt, wo ich zweifel. Ich habe konkret dazu nicht viel gefunden. Eventuell handelt man sich durch RAM irgendwelche Nachteile ein. Bist Du denn wie ich auch der Ansicht, dass mein erster Code mit den ca. 20 "when" Statements recht umständlich/aufwendig ist. Oder sollte der Synthesizer das gut optimieren, vielleicht von selbst RAM verwenden? Im Prinzip ist das ja eine Art Demultiplexer, also nicht so total ungewöhnlich. >> Wenn ich Block- oder Distributed-RAM im FPGA verwende, etwa 16 bit >>breit. Kann >>ich dann einen Unterbereich ansprechen, etwa die unteren 8 Bit? >Nein. Du mußt immer die gesamte Breite des Ports beschreiben. Wenn du >dort nur die unteren Bits manipulierst, dann wird für die oberen einfach >der alte Wert oder ein Defaultwert ('0') genommen. Ich möchte in der Tat, dass die Bits, die ich nicht beschreibe, erhalten bleiben. Geht das? Na demnächst werde ich mal versuchen einen kompletten VHDL-Code zu posten, dann wird alles etwas konkreter -- und dieses Webpack Monster runterladen und installieren. Gruß Stefan
Hallo Lothar, >Getaktet durch ein Taktsignal vom uC, das komplett unabhängig ist vom >FPGA-Mastertakt? Dann solltest du dir einen Mechanismus zum sauberen >Taktdomänenübergang ausdenken. Nachdem ich nun ein paar Zeilen VHDL eingetipp habe, frage ich mich gerade, ob ich total auf dem Holzweg bin... http://www.ssalewski.de/tmp/Start.vhdl Mit dem inout Bus zum uC geht es so sicher nicht, dass ist mir gestern klar geworden, ich muss zunächst separate in und out Register definieren und die dann über einen Bustreiber zusammenfassen, wie bei Reichardt/Schwarz Code 4-4. Aber zu den zwei Takten: Soll man ja eigentlich vermeiden, aber was bleibt mir übrig? Ich habe die ADC, die mit 100 MHz laufen, deren Taktausgang (100 MHz) geht an den FPGA, der mit dieser Frequenz die Daten von den ADCs liest und ins BLOCK-RAM oder externes RAM schreibt. Und wenn er fertig ist, dann will der uC die Daten auslesen, viel langsamer, und über USB zum PC schicken. Den Takt dazu erzeugt der uC selbst, es ist auch kein wirklich periodischer Takt, der uC legt z.B. ein Wort an den 8 Bit Bus und zeigt dann durch toggeln des Taktpins, dass der FPGA das Wort übernehmen soll. Ich sehe momentan keine bessere Lösung. Ach ja, wo die Schaltpläne dazu liegen sollte ja bekannt sein: http://www.ssalewski.de/DAD.html.en
> Mit dem inout Bus zum uC geht es so sicher nicht, dass ist mir gestern > klar geworden, ich muss zunächst separate in und out Register definieren > und die dann über einen Bustreiber zusammenfassen Du kannst durchaus einen Tristate-Bus an den FPGA-Pins realisieren... > Aber zu den zwei Takten: Soll man ja eigentlich vermeiden, aber was > bleibt mir übrig? Mit einem DP-RAM lässt sich die Situation an der Taktdomänengrenze signifikant entspannen. > DATA_RAM_END : natural := DATA_RAM_START + DATA_RAM_SIZE Willst du wirklich 257 Bytes Data_Ram (0 to 256)? Ich werde mir den Code in nächster Zeit mal genauer anschauen... > RAM_POINTER == DATA_RAM_END Geht das wirklich, dieses Doppelgleich? > RAM_POINTER <= RAM_POINTER + 1; > if RAM_POINTER == DATA_RAM_END then > RAM_POINTER <= DATA_RAM_START; > end if; Wenn du die Sache am Anfang etwas weniger generisch angingest, würdest du sehen, dass hier ein einfacher Binärzähler, der automatisch überläuft, ideal wäre...
Hallo Lothar, >Ich werde mir den Code in nächster Zeit mal genauer anschauen... Ja, das wäre schon ganz nett. Wobei ich zugeben muss, dass mein VHDL Text durchaus das Prädikat "dahingeschwiert" verdient. Mir geht es momentan hauptsächlich um das grobe Konzept und sinnvolle Ansätze. Nicht dass ich mich da in die total falsche Richtung verrenne. >Willst du wirklich 257 Bytes Data_Ram (0 to 256)? Nein, diese Feinheiten habe ich aber zunächst nicht so ernst genommen... >Du kannst durchaus einen Tristate-Bus an den FPGA-Pins realisieren... Ja, und das mache ich dann wohl am besten mit einem separaten Entity/Architecture Paar wie im Reichardt/Schwarz Code 4-4 BUSTREIBER. >Geht das wirklich, dieses Doppelgleich? Danke, muss ein einfaches = sein. >Wenn du die Sache am Anfang etwas weniger generisch angingest, würdest >du sehen, dass hier ein einfacher Binärzähler, der automatisch >überläuft, ideal wäre... Ist mir klar, nur bin ich dann auf Zweierpotenzen bei der RAM-Größe festgelegt -- was man wohl eh fast immer haben wird. Allerdings dachte ich, der einfache Test auf Gleichheit "if RAM_POINTER = DATA_RAM_END" wäre vom Aufwand vernachlässigbar. >Mit einem DP-RAM lässt sich die Situation an der Taktdomänengrenze >signifikant entspannen. Muss ich mal nachlesen. Aber wie ich schon schrieb, es ist ja immer nur ein Takt aktiv, das sollte daher nicht so kritisch sein. (Gleichzeitig Daten vom ADC im RAM abzulegen und über USB zu PC zu schicken würde auch kaum Sinn machen bzw. Vorteile bringen, denn die Datengenerierung von den ADCs ist viel schneller als das, was ich per FullSpeed USB wegschreiben könnte. Selbst die 40 MByte/s, die mit USB High-Speed möglich wären, würden da nicht viel beitragen. Und ich habe momentan nur den AT90USB mit FullSpeed. Anders wäre das bei langsamen Langzeitmessungen, aber das wäre dann eine spezielle Sonderanwendung.) Gruß Stefan
>dass mein VHDL Text durchaus das Prädikat "dahingeschwiert" verdient. OK, ein klein wenig aufgeräumt habe ich schon mal... http://www.ssalewski.de/tmp/Start.vhdl
Hallo Stefan, du machst deine Design eher Top-Down, nicht wahr? ;-) Welchen Bezug hat der CLK_UC zum Schreibsignal und zu den Daten? Läuft der dauernd durch, oder gibt es nur 1 Takt, wenn etwas gelesen werden soll? Solltest du dich nämlich mit dem BRAM anfreunden, dann hast du beim Lesen einen Takt Latency. Die Daten kommen also erst nach der nächsten Flanke. Damit muß der uC dann zurechtkommen. Zum Thema bidirektionaler Buffer: wenn das hier das einzige Modul ist (bzw. sein wird), in dem auf den UC-Datenbus zugegriffen wird, und zudem das Signal WE das Schreib/Lesesignal ist, dann solltest du es in etwa so machen:
1 | port ( UC_CLK, ADC_CLK, UC_WE, RESET: in std_logic; |
2 | RECORDING: out std_logic; |
3 | UC_DATA: inout std_logic_vector(BUS_UC_WIDTH - 1 downto 0); |
4 | :
|
5 | signal UC_DIN: std_logic_vector(BUS_UC_WIDTH - 1 downto 0); -- Daten uC -> FPGA |
6 | signal UC_DOUT: std_logic_vector(BUS_UC_WIDTH - 1 downto 0); -- Daten FPGA -> uC |
7 | :
|
8 | -- Bustreiberumschaltung
|
9 | UC_DATA <= UC_DOUT when UC_WE='0' else (others=>'Z'); |
10 | UC_DIN <= UC_DATA; |
Das asynchrone Umschalten des IO-Treibers ist nötig, weil du sonst immer wieder einen Buskonflikt oder einen offenen Bus hast. Ich sehe noch ein paar graue Haare für den ByteCounter. Wie wirst du den synchronisieren? BTW: nimm doch statt der bit nur std_logic (und deren Vektoren). Bei bestimmten Funktionen könnte es sonst sein, dass du unnötig zwischen den beiden Datentypen hin- und herwandeln mußt.
Hallo Lothar, >du machst deine Design eher Top-Down, nicht wahr? ;-) Grundsätzlich ja. Auch wenn es die Meisten hier wohl anders machen -- z.B. mit AVR-Studio mal eine Zeile etwas ändern, Compilieren und sehen was raus kommt. Warum sollte man auch erst Nachdenken... Bottom-Up hat sicher auch seine Berechtigung, würde ich sogar machen, wenn ich meine bestückte Platine schon vorliegen hätte. Da mich ein Prototyp ca. 1000 Euro kostet, will ich zunächst etwas VHDL-Code entwerfen -- noch kann ich an der Hardware notfalls Änderungen machen. (Ich habe zwar ein Spartan3E Board von Digilent im Schrank liegen -- aber meine konkrete Anwendung kann ich damit nicht wirklich gut testen.) Die Platine ist übrigens auch eher Top-Down entstanden. Wenn ich da jede Teil-Komponente zunächst auf Lochraster getestet hätte, dann wäre ich wohl nie fertig geworden. Aber mit der Platine habe ich eigentlich ein ganz gutes Gefühl. Störungen von den Schaltreglern könnten mir etwas zu viel "Rauschen" erzeugen, ja. Aber Hauptsache sie funktioniert überhaupt. Das andere Problem wäre der Frequenzgang der Reed-Relais -- hätte man eigentlich zu Anfang mal messen sollen, aber bis 50 MHz wird der Frequenzgang wohl glatt sein, mit etwas Glück bis 100 MHz. Pech wäre, wenn ich bei der Beschaltung des FPGA etwas falsch gemacht habe, dann muss ich gleich die nächste Platine ordern. >Welchen Bezug hat der CLK_UC zum Schreibsignal und zu den Daten? >Läuft der dauernd durch, oder gibt es nur 1 Takt, wenn etwas gelesen >werden soll? Letzteres hatte ich vor. Ich muss dazu sagen, dass ich mit der Anzahl der zur Datenübertragung zwischen FPGA und uC verwendbaren Pins nicht sehr großzügig ausgestattet bin. Ich möchte ein komplettes Port-Byte des uC für die eigentlichen Daten nehmen, und maximal 4 weitere Signale: CLK_UC, WE (Write_Enable), BUSY/RECORDING (output from FPGA when recording data) und vermutlich nötig RESET. USB Fullspeed kann ja maximal ca. 1 MByte/s übertragen, daher möchte ich zwichen FPGA und uC nicht wesentlich weniger Datendurchsatz haben. Wobei der uC mit 8MHz rennt. >Ich sehe noch ein paar graue Haare für den ByteCounter. Wie wirst du den >synchronisieren? Die grauen Haare habe bzw. hatte ich auch -- bei einem Profi wie dir hätte ich sie eher nicht erwartet. Meine Lösung wäre: Ich schicke drei mal in Folge das Byte 0 über den 8 Bit breiten Bus -- da immer Adresse gefolgt von zwei Daten-Byte vom FPGA erwartet wird, ist so gewährleistet, dass ich an die Adresse 0 schreibe, und das wird vom FPGA als Reset erkannt, er setzt Byte-Counter auf 0. Könnte das so in etwa funktionieren? Eine andere Lösung, an die ich zunächst gedacht hatte: Pegeländerung von WE setzt Byte-Counter jeweils auf Null. Würde Sinn machen, mir ist aber nicht eingefallen, ob man das in VHDL realisieren kann. >BTW: nimm doch statt der bit nur std_logic (und deren Vektoren). Bei >bestimmten Funktionen könnte es sonst sein, dass du unnötig zwischen den >beiden Datentypen hin- und herwandeln mußt. Ja, danke für den Hinweis, aber das ist eher ein untergeordnetes Problem, später bei der Synthese sehe ich dann schon, welcher Typ am besten ist und welche Conversionen erforderlich sind. >dann solltest du es in etwa so machen: Darüber muss ich etwas nachdenken... Danke für Deine Unterstützung. Gruß Stefan
Hallo Lothar, >Ich sehe noch ein paar graue Haare für den ByteCounter. Ich könnte natürlich das CONF_RAM lediglich 8 Bit breit machen, und über ein Port-Signal jeweils anzeigen, ob ich die CONF_RAM-Adresse oder deren Inhalt schreiben bzw. lesen will. Dann brauche ich neben den 8 Bit für den Datenbus mindestens die externen Signale CLK_UC, WE, und ADR (Adresse lesen/schreiben). Eventuell noch RECORDING und RESET, aber ich habe die Vermutung, dass man die durch den Inhalt von Speicherzellen von CONF_RAM "simulieren" kann. Klingt gut und einfacher. Nur arbeite ich im FPGA eher mit 32 oder 16 Bit Werten wie PRETRIGGER usw. -- die muss ich dann wohl zunächst aus den einzelnen Bytes von CONF_RAM zusammensetzen. Aber gut. Das werde ich morgen mal probieren. >Solltest du dich nämlich mit dem BRAM anfreunden, dann hast du beim >Lesen einen Takt Latency. BRAM==Block-Ram? Weiter oben hattest Du ja DP-RAM erwähnt, das ist wohl wieder etwas anderes, Dual-Ported vielleicht, muss ich mal nachlesen. Gruß Stefan Halt, da fällt mir noch ein... Wenn ich drei Signale habe, std_logic_vector oder bit_vector... signal a: bit_vector (7 downto 0); signal b: bit_vector (7 downto 0); signal c: bit_vector (11 downto 0); hat man Ausdrücke wie c <= b(3 downto 0) & a(7 downto 0); Soweit klar, wenn ich mich nicht in der Syntax vertan habe. Aber wenn die Anzahl der Bits von c nun durch eine Generics Anweisung bestimmt ist, und ich alle Bits von a und b einsammeln möchte, soweit sie eben in c hineinpassen? Wie schreibt man das dann hin. Kann man irgendwie eine Fallunterscheidung machen, ähnlich wie in C mit #ifdef. Oder führt man eine Variable ein, an die man a und b zunächst zuweist, und dann von der Variablen wieder die durch generics bestimmten bits an c? Schlecht formuliert von mir, aber sollte verständlich sein, und hier list ja ausser uns beiden eh keiner mehr mit.
Doch! Ich lese noch mit.. Aber wie gehts weiter? @Stefan Wie weit bist du mit deinem Projekt? Grüße Steffen H.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.