Servus, ich konfiguriere ein FPGA über eine USB/JTAG-Verbindung mit einem FT2232H. Dazu verwende ich den ftd2xx-Treiber und die entsprechende lib/API. Meine Software ist so implementiert, dass ich die Schreibzugriffe puffere und als 4K-Blöcke an die FT_WRITE()-Funktion weiter gebe. Dabei kam es sporadisch immer wieder mal vor, dass dass der Update-Vorgang fehlschlägt, also das FPGA nicht zum Leben erwacht. Diese lässt sich verhindern, wenn ich nach jedem FT_WRITE()-Aufruf ein Sleep(1) einfüge, was mich zu der Vermutung führt, dass da irgendein Buffer überläuft. Eigentlich würde ich aber erwarten, dass wenn ich schon vom Hersteller eine Lib bekomme, diese sich selbst um das Timing kümmert. Und im User-Manual von FTDI finde ich auch nirgendwo die Vorgabe irgendwelcher Wartezeiten. Auf eine entsprechende Anfrage an den Support kam keine Antwort. Weiß jemand mehr über das Thema?
Jetzt geht mir gerade auf, dass das hier vielleicht das falsche Forum ist...:-)
Hallo, passt ja gerade noch so :D Was passiert wenn du in 1K Blöcken schreibst? Evt. könnte es auch ein Timingproblem des FPGA's sein, das irgendwo nicht mitkommt. Kannst du irgendwo eine Frequenz oder Bitabstand angeben? Vill. gibt es irgendwo versteckte Defines mit der Buffergröße?
4K ist eben genau die Größe des Sendepuffers auf dem Chip. Wenn ich die JTAG-Frequenz runterdrehe, tritt der Fehler tendenziell häufiger auf, deshalb auch meine Vermutung mit dem Overflow. Das mit den 1K Blöcken müsste ich mal ausprobieren...
Es ist dann vill die Frage ob 4K = 4096 oder 4000 bzw. ob die 4K wirklich komplett für deine Daten draufgehen können.
Ich glaube auch, dass du für das FPGA zu schnell bist. Die ftd2xx schickt im Normalfall die komplette "Wurscht", also die kompletten 4k Daten raus, sobald du das FT_Write abgefeuert hast. Auch kehrt sie erst zurück, wenn alles gesendet ist, so hab ich das zumindest in Errinnerung. Somit gibt dein Sleep dem FPGA mehr Zeit und nicht nur der FTDI Lib. Aber iM DB des FPGA sollte hier schon was zu finden sein...
Das glaube ich eben nicht. Gerade wenn ich den JTAG-Takt kleiner mache, die Daten also langsamer ins FPGA schiebe, tritt der Fehler ja häufiger auf. Die FT_Write mag ja erst zurückkehren, wenn die Daten per USB abgeschickt sind, die Frage ist vielmehr ob sie auch sicherstellt, dass im Sendebuffer des Chips auch Platz dafür ist. Mein Buffer is 4096 Byte groß und beinhaltet sowohl meine Daten als auch die FT-MPSSE-Kommandos.
Das FPGA ist mal ganz sicher nicht zu langsam, denn die können meist 33MHz und mehr als JTAG Takt. UNd wenn es bei neidrigerem JTAG Takt öfter auftritt, deutet das stark auf einen Pufferüberlauf und fehlerhaftes Handshake hin.
Welches Kommando verwendest du denn? Irgendwie kommt mir 4096 gesamt komisch vor, wenn da die MPSSE auch mit dabei sind. Ich würde eher auf 4099 kommen, Kommando, LengthL, LengthH, Daten (4096). Evtl. hilft es dir auch, wenn du ein 0x87 Kommando ans Ende stellst. Ich hab mal eine Boundary Scan Lib auf Basis der ftd2xx geschrieben und da hab ich tausende Bytes in kürzester Zeit geschrieben und gelesen und konnte solche Probleme nicht feststellen. Ich behaupte sogar dass die FT_Write erst zurück kehrt, wenn die Daten tatsächlich raus gegangen sind. Alternativ könntest du natürlich auch ein Schreib/Lese Kommando nehmen, dann kehrt er 100% erst zurück, sobald die Daten durch geschoben sind... Gruß MB
Günter R. schrieb: > Welches Kommando verwendest du denn? Irgendwie kommt mir 4096 > gesamt > komisch vor, wenn da die MPSSE auch mit dabei sind. Ich würde eher auf > 4099 kommen, Kommando, LengthL, LengthH, Daten (4096). Versteh ich nicht. Ich kopiere halt die Daten in den Puffer, und sobald er voll ist oder ich explizit ein flush() aufrufe, wird der Inhalt abgeschickt. Was hat das mit den verwendeten Kommandos zu tun? > Ich behaupte sogar dass die > FT_Write erst zurück kehrt, wenn die Daten tatsächlich raus gegangen > sind. Du meinst auf dem JTAG raus gegangen? Das kann ich mir nicht vorstellen. Damit würde mann u.U. ja Geschwindigkeit verschenken. > Alternativ könntest du natürlich auch ein Schreib/Lese Kommando nehmen, > dann kehrt er 100% erst zurück, sobald die Daten durch geschoben sind... Das dürfte den ganzen Vorgang aber auch deutlich bremsen.
Hier mal ein Code-Auszug:
1 | #define TR_BUFFER_SIZE 4096
|
2 | |
3 | void FtJtagIO::writeBuffer(int numBytes, uint8_t *data) |
4 | {
|
5 | uint8_t *dPtr = data; |
6 | while(numBytes) |
7 | {
|
8 | if(trSize < TR_BUFFER_SIZE) |
9 | {
|
10 | trBuffer[trSize++] = dPtr ? *(dPtr++) : 0xff; |
11 | numBytes--; |
12 | }
|
13 | else
|
14 | {
|
15 | flushBuffer(); |
16 | }
|
17 | }
|
18 | }
|
19 | |
20 | void FtJtagIO::writeBuffer(uint8_t data) |
21 | {
|
22 | writeBuffer(1, &data); |
23 | }
|
24 | |
25 | void FtJtagIO::flushBuffer() |
26 | {
|
27 | if(trSize == 0) |
28 | return; |
29 | |
30 | ftStatus = FT_Write(ftHandle, trBuffer, trSize, (DWORD*)&trDoneSize); |
31 | Sleep(1); |
32 | |
33 | if(ftStatus != FT_OK || trDoneSize != trSize) |
34 | {
|
35 | throw std::runtime_error("FT_Write() failed"); |
36 | }
|
37 | trSize = 0; |
38 | }
|
39 | |
40 | void FtJtagIO::shiftTdiData(uint32_t numBits, uint8_t *tdiData, |
41 | bool readTdo) |
42 | {
|
43 | int numBytes = (numBits-1) >> 3; |
44 | int numBitsRes = (numBits-1) & 0x7; |
45 | char cmdRdMask = readTdo ? 0x20 : 0; |
46 | uint8_t *dPtr = tdiData; |
47 | |
48 | ...
|
49 | |
50 | // Write complete bytes
|
51 | if(numBytes) |
52 | {
|
53 | writeBuffer(CMD_DATABYTES2TDI | cmdRdMask); |
54 | writeBuffer((numBytes-1) & 0xFF); |
55 | writeBuffer(((numBytes-1) >> 8 ) & 0xFF); |
56 | writeBuffer(numBytes, dPtr); |
57 | dPtr += numBytes; |
58 | }
|
59 | |
60 | // Write residual bits
|
61 | if(numBitsRes) |
62 | {
|
63 | writeBuffer(CMD_DATABITS2TDI | cmdRdMask); |
64 | writeBuffer((numBitsRes-1) & 0xFF); |
65 | writeBuffer(dPtr); |
66 | }
|
67 | }
|
Mit Kommandos meinte ich z.B. CMD_DATABYTES2TDI. Somit hat dein Buffer (der der wirklich im flushBuffer() gesendet wird) immer mehr als 4096 Bytes. Du schickst das Zeug aber schon sobald Gesamt > 4096 ist und das ist der Bock, weil dir immer einige Daten fehlen. Schau mal in die shiftTdiData() Methode und dann siehst du sofort, dass immer 3 Bytes pro Aufruf dazu kommen. Den Wert CMD_DATABYTES2TDI kannst du in der MPSSE Doku mal nachschlagen und dann siehst du schon was ich meine... Ich würde die Daten extern auf 4096Byte Päckchen umbauen und dann in einem Rutsch absenden, dann ist die Performance bestimmt am besten. Alterntaiv könnte auch ein Umbau was bringen, in etwa so (ungetetstet): EDIT: trBuffer muss natürlich groß genug sein!
1 | #define TR_BUFFER_SIZE 4096
|
2 | |
3 | void FtJtagIO::writeBuffer(int numBytes, uint8_t *data) |
4 | {
|
5 | uint8_t *dPtr = data; |
6 | while(numBytes) |
7 | {
|
8 | trBuffer[trSize++] = dPtr ? *(dPtr++) : 0xff; |
9 | numBytes--; |
10 | }
|
11 | }
|
12 | |
13 | void FtJtagIO::writeBuffer(uint8_t data) |
14 | {
|
15 | writeBuffer(1, &data); |
16 | }
|
17 | |
18 | void FtJtagIO::flushBuffer() |
19 | {
|
20 | if(trSize == 0) |
21 | return; |
22 | |
23 | ftStatus = FT_Write(ftHandle, trBuffer, trSize, (DWORD*)&trDoneSize); |
24 | |
25 | if(ftStatus != FT_OK || trDoneSize != trSize) |
26 | {
|
27 | throw std::runtime_error("FT_Write() failed"); |
28 | }
|
29 | trSize = 0; |
30 | }
|
31 | |
32 | void FtJtagIO::shiftTdiData(uint32_t numBits, uint8_t *tdiData, |
33 | bool readTdo) |
34 | {
|
35 | int numBytes = (numBits-1) >> 3; |
36 | int numBitsRes = (numBits-1) & 0x7; |
37 | char cmdRdMask = readTdo ? 0x20 : 0; |
38 | uint8_t *dPtr = tdiData; |
39 | |
40 | ...
|
41 | |
42 | // Write complete bytes
|
43 | if(numBytes) |
44 | {
|
45 | writeBuffer(CMD_DATABYTES2TDI | cmdRdMask); |
46 | writeBuffer((numBytes-1) & 0xFF); |
47 | writeBuffer(((numBytes-1) >> 8 ) & 0xFF); |
48 | writeBuffer(numBytes, dPtr); |
49 | dPtr += numBytes; |
50 | }
|
51 | |
52 | // Write residual bits
|
53 | if(numBitsRes) |
54 | {
|
55 | writeBuffer(CMD_DATABITS2TDI | cmdRdMask); |
56 | writeBuffer((numBitsRes-1) & 0xFF); |
57 | writeBuffer(dPtr); |
58 | }
|
59 | if(trSize > TR_BUFFER_SIZE) |
60 | {
|
61 | flushBuffer(); |
62 | }
|
63 | }
|
:
Bearbeitet durch User
Ich hab das Gefühl wir reden aneinander vorbei :-) Günter R. schrieb: > Mit Kommandos meinte ich z.B. CMD_DATABYTES2TDI. Somit hat dein Buffer > (der der wirklich im flushBuffer() gesendet wird) immer mehr als 4096 > Bytes. Du schickst das Zeug aber schon sobald Gesamt > 4096 ist und das > ist der Bock, weil dir immer einige Daten fehlen. > Schau mal in die shiftTdiData() Methode und dann siehst du sofort, dass > immer 3 Bytes pro Aufruf dazu kommen. Den Wert CMD_DATABYTES2TDI kannst > du in der MPSSE Doku mal nachschlagen und dann siehst du schon was ich > meine... Dass da Kommandos hinzugefügt werden, ist mir schon klar. Aber aus Sicht der writeBuffer()-Methode ist das doch völlig egal. Die bekommt einen beliebig großen anonymen Datenblock übergeben und kopiert diesen byteweise in den 4K-Transmit puffer. Immer wenn dieser voll ist, wird ein flush aufgerufen, der den puffer leert. Anschließend wird er wieder befüllt usw. Das geht so lange, bis alle Daten kopiert sind. Was in meinem codeschnipsel nicht zu sehen ist - sollte der Gesamttransfer (Daten+Kommandos) nicht 4K aligned sein, werden die am Ende verbleibenden Daten (plus die nachfolgenden TMS-shift Kommandos) beim nächsten RUNTEST-Kommando abgeschickt. Wo da jetzt Daten fehlen sollen, sehe ich nicht. Wenn das so wäre, dürfte das Ganze ja, unabhängig vom Sleep(), gar nicht funktionieren.
Kann schon sein, dass es aneinander vorbei geht gg ABER ich sehe das nicht so. Nehmen wir deinen Code und spielen mal durch. Buffer hat 4090 Bytes. Nun schiebst du zB nochmal 8Byte nach. Der Buffer kriegt 1 Byte Kommand, 2 Byte Länge und 8 Byte Daten, doch nach dem 3. Byte wird die FT_Write aufgerufen und die Daten geschickt (ich denke auch auf der HW) Jetzt sind noch 5 Byte übrig die wieder in den Buffer kommen und ob der Treiber jetzt noch weiß, dass es Daten aus dem Kommando von vorhin sind, wage ich zu bezweifeln. Irgendwo her müssen ja deine Probleme kommen und das wääre für mich eine Erklärung. Bei meiner JTAG Lib hab ich das alles immer intern vorbereitet und erst danach sauber an die FT Lib übergeben und das hat dann auch geklappt. Ich behaupte wenn du die Daten selber bufferst bis du 4k beisammen hast und in einem Rutsch übergibst, rennt die Geschichte. So viel Aufwand ist das sicher nicht... Also dann,
Ok, jetzt habe ich zumindest verstanden was Du mir sagen willst :-) ABER ich sehe das wiederum anders. Der Treiber weiß doch überhaupt nichts von irgendwelchen Kommandos, oder sollte es zumindest nicht. Seine Aufgabe sollte sein, transparente Daten über USB zum/vom Chip zu transportieren und dafür zu sorgen, dass alles ankommt. Die Interpretation der Daten ist Sache der MPSSE. Und ich baue doch eine Abstraktionsschicht wie obige Klasse FtJagIO doch gerade deshalb, damit ich mich als Anwender eben nicht um irgendwelche Buffergrößen etc. kümmern muss. Ich will gar nicht generell ausschließen, dass Dein Vorschlag Erfolg haben mag und werde es auch bei Gelegenheit mal ausprobieren. Aber ich bin der Meinung, dass wenn Du Recht hast dieses Verhalten ein schlechtes Design, wenn nicht gar einen Bug auf Seiten der FTDI-Entwickler darstellen würde. Und vor allem sollte es dann irgendwo dokumentiert sein. Man findet übrigens eine solche Sleep-Anweisung auch im Beispielcode einer Application-Note von FTDI, ohne dass sie näher erläutert wäre. Letztlich wäre es auch noch möglich, dass es sich einfach um einen Hardware-Bug handelt, da das Problem mit einem anderen Design (anderes FPGA) nicht auftritt. Leider habe ich momentan keine Möglichkeit ein anderes Exemplar der gleichen Hardware zu prüfen. Gruß
Ist Ansichtssache. Meines Erachtens kann es bei deinem Aufbau sein, dass du unvollständige Befehle schickst und ob das richtig gehandhabt wird ist fraglich. Ich denke dann mal wohl eher nicht. Du hast aber mit wenigen "Handgriffen" die Möglichkeit deine FtJagIO umzubauen, indem du nur die Daten speicherst bis du wirklich 4096Bytes hast und dann machst du einen neuen Buffer inkl. Kommando und Länge und schickst das per FT_Write. Beim externen Aufruf von FlushBuffer müsstest du es natürlich ein wenig anders handhaben, aber Hexerei ist das sicher keine. Naja, ich glaub ich hab alles gesagt was mir dazu einfällt ;-) So denn, PS: Viele App Notes und auch viele Tools von FTDI sind einfach nur Schrott und man könnte verzweifeln. FT_PROG zB hab ich noch nie fehlerfrei erlebt...
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.