Mittwoch, 8. April 2015

Altera FPGA Konfiguration per SPI Flash im Active Serial-Modus

In meinem AmbiController-Projekt verwende ich einen Cyclone IV EP4CE6 FPGA von Altera. Da in diesem Chip kein persistenter Speicher enthalten ist benötigt dieser einen externen Speicherbaustein wie beispielsweise den EPCS16. Dieser ist jedoch recht teuer. Alternativ kann auch ein einfaches serielles SPI Flash mit z.B. 16MBit Speicher verwendet werden. Wie zum Beispiel ein MP25P16, den ich verwende. Dieser ist schaltungstechnisch identisch zum EPCS16 mit dem FPGA verbunden uns wird per SPI angesteuert. Die maximale Frequenz die bei der Kommunikation verwendet werden kann liegt bei 50 MHz.

Für die Konfiguration des FPGA/Flash habe ich bisher immer einen Altera USB-Blaster - China-Clon verwendet, dieser piept zwar hochfrequent wenn man ihn verwendet aber er tut seinen Zweck sonst einwandfrei. Als Software verwende ich Alteras Quartus II bzw. den "Programmer" welcher dort mitgeliefert wird.

Zum Ablauf: Das Flash wird über den FPGA, welcher per JTAG über den USB-Blaster - Clon beschreiben. Hierzu kommt ein "JIC"-File zum Einsatz damit das Design des FPGA persistent im Flash abgelegt wird. Das funktioniert einwandfrei.

Allerdings muss ich dazu sagen, dass ich damit nicht wirklich zufrieden bin. Das Problem ist, dass man in jedem Fall die doch recht unhandliche Quartus II - IDE benötigt. Und das auch in dem Fall um nur kurz ein neues Design auf den Flash übertragen zu können. Wirklich sehr umständlich!

Ich halte mein AmbiController - System jedoch gerne vollkommen frei von Entwicklungsumgebungen, also überdimensional großen Tools wie ein ATmel-Studio oder auch Altera Quartus II. Es ist daher schon immer mein Ziel gewesen die Firmware des Mikrocontrollers als auch das Design des FPGA per USB aktualisieren zu können. Da der Update-Vorgang eines Mikrocontrollers per USB bereits eher Standard ist, gehe ich hierauf nicht groß weiter ein.

Für das Update des FPGA-Flash-Inhaltes ist jedoch bei weitem mehr zutun als am Anfang gedacht...

Zum gewünschten Abauf:
Der Plan war zunächst den AVR XMega per SPI (parallel) zum FPGA anzuschließen und bei Bedarf auf den SPI Flash zuzugreifen. Per USB wird zum Mikrocontroller eine Verbindung aufgebaut, dieser darauf hin in einen Zustand gebracht in dem der Flash zugängig ist (schreibend und lesend) und das Update kann durchgeführt werden.

Leider steckt hier der Teufel im Detail. Prinzipiell ist SPI auf einem Mikrocontroller eine standardisierte Schnittstelle welche - simpel - mittels ATmel Application notes und kurzen Beispielen quasi direkt verwendet bzw. integriert werden kann.

Leider ist es bei SPI jedoch nicht vorgesehen ein MultiMaster-System aufzubauen - bei SPI kann es immer nur einen Master geben welcher mit allen Slaves selektiert kommuniziert. Aufgrund dieser Gegebenheit muss also der FPGA zunächst in einen Zustand gebracht werden in dem er alle SPI-Spezifischen Pins/Leitungen unberührt belässt. Im Aktiven Zustand würde dieser die Signale des AVR grundsätzlich verfälschen, was natürlich nicht erwünscht ist. Mit unberührt ist hier übrigens gemeint das alle Pins des FPGA als hochohmig konfiguriert sind, also keine messbaren Auswirkungen auf die SPI-Leitungen haben.

In meinem Fall habe ich hierzu die Chip-Enable-Leitung (nCE) des FPGA auf High gesetzt, und die nConfig-Leitung des FPGA auf Low. Damit verfällt der FPGA in einen unkonfigurierten Zustand - zum Glück gibt es bei derart schwer zu findenden Antworten auf derartige Probleme noch nette Leute in öffentlichen Foren - in dem alle Pins hochohmigen geschalten sind. Hochohmig bedeutet, dass hier keine Spannungen (durch den FPGA) anliegen und auch kein (messbarer) Strom in irgend eine Richtung an den betreffenden Pins fließt.

Ist der SPI Bus nun vom FPGA losgelöst kann im Mikrocontroller die SPI-Schnittstelle konfiguriert und verwendet werden. Ist hingegen der FPGA aktiv sollten alle SPI-Spezifischen Pins des Mikrocontroller hochohmig gesetzt worden sein, damit diese nicht die Kommunikation des FPGA mit dem Flash stören. Nachdem der Mikrocontroller die SPI-Schnittstelle nicht mehr benötigt sollte diese also wieder deaktivert werden, die Pins hochohmig geschalten und daraufhin der FPGA wieder in den "normalen" Betrieb geschalten werden. Der FPGA lädt sich daraufhin aus dem Flash das neue Design, sofern es aktualisiert wurde, und beginnt seine Arbeit.

Betrachtet man die einzelnen Aufgaben getrennt voneinander gestaltet sich das "Bild" nun deutlich einfacher, aber der Weg bis dahin kann sich ziehen wenn Informationen fehlen oder - wer hätte das gedacht - wenn die Hardware streikt.

Das interessante während der Entwicklung des Verfahrens war also das an meiner AmbiController - Hardware verwendete ATXMega192A3 den Betrieb der SPI-Schnittstelle verweigerte. Letztendlich habe ich drei (3) SPI-Implementierungen getestet, welche alle die interne SPI-Funktionalität verwenden. Und keine einzige hat auch nur ein einziges mal die Clock- oder MOSI-Leitung angesteuert.

Laut einschlägigen Foren ist natürlich dies absolut unmöglich... Vor allem da die Software, welche ich testen durfte von Personen stammte die sie ja erfolgreich seit Jahren auf anderen Controllern verwenden...
Leider hält sich mein Mikrocontroller aber nicht an deren Überzeugung und verweigert dennoch den Dienst. Auch mit gutem zureden war nichts zu bewege. Abhilfe hat mir dann eine Softwareseitige Implementierung einer Master-SPI-Schnittstelle gebracht. Diese ist vermutlich nicht ganz so performant und kompatibel bzw. generisch implementiert, jedoch fehlerfrei und funktionstüchtig.

Ich habe dann einige Zeit mit den Tests der SPI-Kommunikation verbracht, um einen Treiber zu implementieren welcher die Kommandos des SPI-Flashs beinhaltet, wie beispielsweise Pages zu schreiben oder lesen zu können.

Als Gegenstück dazu implementierte ich ein Kommandozeilen-Tool welches in der Lage ist per USB/Serielle Schnittstelle Daten aus dem Flash per Mikrocontroller auszulesen. Die ersten Tests verliefen zufriedenstellend, es kamen Daten aus dem Flash zurück. Der Sieg über Hard- und Software erschien mir sicher. Zumindest zunächst...

Auf den zweiten Blick hin wurden auch Muster, im Vergleich zu den von Quartus II erstellten Image-Dateien sichtbar. Jedoch mit einigen Unterschieden. Zu vielen Unterschieden...

Beispielsweise waren nur die Muster, also die Verteilung der Bytes in den Hexdumps der Dateien ähnlich/gleich. Nicht jedoch die einzelnen Byte. Dies lag daran das in den SOF- und JIC-Dateien - welche Quartus II einem erstellen kann - noch diverse weitere Header und Footer enthalten sind, und in den Flash-Daten selbst nicht mehr enthalten sind.

Weiterhin besteht der Grund für die Unterschieder ALLER Bytes im Flash zu den Quelldaten darin, dass alle Bytes einzeln nochmal bitweise umgekehrt werden (Bsp.: aus 0b0101_1000 wird 0b0001_1010). Mit einem Script, um Bytes in Dateien umzukehren, wurde der Vergleich des Flash-Inhaltes mit den Quelldateien einfacher.

Leider waren diese noch immer nicht identisch. Das Problem war natrlich das Datenformat der im Flash enthaltenen Daten. Es werden für das Konfigurieren eines FPGAs verschiedene Formate verwendet, welche abhängig sind von der verwendeten "Übertragungsform" und dem Flash (jedenfalls sind das die Hauptaussagen aus diversen Foren). Bei mir ist die Übertragungsform "Active Serial" - und damit eine SPI-Schnittstelle zwischen FPGA und einem seriellen Flash, wobei der FPGA der Master ist und sich die Daten aus dem Flash lädt. Der FPGA unterstützt dabei zudem auch eine Kompression der Daten.

Das untersuchen des Flash-Inhaltes nahm also noch kein gutes Ende. Als nächstes verglich ich verschiedene komprimierte und unkomprimierte - von Quartus II erzeugte - Dateien im RBF-Format (Raw-Binary-File) mit dem Flash-Inhalt. Dort hatte ich im Kopf der Dateien größere Unterschiede als im Rest der Dateien, und jede Zweite Page - im Flash - enthielt im letzten der 256 Bytes einer Page den Wert 0x05. Das RB-File enthielt dort weniger einheitliche Werte. Mein Tool zum Zugriff vom PC aus auf den Flash war zu diesem Zeitpukt bereits weiter entwickelt und nun auch in der Lage Daten in den Flash schreiben zu können...

Warum die Daten unterschiedlich waren konnte mir zunächst niemand sagen - wie auch - es lag an meiner Implementierung. Das letzte Byte einer zu schreibenden Page wurde nie korrekt verarbeitet. Diesen Leichtsinnsfehler/Tippfehler korrigiert, und schon waren die Images nahezu identisch. Lediglich in der ersten Page sind aktuell noch Unterschiede enthalten.

Der Grund ist hierfür angeblich, dass RBF nur für parallele Konfgurations-Arten verwendet werden. Der Header der Datei ist also noch unterschiedlich und das Image damit auch nicht lauffähig.

Was ist aber dann die Alternative?

Eine nette Person wies mich darauf hin, dass man mit den beiden Tools "sof2image" und "objcopy" Images erzeugen kann, welche auch beim konfigurieren mit "Active Serial" verwendet werden können. Die Verwendung ist einfach - sofern man keine Scheu vor einer Kommandozeile hat - es wird die mit Quartus II mitgelieferte NIOS2-Kommandozeige benötigt. Dort laufen alle benötigten Tools einwandfrei (bei Quartus II 13.1 auf Win7 Prof. 64bit und mti 14.x auf Win8.1 und Linux) und man kann die Konvertierung einer SOF-Dateirepräsentation des FPGA-Designs in ein Image vornehmen das dem tatsächlich
benötigten Flash-Inhalt entsprechen soll. Die NIOS2-Kommandozeile ist übrigens unter Windows nur eine "DOS-Box" (cmd.exe) in der ein Cygwin läuft.

Hier ein Beispiel für die Konvertierung:

$ sof2flash --input=fpga_design.sof --output=fpga_design.srec --compress --epcs --verbose
$ objcopy -I sreg -O binary fpga_design.sreg fpga_design.epcs_img -v

Vergleicht man nun die erzeugte Datei mit dem tatsächlichen Flash-Inhalt sind aber auch hier weiterhin Unterschiede vorhanden. Um genau zu sein 3 Byte in der ersten Page. Warum ist unklar - zumindest mir - aber interessanterweise funktioniert das erzeugte Image problemlos.

Damit ist für meinen AmbiController eine größere aber umso spannendere Hürde gemeistert, das FPGA Design per USB aktualisieren ohne die vollkommen überladene Quartus II - Umgebung von Altera verwenden zu müssen.

Was die Übertragungs-Geschwindigkeit angeht, mit der die Daten in den SPI Flash geschrieben werden, möchte ich bei Gelegenheit noch Tests durchführen.

Ich jedoch bereits Übertragungsraten von bis zu 60 kByte/s (lesend) vermessen können. Beim schreiben sinkt diese jedoch auf etwa 5,4 kByte/s (Win8.1 + Cygwin) und ca. 18kByte/s unter Linux.

Da die zu schreibenden Datenmengen jedoch sehr klein sind ist diese Geschwindigkeit noch nicht an bzw. über der Grenze zum unerträglichen.


Keine Kommentare:

Kommentar veröffentlichen

UpConverter fixed

Vor einiger Zeit berichtete ich darüber das mein Versuch einen UpConverter für mein rad1o zu bauen leider fehlgeschlagen ist. Es lag an der...