Forum: PC-Programmierung Cypress FX2 libusb


von JE (Gast)


Lesenswert?

Hallo,

bin auch gearde mit dem Slave FIFO Interface des FX2 beschäftigt. Leider 
komme ich momentan nur auf eine Datenrate von 4MB/s.

Ich steure es mit einem Zustandsautomaten aus einem FPGA an. FULL flag 
berücksichtige ich usw.

Nun takte ich die FSM einmal mit 12.5 MHz und einmal 25MHz. Beide Male 
sind die Datenraten gleich.

Der Falschenhals liegt also bei Software mit der ich die Daten auslese.

Seitens des FX2 verwende ich Bulk-Übertragung, 4x buffered, Auto IN, ext 
clocked.

Ich verwende libusb, synchron. Dort hohle ich in einer Schleife mit 
usb_bulk_read() Datenblöcke mit je 1024Bytes ab.

Im Thread stand, dass man größere Datenblöcke anfordern soll, dann wird 
die Übertragung schneller.

Warum das?

von Christian R. (supachris)


Lesenswert?

1024Byte pro Transfer ist zu wenig. Da kommst du nur auf so niedrige 
Raten. Wir erreichen die 40MB/s knapp, wenn wir richtig große Blöcke 
abholen....128kiByte beispielsweise.

Achso, die Rechung: Bei 1024 Byte pro Transfer ist ein Microframe nur 
mit 1024 Byte gefüllt. Bei USB 2.0 HighSpeed wird alle 125µs ein 
Microframe generiert. Ist der nur mit 1024 Byte gefüllt, kommst du auf 
ziemlich genau 8MB/s maximal.

von JE (Gast)


Lesenswert?

Christian R. schrieb:
> 1024Byte pro Transfer ist zu wenig. Da kommst du nur auf so niedrige
>
> Raten. Wir erreichen die 40MB/s knapp, wenn wir richtig große Blöcke
>
> abholen....128kiByte beispielsweise.
>

Aha..

>
>
> Achso, die Rechung: Bei 1024 Byte pro Transfer ist ein Microframe nur
>
> mit 1024 Byte gefüllt. Bei USB 2.0 HighSpeed wird alle 125µs ein
>
> Microframe generiert. Ist der nur mit 1024 Byte gefüllt, kommst du auf
>
> ziemlich genau 8MB/s maximal.

Ok.., und das unter der Vorraussetzung, dass alle 125us usb_bulk_read() 
ausgeführt wird. Denn der Host ist ja der "master".
Wenn die externe Logik in der Lage ist 6656 Bytes alle 125us (pro 
Microframe) zu liefern, kommt mal also auf eine Datenrate von ca 
50MB/s..

Vorrausgesetzt, dass usb_bulk_read() alle 125us aufgerufen werden kann, 
reicht dann doch also, immer 6656 Bytes mit dieser Funktion anzufordern?

Wenn es nun aber nicht nicht möglich ist, alle 125 us die Funktion 
aufzurufen, muss man größere Blöcke anfordern, sodass mehrere Microframe 
aufeinander folgend empfangen werden.

Also wäre es grundsätzliche ratsam größere Blöcke anzufordern, wie bei 
euch 128kByte.

Dann muss die externe Logik allerdings auch schnell genug nachliefern, 
sonst gibt es einen timeout.

Gibt es da nicht auch eine obere Grenze bei libusb bezüglich der 
Einlesemenge?

von Christian R. (supachris)


Lesenswert?

Also die 125µs sind fest. Und darum kümmert sich der Hostcontroller. Das 
API sollte die Blöcke so groß wie möglich abfragen. Außerdem sind bei 
HighSpeed die Pakete maximal 512 Byte groß. Pro MicroFrame passen 10 bis 
11 512 Byte rein. Man kommt also nur auf etwa 40MB/s. Musst du das 
TimeOut entsprechend hochsetzen. Wir lesen immer so riesen Brocken. Die 
Hardware setzt das Packetend an der entsprechenden Stelle, dann kommt 
der Treiber zurück, auch wenn die Anzahl noch nicht erreicht ist. Und da 
wir im Voraus exakt wissen, wieviel Daten anliegen, klappt das.

von JE (Gast)


Lesenswert?

Ok, danke für den Tipp! Sehr gut..Bin jetzt bei meinen erwarteten 
15-16Byte/s. Meine FPGA Logik kann theoretisch auch nur 16,66MByte/s 
Daten produzieren. Soweit so gut.

Zum PKTEND: Lasse den FX2 mit AUTOIN=1 laufen. Mit meiner FPGA Logik 
frage ich das Full Flag ab, sodass wenn das FULL-Flag high ist, keine 
Daten in das Slave FIFO geschrieben werden. In der Simulation 
funktioniert der Mechanismus. Ob das FULL Flag aber überhaupt mal high 
wird, habe ich noch gar nicht geprüft. - Die Daten, die ich empfange 
sind jedenfalls korrekt, ganz ohne PKTEND. Naja habe ja auch einen 
kontinuierliche Datenstrom. Der PKTEND Pin ist ja nur für Anwendungen 
gedacht, wenn keine Daten mehr von der externen Logik mehr generiert 
werden und der FIFO-Füllstand des Autoin noch nicht erreicht ist.

von Christian R. (supachris)


Lesenswert?

Naja, wenn der Rechner mal zu tun hat, wirst du schon merken, wie 
wichtig das Full Flag ist. Das PacketEnd ist schon sehr nützlich, eben 
weil man dann fast beliebig große Transfers machen kann, die keine 
ganzzahligen Vielfachen von 512 Byte sind. Und weil man damit einen noch 
größeren Datenstrom segmentieren kann. Wir nutzen das wie gesagt 
intensiv.

von Tilo (Gast)


Lesenswert?

Hallo

Ich habe gerade auch mit dem Chip zu tun.

Wie sind eure Erfharungen, in wie weit wirkt sich die MaxPacketSize auf 
die Transferrate aus? Bei kelienren Paketen wird der prozentuale Anteil 
des Overheads größer. Kommt sonst noch etwas dazu?

Viele Grüße, Tilo

von JE (Gast)


Lesenswert?

Tilo schrieb:
> Wie sind eure Erfharungen, in wie weit wirkt sich die MaxPacketSize auf
>
> die Transferrate aus? Bei kelienren Paketen wird der prozentuale Anteil
>
> des Overheads größer. Kommt sonst noch etwas dazu?

Naja, es gilt ja die Microframes möglichst voll zu bekommen. Es passen 
ja zehn bis elf Pakete je 512 Bytes(maximal) in einen Microframe(bei 
bulk Transfer). Wenn die Pakete nicht voll werden, schafft man eben 
nicht die volle Bandbreite. Die Anzahl der Pakete ist glaube ich fix.


Wie schnell taktet Ihr den FX2? Und taktet ihr ihn extern oder intern?

von Christian R. (supachris)


Lesenswert?

Genau, je länger die Paketgröße, desto mehr Übertragungsrate.
Wir takten mit 40MHz extern, 16 Bit Datenbus.

von Tilo (Gast)


Lesenswert?

Guten morgen

Leider intern, weil es das Design so vorgibt. Ich bin gerade dabei von 
Iso auf Bulk umzustellen. Das Problem ist, dass das Datenvolumen nicht 
fix ist und man den Iso. Transfer auf Worst case auslegen muss. Mit dem 
CyUSB Treiber scheint dies den PC dann ordentlich zu beschäftigen.

Da von libusb die rede ist, verwendet ihr Linux oder Windows?

von Christian R. (supachris)


Lesenswert?

Also wir nutzen den CyUSB Treiber unter Windows und arbeiten ohne das 
beknackte API direkt auf den IOCONTROLS. Das API kann parallele 
asynchrone Transfers nicht korrekt handhaben. Die sind aber nötig, um 
konstant die volle Datenrate auszuschöpfen. Eine sonderlich hohe 
Prozessorlast gibts dabei aber nicht (<3% bei 40MB/s auf einen C2D mit 
3GHz). Auch da schlagen die möglichst großen Blöcke wieder rein. Je 
weniger Anfragen gestellt werden müssen, desto weniger Prozessorlast. 
Wenn man ständig kleine Pakete abholt, steigt die Last rapide an.

von Tilo (Gast)


Lesenswert?

Hallo

Welche Probleme habt ihr mit der API bei asynchronen Transfers genau? Im 
Cypress Forum gibts leider kaum etwas :(

von Christian R. (supachris)


Lesenswert?

Kann ich dir nicht genau sagen. Ich bin der Hardware-Entwicker. Der 
zuständige SW-Entwickler hat nach 2 Tagen das Handtuch geworfen und den 
Treiber direkt angesprochen. Das geht super.

von Tilo (Gast)


Lesenswert?

Mist, ich bin auch "nur" der Hardwareentwickler.

Bei uns die CyAPI eigentlich recht gut. Problematisch war allerdings 
bisher, dass es gerne zu PacketLoss kommt.

von JE (Gast)


Lesenswert?

Momentan arbeite ich auch mit den synchronen Interface von libusb. Die 
Datenrate, die ich zur Zeit habe, reicht mir zunächst. Allerdings möchte 
ich schon noch das asynchrone Interface als Alternative habe.

Ja, ich habe schon einen Versuch gemacht. Leider hat es nicht geklappt. 
Bis zu dieser ..reap..() Funktion läuft alles super, doch bei dieser 
Funktion bekomme ich -5 zurück. "Can't find entity" bedeutet das glaube 
ich. Habe auch schon im Forum nachgefragt, aber da konnte mir auch 
keiner helfen. Falls du weiter bist, kannst du das hier gerne zum Besten 
geben:)

von Christian R. (supachris)


Lesenswert?

PacketLoss haben wir nicht, aber wir haben noch ein kleines Problem bei 
extreme Datenraten. Wenn wir zusätzlich zum massiven upstream noch 
einiges an Downstream erzeugen, verhaspelt sich der Chip und/oder der 
Treiber. Das haben wir noch nicht gänzlich klären können. An der 
Firmware scheints nicht zu liegen, das tritt erst bei vielen parallelen 
asynchronen Anfragen an den Treiber auf. Wenn wir mal Zeit haben, 
stellen wir das mal auf den WinUSB aus dem KMDF um, und schauen, wie das 
dann aussieht.

von Tilo (Gast)


Lesenswert?

Welche Chiprevision verwendet ihr? Ich hab in einem Errate was gelesen, 
dass Daten zerwürfelt, wenn mehrere OUT-Endpoints verwendet werden.

Ihr habt mir mit der CyAPI Angst gemacht. Wir haben nur in eine Richtung 
etwas größere Datenmengen, glück gehabt.

Beim Testen ist mir etwas anderes aufgefallen:
An manchen PCs renumeriert sich der FX2 nach upload der Firmware nicht 
richtig. Dies kann daran erkannt werden, dass in CyConsole zwar das 
Gerät angezeigt wird, dem Gerät aber alle Endpoints fehlen. Drücke ich 
in CyConsole auf "Reset" tauchen die EPs auf.

Kommt einem von euch das Problem bekannt vor?

Was macht ihr in der Firmware zu erst: EPs konfigurieren oder 
Renumerierung? Hat einer schon mal versucht die EPs anderst zu 
konfigurieren, muss das Device dann reconnected werden?

Viele Grüße,

Tilo

von Christian R. (supachris)


Lesenswert?

Also wir haben nur einen OUT EP und einen IN EP. Die Firmware ist quasi 
die BulkLoop Beispiel Firmware, halt auf Slave FIFO umgeschaltet. Ich 
hatte hier auch mal eine ähnliche Firmware gepostet, die auf jeden Fall 
funktioniert, da sieht man auch die Reihenfolge. Einfach mal suchen.
Diese Renum Geschichten haben wir nicht. Wir halten die Firmware 
komplett im EEPROM und das Laden und enumerieren klappt immer 
zuverlässig. Mit synchronen Zugriffen funktioniert die CyAPI auch 
problemlos, nur mehrere parallele asynchrone Anfragen kann die schlecht 
handhaben. Wahrscheinlich der Treiber an sich auch, das müssen wir wie 
gesagt, bei viel Zeit mal herausfinden. Prinzipiell ist der WinUSB 
Treiber bzw. der hier Beitrag "Generischer USB Treiber für Windows mit C++ API" 
der auch WinUSB nutzt, eine gute Sache.

von Tilo (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

Die Beispiele habe ich soweit surch. Prinzipiell halte ich mich auch an 
die Beispiele. Leider passen die nicht immer.

Ich will z.B. folgendes:
EP2 soll OUT-EP mit 64Byte Bulk sein

EP6 soll:
Wenn HS-Mode: IN-EP mit Quad-512Byte Bulk
Wenn FS-Mode: IN-EP mit Quad-64Byte Bulk sein
Optional ist für Testzwecke nochmal beides als isochron drin.

EP6 wird von einem DSP gefüttert. Autocommit soll an sein, so dass der 
FX2 volle Pakete selbstständig wegschickt. Der DSP schickt immer 64Byte 
Blöcke. PF soll daher low werden, so bald 64Byte nicht mehr in die 
Puffer des FX2 passen, damit der DSP weiß, dass er warten muss.

Das verrückte ist, an vielen PCs tut alles einwandfrei aber an einzelnen 
PCs funktioniert das Device reproduzierbar nicht. Ich bin noch nicht 
dahinter gekommen, warum.

Fällt dir eventuell etwas auf?
Im ersten Codeteil passe ich die Descriptortable dynamisch an. Diese 
beginnt bei 0x0500. Danach will ich die EPs für den DSP einstellen.

Verwendest du auch Autocommit? Kann es sein, dass ein Paket, das 
commitet wurde aber noch nicht vom Host abgeholt wurde nicht mehr mit 
INPKTEND gelöscht werden kann?

Vielen Dank,

Tilo

von Tilo (Gast)


Lesenswert?

Ich hab das Problem gefunden.
Ich habe die USB Spec so verstanden, dass im FullSpeed Mode 8,16,32,64 
und im HighSpeed Mode dazu zusätzlich 512 Byte Pakete zugelassen sind. 
Tatsächlich sind es nut 512Byte im HS Mode. Die meisten USB-Hosts machen 
das mit aber nicht alle.

von JE (Gast)


Lesenswert?

Wenn ich das PROGLEVEL Flag des FX2 benutze, um zu sagen, dass das FIFO 
fast voll ist.

Muss ich dann auch zwangsweise den PKTEND Pin setzen, damit sich das 
FIFO wieder leert (Ich arbeite im AUTOIN Modus)? Oder leert es sich 
automatisch, da ich im AUTOIN Modus bin. Ich mache quad buffering. der 
letzte Buffer wird dann also nicht ganz voll. Die anderen Buffer werden 
aufgrund des AUTOIN Modus doch aber geleert, dass sich das FIFO 
automatisch leert, oder?

von Tilo (Gast)


Lesenswert?

Im AUTOIN-Mode werden volle Pakete automatisch commited.
Sagen wir, du hast einen Quad buffer. Die ersten drei Buffer sind voll, 
der 4. zur Hälfte. Wenn der PC nun Daten abholt, werden die drei vollen 
Puffer abgeholt und freigegeben, der 4. jedoch nicht, da er noch nicht 
voll ist. Werden nun weiterhin Daten in den FIFO geschoben, wird der 
angefangene Puffer voll gemacht und dann an den PC geschickt.
Mit dem PKTEND kann ein Paket abgeschickt werden, dass noch nicht voll 
ist.

Beispiel 1: Kontinuierlicher Messdatenfluss
PKTEND muss nie gezogen werden, da kontinuierlich Daten in den FIFO 
geschrieben werden und somit die Pakete immer voll werden. Die vollen 
Pakete werden voll automatisch vom PC abgeholt.

Beispiel 2: ACK auf ein Steuerkommando
PKTEND muss gezogen werden, da in den meisten Fällen nach dem ACK keine 
weiteren Daten in den FIFO geschrieben werden. Da das Paket nicht voll 
ist, würde das Paket ohne PKTEND nie an den PC geschickt. Durch das 
PKTEND wird alles was im FIFO ist an den PC geschickt.

Das Proglevel-Flag hat einen anderen Zweck. Ich verwende einen DSP mit 
DMA, um die Daten in den FIFO zu kopieren. die DMA kopiert immer 64Byte 
Blöcke in den FIFO. Mit dem Proglevel Flag kann ich sicherstellen, dass 
ein Block mit 64Bytes auch in den FIFO passt. Ohne das Flag musste jedes 
Byte einzeln in den FIFO kopiert werden und dann einzeln das FIFO-Full 
Flag ausgewertet werden. Das ganze ist ein Performance-Booster.


Ich hoffe ich habe alle Klarheiten beseitigt?

Viele Grüße,

von JE (Gast)


Lesenswert?

Sehr gut, soweit ist jetzt alles klar. Danke!

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
Noch kein Account? Hier anmelden.