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.
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.
Hier sind einige Dinge zu überprüfen.
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.SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES
Flag.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:
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);} }
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!
Chris Stratton
gadd29
Ale..chenski
gadd29
Krog
Krog