====== FPGA NEXYS3 FUN ====== {{tag>project hardware electronics software}} Das Board: [[http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,400,897&Prod=NEXYS3|Digilent NEXYS3]] Gekauft als Academic Board bei: [[http://shop.trenz-electronic.de/catalog/product_info.php?cPath=1_114_123&products_id=963|Trenz Electronic]] {{http://shop.trenz-electronic.de/catalog/images/products/24143gross.jpg}} ===== Ubuntu ===== [[http://www.xilinx.com/support/download/index.htm|Xilinx ISE WebPack]] - die IDE die empfohlen wird um VHDL für den Spartan-6 zu schreiben, gibt es auch für Linux. Das Problem ist nur, nicht für Ubuntu. Mit dem Programm [[http://www.digilentinc.com/Products/Detail.cfm?Prod=ADEPT2|ADEPT2]] von Digilent wird dann das erzeugte .bit file in den FPGA geladen. Nur hat es unter Linux auch nicht die wunderhübsche GUI wie unter Windows. Unter Linux, nach der Installation der USB Treiber kann man mit djtgcfg --enum die Boards auslesen die mit USB gerade verbunden sind und mit djtgcfg prog -d Nexys3 -i 0 -f ~/path_to/file.bit den FPGA mit dem .bit File programmieren. //(OT: wer kommt auf den bescheuerten Namen djtgcfg für das Programm? wenn man adept2 installiert erwartet man, dass das Programm auch adept2 heißt... fuuuuuuu)// inzwischen bin ich auf die Windows Version von Adept2 und ISE umgestiegen und arbeite in einer Windows VM auf meinem MacBook Air. ===== Ansteuern der 4x 7-Segment-Displays ===== Nach 5 Tagen mein erster großer Erfolg. Ich habe es endlich geschafft, die 4 7-Segment-Displays auf meinem Board anzusteuern. Der Code ist auf github.com zu finden. Eigentlich ist es einfach. Es gibt die Andode an(0..3), mit der man die einzelnen Anzeigen ansteuert. Auf seg(0..7) kann man die einzelnen Segmente a,b,c,d,e,f,g und punkt anzeigen. Man muss also multiplexen. Dies geht in VHDL auch gut. (Obwohl ich hier ein paar Warnings und Errors immer bekam und ich sie mir nicht logisch erklären kann. Aber jetzt funktiniert es endlich): process begin if (Clock'event and Clock = '1') then -- multiplex foo end if; end process; Ich habe dann einen Counter von 0-3 mit jedem Takt zählen lassen und dann die Signale für an und seg gesetzt. if COUNT1 = 0 then case in1 is --hgfedcba when "0000"=> out1 <="11000000"; -- '0' when "0001"=> out1 <="11111001"; -- '1' when "0010"=> out1 <="10100100"; -- '2' when "0011"=> out1 <="10110000"; -- '3' when "0100"=> out1 <="10011001"; -- '4' when "0101"=> out1 <="10010010"; -- '5' when "0110"=> out1 <="10000010"; -- '6' when "0111"=> out1 <="11111000"; -- '7' when "1000"=> out1 <="10000000"; -- '8' when "1001"=> out1 <="10010000"; -- '9' --nothing is displayed when a number more than 9 is given as input. when others=> out1 <="01111111"; end case; out2 <= "0111"; end if; Das hat leider nicht funktioniert. Auf allen Displays wurde immer das Gleiche angezeigt. Vermutet hatte ich erst einen Fehler in meinem Multiplexen oder Stellen berechnen: tausender := zahl / 1000; hunderter := (zahl - tausender*1000) / 100; zehner := (zahl - tausender*1000 - hunderter*100) / 10; einer := (zahl - tausender*1000 - hunderter*100 - zehner*10); Aber mit etwas nachrechnen, konnte auch hier nicht der Fehler liegen. Ich habe dann just4fun einen ClockDivider eingebaut, der für einen Takt, nun 10.000 normale Takte benötigt. Dann wurde die 7-Segment-Display richtig angezeigt - der FPGA ist einfach zu schnell :D Auf github.com gibt es mein Beispiel Programm, bei dem man über die Schalter eine binäre Zahl einstellen kann, und er bis da hin zählt. [[https://github.com/Samuirai/fpga/tree/master/Binary7SegCounter|git:Binary7SegCounter]] ===== Zugriff auf den RAM ===== Auf dem NEXYS3 Board ist ein CellularRam von Micron verbaut ([[http://download.micron.com/pdf/datasheets/psram/128mb_burst_cr1_5_p26z.pdf|datasheet]]). Ich habe sehr lange gebraucht, bis ich es endlich geschafft habe, sauber zu lesen und schreiben. Adept2 - das Tool mit dem man das .bit File auf den FPGA laden kann, ermöglicht auch das lesen und schreiben vom RAM. So konnte ich testen, ob alles funktioniert. {{:project:adept2.png|}} Ich habe den RAM an den ersten Speicherstellen auf 0 gesetzt, um richtig erkennen zu können, ob das schreiben funktioniert. {{:project:hex1.png|}} Als ich dann den FPGA programmiert habe und danach den RAM ausgelesen habe, konnte ich erkennen, dass mein Schreiben erfolgreich war. {{:project:screen_shot_2011-11-27_at_4.58.00_am.png|}} Inzwischen habe ich auch geschafft zu lesen. Ich habe die Funktionalität (Die State-Machine) in einen MemoryController ausgelagert und nun einfach lesen und schreiben zu können. Mein Beispiel Projekt befindet sich auch wieder auf [[https://github.com/Samuirai/fpga/tree/master/Memory|github.com/Samuirai/fpga/Memory]] ===== lessons learned ===== * Der FPGA verdammt schnell - eventuell hilft runtertakten. * Man darf nicht in das normale Programmier-Denken zurück fallen - hier gibt es keine Funktionen und return Werte. * Immer in Block-Diagrammen/Shematics denken. * An die Signallaufzeit von Signalen denken. Vor Allem bei schnellen Clocks. (States und Counter eventuell als Variabeln nehmen)