FT232HL FTDI Verzögerungsproblem bei aufeinanderfolgenden SPI-Bytes

Ich habe ein Problem mit dem FT232HL FTDI ic.

Die Windows-Anwendung sendet Daten über USB an den Chip und der Chip sendet die Daten mit einem SPI-Kanal.

Ich habe mit einem Logikanalysator überprüft, die Bytes werden korrekt gesendet und die SPI-Uhr stimmt mit den Einstellungen überein. Zwischen jedem Byte gibt es jedoch eine Verzögerung von 64 uS, was bedeutet, dass die Datenübertragung, egal wie hoch der SPI-Takt ist, Minuten statt Sekunden dauert.

Ich stellte mir vor, dass es vielleicht helfen würde, mit dem channelConf.LatencyTimer zu spielen, aber es zeigt keinen Unterschied, egal welcher Wert verwendet wird (10, 128, 255), die Verzögerung bleibt 64 uS zwischen aufeinanderfolgenden Bytes.

Es muss etwas zu beheben geben, denn es gibt zahlreiche Beispiele dafür, dass Menschen hohe Übertragungsraten erreichen. Außerdem sollte die Verzögerung zwischen Bytes irgendwo eine Einstellung sein.

Ich habe den mit sample-dynamic.c bereitgestellten Beispielcode verwendet. Der Bytestrom wird mit einem einzigen Aufruf von p_SPI_Write() mit einer Gesamtlänge von 2048 Bytes gesendet. Ich habe andere Längen (256, 8192 usw.) ausprobiert, keine Änderung. Hier ist die verwendete Konfiguration:

channelConf.ClockRate = 5000*1000; 
channelConf.LatencyTimer= 10; 
channelConf.configOptions = SPI_CONFIG_OPTION_MODE0| SPI_CONFIG_OPTION_CS_DBUS3/*|*/ ;
channelConf.Pin = 0x00000000; /* FinalVal-FinalDir-InitVal-InitDir (for dir: 0=in, 1=out) */

Betriebssystem: Windows7 X64 Compiler: GCC-Bibliothek und Code von: http://www.ftdichip.com/Support/SoftwareExamples/MPSSE/LibMPSSE-SPI.htm

FYI: Ich habe den FTDI-Support kontaktiert, sie haben mich gebeten, die Bibliotheken auf die neueste zu aktualisieren (was ich getan habe), dann würden sie keinen weiteren Support leisten.

Jede Hilfe geschätzt. Danke schön.

Wie liefern Sie die Daten an die Fahrer? In welcher Stückgröße? USB-Peripheriegeräte können schleichend langsam werden, wenn sie nur ein oder wenige Bytes pro Frame verschieben. In den frühen Tagen, bevor die Leute die Probleme verstanden, konnte das Hinzufügen eines USB-Seriell-Konverters zu etwas, das an einem seriellen Port eines lokalen Busses gut funktionierte, seine Benutzerfreundlichkeit vollständig beeinträchtigen. Das wird jetzt oft verstanden, aber SPI kann die Koordination mit anderen Signalen wie Selects beinhalten, so dass man sich leicht vorstellen kann, durch Bus-Framing behindert zu werden und nicht in der Lage zu sein, die theoretische Datenrate zu nutzen, die für größere Übertragungen gelten würde.
Hallo. Wie in der Nachricht angegeben, ist die Verzögerung gleich, egal wie viele Bytes gleichzeitig gesendet werden. Normalerweise sende ich 2048 Bytes pro Aufruf von p_SPI_Write(). Außerdem verwende ich den Master-SPI-Modus, nur Schreiben, es sollte kein Handshaking geben. Danke schön.
Sind Sie sicher, dass die USB-Seite Daten schnell genug sendet? Warum schauen Sie nur auf die SPI-Seite Ihrer Brücke?
Ich habe keine Ahnung, wie schnell der USB die Daten überträgt. Ich überprüfe die SPI-Seite, weil das das Ende der Zeile ist und ich es leicht mit dem Logikanalysator überprüfen kann. Ich sehe sowieso nicht, wie die USB-Übertragung langsamer als 16KByte/s sein könnte. Ich habe von FTDI-Leuten gehört, sie schlagen vor, dass ich ihre Bibliothek nicht benutze (aber sie haben nicht klar gesagt, dass ihre Bibliothek verwanzt ist). Ich bin immer noch überrascht, dass einige Leute hohe Übertragungsgeschwindigkeiten erreichen können, wenn sie die mitgelieferte Bibliothek verwenden. Wird für einen einfachen USB<>SPI-Übertragungsjob zu kompliziert.
Ich bin in der gleichen Situation. Das SPI_ToggleCS() ist aufgrund des Ruhezustands definitiv langsam, aber nachdem es auf nur Ft_Write-Aufrufe umgestaltet wurde, gibt es immer noch eine lange Verzögerung zwischen der Anzeige auf dem Logikanalysator zwischen dem Cs-Pin, der auf niedrig geht, um + Daten von etwa 100 us in meinem Fall. Sehr genervt und frustriert!
Ich habe FTDI kontaktiert und hatte etwas Unterstützung. Nachdem ich die Logik mit den FT_Write () -Funktionen auf niedrigerer Ebene geschrieben hatte, sah ich immer noch eine Verzögerung von> 60 us von CS Low bis zur Datenübertragung. Ich hatte mich gefragt und sie bestätigten, dass das Problem mit den USB-Datenübertragungsrahmen zu tun hat. Sie müssen die Nachrichten über den USB-Bus in denselben Datenrahmen packen, um die erforderliche USB-Bandbreite zu erhalten, dh einen einzelnen Puffer erstellen, um Ihre CS-Befehle und die Datenpuffer zu speichern, und dann FT_Write zum Senden verwenden. Wenn Sie genug über USB wissen, können Sie sicherstellen, dass Sie jeden Datenrahmen maximieren, um die volle Bandbreite zu erhalten.

Antworten (4)

Normalerweise arbeite ich mit dem FT2232H-Chip, aber ich habe einen FT232HQ-Chip ausgegraben, nur um dieses Problem zu überprüfen, das Sie hatten. Es ist derselbe Chip wie der FT232HL-Chip, den Sie haben, nur in einem QFN-Gehäuse anstelle eines QFP.

Ich habe versucht, das von Ihnen beschriebene Problem nachzustellen, aber ich konnte es nicht genau. So sah es auf meinem Logikanalysator aus, wenn ich bei einer Taktrate von 5 MHz 6 Bytes auf einmal ausgab. Es gibt eine kleine Verzögerung zwischen Bytes, aber bei weitem nicht so groß wie 64 us.

Beispiel 5 MHz Multibyte-Übertragung

Hier sind einige Dinge zu überprüfen.

  • Der Latenztimer sollte wirklich keine Rolle spielen, da dies einfach ein Timeout ist, bevor USB ein unvollständiges Paket sendet. Ich habe es auf 255 eingestellt, aber oft für Timing-empfindliche Sachen habe ich es niedriger (2 -10)
  • Versuchen Sie zuerst eine langsamere Taktrate, nur um zu testen und sicherzustellen, dass das Gerät korrekt kommuniziert (ich nehme an, Sie haben es getan, ich füge dies nur hinzu, falls jemand anderes das noch nicht versucht hat).
  • Die Pin-Richtungen spielen keine Rolle, außer für GPIO, da sie von der SPI-Bibliothek überschrieben werden.
  • p_SPI_Write()Verwenden Sie statt SPI_Write(). Wenn Sie einen einzelnen Anruf tätigen, fügen Sie die entsprechenden Chip-Select-Enable- und -Disable-Flags hinzu (siehe unten). Wenn Sie mehrere Anrufe tätigen, stellen Sie sicher, dass Sie die Chipauswahl-Flags zum ersten und letzten Anruf in der Reihe hinzufügen.
  • Stellen Sie sicher, dass Sie die Anzahl der zu übertragenden Bytes übergeben, und setzen Sie das SPI_TRANSFER_OPTIONS_SIZE_IN_BYTESFlag.
  • Wenn es sich um ein benutzerdefiniertes Platinendesign handelt oder Sie eine reduzierte FT232H-Adapterplatine gekauft haben, stellen Sie sicher, dass sie die richtige Systemtaktfrequenz hat. Diese Verzögerung zwischen Bytes basiert darauf, wie lange der Chip braucht, um das nächste Byte von seinem internen Puffer zu den Ausgangsschieberegistern zu verschieben. Wenn der Chip langsam getaktet wird, zeigt sich dies bei den höheren Frequenzen als eine größere Lücke zwischen den Bytes. Beachten Sie, dass es für SPI keine Rolle spielt, ob der Takt hier und da ein wenig gestreckt wird, da er auf den Flanken des Taktsignals basiert (auf einer Flanke lesen, auf der anderen ausbreiten). Prüfen Sie den Kristall- oder CMOS-Kristallchip und stellen Sie sicher, dass er 12 MHz erhält.

Hier ist ein kurzer Beispielcode zum Senden mehrerer Datenbytes, falls es hilft.

uint32 sizeToTransfer = 0;
uint32 sizeTransfered = -1;
uint8 buffer[256]; //Must be large enough for what you are sending.
FT_STATUS status;

//add data
buffer[sizeToTransfer++] = 0x20; //First data byte (can be what you need)
/*
 * More bytes added....
 */
buffer[sizeToTransfer++] = 0x00; //Last data byte (can be what you need)

status = SPI_Write(*handle, buffer, sizeToTransfer, &sizeTransfered,
    SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES |
    SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE |
    SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);

//Don't forget to check status. It should equal FT_OK if everything went well

Disclaimer: Ich verwende den FT2232H und bin mir nicht 100% sicher, ob alle Aussagen auf diesen Fall übertragbar sind.

Meines Wissens nach ist ftdi mpsse spi nicht wirklich für hohen Datendurchsatz optimiert. Dies wird deutlich, wenn man sich die Quelle genauer ansieht. In der aktuellen Version (ausgecheckt am 24.04.2019) gibt es einen INFRA_SLEEP(2)-Aufruf innerhalb der SPI_ToggleCS-Funktion, der bei jeder Änderung des Zustands der CS-Leitung zu einer Verzögerung von 2 ms führt. Wenn Sie also CS für jedes einzelne Wort pulsieren müssen, sind Sie dem Untergang geweiht. Selbst ohne den Schlafanruf wird die USB-Latenz die Dinge höchstwahrscheinlich stark verlangsamen. Auch ohne diesen Aufruf bleibt der maximale Durchsatz bei meinen Tests hinter den Erwartungen zurück. Ich vermute, dass der Grund dafür in der Architektur von mpsse selbst liegt. Daher würde ich persönlich empfehlen, wenn möglich bei den nativ unterstützten Protokollen wie UART, Fast Opto oder FIFO für Anwendungen mit hohem Durchsatz zu bleiben.

Aus Neugier (falls dieser Fall noch offen ist): Haben Sie auch nach verschiedenen Treibern gesucht? Können Sie dasselbe Verhalten auch bei einem anderen PC beobachten?

Hinter jedem libMPSSE-Aufruf steht ein Aufruf von FT_Write(), das tatsächlich einen Datenrahmen auf Hochgeschwindigkeits-USB schreibt. Bei der Verwendung der Bibliotheksfunktionen sind Sie daher durch die USB-Kommunikationsschicht eingeschränkt (wie vom FTDI-Support gemeldet).

Die Lösung, um die volle Geschwindigkeit zu erreichen, besteht darin, auf eine niedrigere Ebene zu gehen und Ihre Befehle zusammen in einem großen FT_Write() zu puffern, sodass die Daten in einen USB-Übertragungsrahmen gepackt werden:

{
Add to buffer: GPIO Write for CS lo
Add to buffer: Clock N bytes command
Add to buffer: N bytes of data
Add to buffer: GPIO write for CS hi
Add to buffer: Send immediate command (0x87) – only if you read bytes from the LTC device, not if you only write them
++ Repeat for other commands as much as possible for your use-case …
}
FT_Write of the above buffer

Nur um Sie wissen zu lassen, dass die FT232HL FTDI-Treiber meines Erachtens fehlerhaft sind, da die Fehler je nach verwendetem USB-Hub/Marke verschwinden/auftauchen, wie lang das USB-Kabel ist und wie der Computer "vorbereitet" ist. Am Ende kaufte ich einen bestimmten Computer und blieb für die Massenproduktion dabei.

Einige Helfer:

  1. AufrufzeitBeginPeriod(4); Vor dem Laden von FTDI-Treibern hilft es sehr, Sie müssen nur danach überprüfen, ob der Zeitraum festgelegt wurde, da Windows den Zeitraum manchmal nicht aktualisiert (aus welchem ​​Grund auch immer). Sehen Sie sich den folgenden Code an, um zu überprüfen, ob timeBeginPeriod(4) funktioniert hat.

    t1d=Uhr(); BITBANG_usleep(5*1000);//5ms t2d=clock(); tspent=(((float)t2d-(float)t1d) / (CLOCKS_PER_SEC/1000)); if((int)tspent > 8){ fehlgeschlagen, beenden oder erneut versuchen! }

    void BITBANG_usleep (unsigned int usdelay) { clock_t t1,t2; Wenn (usdelay <16 * 1000) // 16 ms {t1 = Uhr (); während (1) {t2 = Uhr (); if(((t2-t1)/ (CLOCKS_PER_SEC/(1000)))>usdelay/1000){break;}}} else {usleep(usdelay);} }

  2. Verwenden Sie ein kurzes Kabel und eventuell einen USB-HUB im Weg, verbessert die Stabilität erheblich und kann hunderte von Stunden ohne Probleme direkt arbeiten.

Hoffe das hilft, es ist nicht die beste Lösung, aber es hat für mich funktioniert!