Hallo Forum! Ich hänge zur Zeit an einer USB-Programmierung. Es müssen mindestens 250 kbps übertragen werden. Hostseitig polle ich aller 100 ms. Das heißt, pro USB-Paket müssen 3125 Byte übertragen werden. Ich hab zur Sicherheit 4 kB eingestellt. Problem dabei ist, das ich im USB-Controller zawr ein so großese char-Array anlegen kann, sobald ich dieses jedoch bearbeiten will funktioniert nichts mehr. Der Compiler (IAR) findet keine Fehler und das Programm wird auch auf den Controller geflasht - danach passiert aber nichts mehr. Ich hab im Debugger RunToMain eingestellt, dort kommt er aber nie an. Der Debug-Adapter ist die ganze Zeit im Run-Modus, IAR reagiert nicht mehr. Die maximal mögliche Größe des Puffers liegt bei 478 Byte - warum auch immer... Ich befürchte, dass ich irgendwelche Compilereinstellungen treffen muss, mit denen ich mich nicht auskeene. Kann mir da vielleicht jemand helfen? Vielen Dank mario
In 99% der Fälle sind Fehler, wie du sie beschreibst auf folgendes zurückzuführen: - Verwendung von initialisierten Variablen im XDATA-Bereich - Bedienen des defaultmäßig aktivierten Watchdogs erst ab der Main Das Initialisieren der Variablen erfolgt bevor MAIN angesprungen wird. Da der Watchdog aber nach einem PowerUp aktiv ist, schlägt er während der Initialisierung zu, deswegen kommst du nicht zur Main. Der IAR wird irgendeine STARTUP-Datei haben (so ist es zumindest bei Keil), in der du den zusätzlichen Assemblercode für das Deaktivieren des WD einstellen kannst. Somit passiert das vor der Initialisierung, und du erreichst dann auch die MAIN()-Routine :) Ralf PS: Warum legst du die Descriptoren nicht ebenfalls im Code-Speicher ab? Erstens verschwenden sie in deinem Fall nur XRAM, und zweitens werden sie normalerweise nicht geändert (was aber auch möglich ist, selbst wenn sie im Flash liegen).
PPPS: Dir ist übrigens sicherlich bewusst, dass der F32x nur 2kB RAM hat?
Hallo und danke erstmal. Die USB-API ist die von SiLabs (USBXpress). Der WatchDog ist deaktiviert - das wird in der sog. low_level_init gemacht. Die USB-Initialisierung hab ich 1:1 von Beispielen von SiLabs kopiert. Das mit den 2kB RAM ist mir auch bewusst, leider bin ich an diesen Controller gebunden - der war schon auf der Platine. Gibt es nicht vielleicht doch eine Möglichkeit des Paket am Stück abzuarbeiten? Wenn ich das Pollingintervall verkürze, kommt der Controller zu nichts anderem mehr, was sich äußerst ungünstig auf seine eigentliche Aufgabe auswirkt. VG mario
> Die USB-API ist die von SiLabs (USBXpress). Ah, okay. > Der WatchDog ist deaktiviert - das wird in der sog. low_level_init gemacht. Was ich nicht sehen konnte :) > Die USB-Initialisierung hab ich 1:1 von Beispielen von SiLabs kopiert. Oh, da wär ich vorsichtig... Die MCUs sind spitze, aber die Beispielsoftware ist bisweilen... optimierungswürdig. Die pfriemeln halt meistens auf die Schnelle zusammen, für ne Demo langt das meist, aber auf Performance etc. wird da kaum geachtet... > Das mit den 2kB RAM ist mir auch bewusst, ... Dann frag ich mich, warum du dich wunderst, dass deinem Buffer nur knapp 500Byte zugesprochen werden, v.a.dann, wenn du die Strings auch noch im XRAM ablegst, was die mögliche Maximalgröße des Puffers auch wiederum schmälert... Verwendest du wenigstens den vollen USB FIFO? > ...leider bin ich an diesen Controller gebunden - der war schon auf der > Platine. Das tut ja mal nix zur Sache, entweder er ist geeignet oder nicht - dass er schon auf der Platte ist, hilft nix :) > Gibt es nicht vielleicht doch eine Möglichkeit des Paket am Stück > abzuarbeiten? Wenn ich das Pollingintervall verkürze, kommt der > Controller zu nichts anderem mehr, was sich äußerst ungünstig auf seine > eigentliche Aufgabe auswirkt. Was wäre denn die "eigentliche" Aufgabe? Je mehr Informationen du gibst, desto besser kann dir geholfen werden :) Ralf
Der Controller empfängt per SPI aus einem IEEE802.15.4 Daten mit bis zu 250 kbps und soll diese an einen PC weiterreichen. Auf den USB-FIFO hab ich durch die USBXpress-Bibliothek keinen Zugriff. Die Bibl. ist compiliert - ich kann mir also auch nicht die Quellen anschauen. Die reine USB-Programmierung wollte ich mir eigentlich ersparen - das kostet zu viel Zeit. Meine eigentliche Aufgabe ist das 802.15.4-Netz. Ich hatte gehofft, dass man die Variablen auch in irgendeinem anderen Speicherbereich ablegen kann - das geht aber nur, mit Konstanten. Die Struktur beim 8051 ist mir zugegebenermaßen noch nicht wirklich klar. Ich dachte das wird so 'ne learning by doing Sache... . . wohl nicht. Tja... dann muss ich mir wohl was anderes einfallen lassen. Die Descriptoren werde ich gleich mal in den Code-Speicher legen, das wird aber sehr wahrscheinlich nicht genügen. Trotzdem Danke nochmal... hast mir sehr geholfen. mario PS: Warum kann man das Array ohne Probleme anlegen? Sollte da nicht eigentlich schon der Speicher reserviert werden? A: Der Compiler überspringt die Deklaration, weil das Array nie verwendet wird. PPS: Die USB_Init-Methode will die Descriptoren nur aus dem RAM.
Mario G. schrieb: > Ich hab zur Sicherheit > 4 kB eingestellt. Weil 4kB mit Sicherheit nicht in einen 1kB FIFO passen werden??? Du mußt schon das Datenblatt mal anfassen. > Die maximal mögliche Größe des Puffers liegt bei > 478 Byte - warum auch immer... Vermutlich sind die 1kB USB FIFO in je 512 fürs Senden und Empfangen aufgeteilt + einige Byte Headerkram. Peter
> Ich hatte gehofft, dass man die Variablen auch in irgendeinem anderen > Speicherbereich ablegen kann - das geht aber nur, mit Konstanten. Nein, das stimmt nicht. Du hast einmal den RAM vom 805x-Kern. Das sind bis zu 256 Byte (real mit Hardware- und reentrant-Stack und etc. etwa 100 Byte). Zusätzlich hast du bei deinem Controller 2kB RAM, sog.XRAM, da es sich im eXternen Speicher_bereich_ befindet. In beiden kannst du Variablen anlegen. In deinem Fall wird die Hälfte des verfügbaren XRAM für den USB-Hardware-FIFO verwendet. Die API kümmert sich um den Zugriff. > Die Struktur beim 8051 ist mir zugegebenermaßen noch nicht wirklich klar. > Ich dachte das wird so 'ne learning by doing Sache... . . wohl nicht. > Tja... dann muss ich mir wohl was anderes einfallen lassen. Was genau ist dir nicht klar an der Struktur? Bevor du sie nicht verstehst, wird dein Programm nicht effizient sein, also müssen wir dafür sorgen, dass du den Käfer verstehst :) > Die Descriptoren werde ich gleich mal in den Code-Speicher legen, das wird > aber sehr wahrscheinlich nicht genügen. Aber es wird dir trotzdem schon mal ein paar Byte bringen. Du könntest zusätzlich auch mal das komplette Projekt in ein ZIP packen und hier anhängen, dann kann man sich das mal angucken, und Verbesserungen vornehmen. > PS: Warum kann man das Array ohne Probleme anlegen? Sollte da nicht > eigentlich schon der Speicher reserviert werden? Du meinst das übergroße Array? Eigentlich sollte der IAR maulen, da hast du recht. Entweder eine falsche Einstellung gaukelt ihm mehr RAM vor, als er wirklich hat, oder eine Einstellung verhindert, dass eine Warnung ausgespuckt wird. Ich kann mir nicht vorstellen, dass sowas einfach akzeptiert wird vom IAR, aber genau sagen kann ich's nicht, ich verwende den Keil. Apropo Keil, ich dachte die USBXpress ist nur für den Keil verfügbar? Gibts die mittlerweile auch für den IAR? oO Ralf
> PPS: Die USB_Init-Methode will die Descriptoren nur aus dem RAM.
Falsch. Das ist jetzt der Zeitpunkt, an dem ich vermute, dass du den
ProgrammersGuide nicht aufmerksam gelesen hast. Die USB_INIT(...) will
einen Pointer auf den String! Im ProgrammersGuide kann ich keinen
MemorySpecific-Pointer im Prototyp sehen, also gehe ich davon aus, dass
auch ein Generic-Pointer funktioniert -> Da stimmt also was an deiner
Übergabe noch nicht ganz...
Ralf
USB-Init möchte BYTE* und bekommt aber "unsigned char const __code *" wenn ich die Descriptoren im Code-Speicher ablege.
1 | __code const BYTE USB_ProductStr[] = {0x10, 0x03, 'U', 0, 'S', 0, 'B', 0, ' ', 0, 'A', 0, 'P', 0, 'I', 0}; |
In der zip befindet sich diese Variante. Wenn ich auf BYTE* caste kommt am PC murks an - grundsätzlich gehts aber so. Eine USBXpress Portierung für IAR ist bei der Kaufversion dabei. Durch die Portierung wird sich wohl der Datetyp für die Descriptoren geändert haben. Wie gesagt... ich habe keine Quellen und IAR hat selbst keine Beschreibung beigefügt. (Mich stört schon allein das BYTE! Warum kann man da nicht unsigned char hinschreiben statt #define BYTE unsigned char?) Externer RAM war das Stichwort... jetzt wird mir so langsam einiges klar. Die Effizienz ist mir im übrigen nicht allzu wichtig. Der Controller soll nur Daten mit mind. 250 kbps weiterreichen - mehr nicht. Dafür werde ich wohl das Polling-Intervall deutlich verkürzen müssen.
Peter Dannegger schrieb: > Weil 4kB mit Sicherheit nicht in einen 1kB FIFO passen werden??? > Du mußt schon das Datenblatt mal anfassen. Block_Write kann lauf API-Beschreibung von 1 bis 4096 Byte mit einmal "aufnehmen" - was die Bibliothek damit macht, weiß ich nicht. USB low level sind böhmische Dörfer für mich.
> Block_Write kann lauf API-Beschreibung von 1 bis 4096 Byte mit einmal > "aufnehmen" Genau... auf einem F34x Device mit 4kB XRAM tut's das dann auch :) > Wenn ich auf BYTE* caste kommt am PC murks an - grundsätzlich gehts aber > so. Hm, okay, dann müssen wir uns das eben genau angucken. Irgendwie muss es korrekt klappen. > Wie gesagt... ich habe keine Quellen und IAR hat selbst keine > Beschreibung beigefügt. (Mich stört schon allein das BYTE! Warum kann > man da nicht unsigned char hinschreiben statt #define BYTE unsigned > char?) Gute Frage... Sag mal, beim Keil Compiler ist eine compiler_defs.H (oder ähnlich) dabei... Gibts die beim IAR auch? Wenn nicht, guck ich daheim mal danach. Vielleicht kann uns die helfen, richtig zu casten :) > Externer RAM war das Stichwort... jetzt wird mir so langsam einiges > klar. Das freut mich :) > Die Effizienz ist mir im übrigen nicht allzu wichtig. Der Controller > soll nur Daten mit mind. 250 kbps weiterreichen - mehr nicht. Sorry, aber für mich gehört Effizienz und "Daten schnell durchreichen" irgendwie zusammen zwinker > Dafür werde ich wohl das Polling-Intervall deutlich verkürzen müssen. Kann sein, aber lass uns erstmal gucken, was wir alles ausm Controller rausknautschen können, okay? Ralf
Mario G. schrieb: > Block_Write kann lauf API-Beschreibung von 1 bis 4096 Byte mit einmal > "aufnehmen" - was die Bibliothek damit macht, weiß ich nicht. USB low > level sind böhmische Dörfer für mich. Eine Bibliothek kann aber nicht die Hardware austricksen. Was nicht da ist, kann man auch nicht benutzen. Ich bin mir auch ziemlich sicher, daß nicht der gesamte 2kB RAM vom USB benutzt werden kann, sondern nur die 1kB FIFO. Peter
Das hört sich super an! Danke! Ich lege jetzt die beiden Arrays vor den Descriptoren an; in der Annahme, dass der RAM linear belegt wird. Alternativ könnte ich bei Konstanten auch eine Speicheradresse angeben. Mal schauen, wie groß ich das Sende-Array jetzt machen kann. Vorher mess ich aber mal die Übertragungszeiten des USB um zu sehen, wie weit runter ich mit dem Polling-Intervall gehen kann. Ich hab noch mal eine kommentierte und von allem Sinnlosen befreite Version der main.c angehängt. Per SPI kommen die Daten übrigens mit knapp 500kbps. Es ist also sichergestellt, dass nach einem SPI-Paket nicht gleich wieder eins kommt. Diese Übertragungsgeschwindigkeit kann ich auch noch erhöhen (1/10 der Taktfrequenz vom USB-Controller - also 1,2 Mbps). ...wäre ja irgendwie paradox, wenn USB da der Flaschenhals wäre. PS: BYTE ist in der USB_API.h definiert. Ob IAR sowas auch mit sich bringt, weiß ich nicht. Mir genügen die normalen c-Datentypen. ...und vielleicht mal eine Struktur. Ich bin aber noch nicht auf die Idee gekommen, die normalen Datentypen umzubennenen - auch wenn es Hostseitig byte gibt (ich verwende C#).
Die schlechte Nachricht: Die von mir erwähnte Headerdatei ist nicht von Keil. Die gute Nachricht: Sie ist von SiLabs :) Siehe Anhang, vielleicht hilft dir das schon mal. Bist mittlerweile weitergekommen, was die Strings bzw. die Pointer angeht? Ralf
Ich hab mir mal das Speicherabbild im Debugger angeschaut (hätte ich auch früher drauf kommen können). Da siehts folgendermaßen aus: 0x0000 1 Byte 0x08 0x0001-0x01A0 400 Byte 0xCD ? 0x01A1-0x01E0 64 Byte pac (InputBuffer) 0x01E1-0x03A0 448 Byte SPIbuffer 0x03A1-0x03FE 110 Byte Descriptoren, count und letzter freier Platz 0x03FF-0x07FF 1025 Byte 0x1A ? Viel mehr lässt sich also nicht mehr rausholen. Die beiden großen Bereiche werden wohl von der USBXpress-Bibliothek belegt (bzw. halt die FIFOs fürs USB). Die USB-ISR hat übrigens eine Laufzeit von ca. 2,8 ms mit 448 Byte Daten. Bei 448 Byte müssten man aber das Intervall auf 14 Sekunden setzen um auf 250 kbps zu kommen. Das würde aber bedeuten, dass der USB-Controller 20% der Rechenzeit in der blockierenden USB-ISR "hängt". Das wird knapp! Mit den Strings bin ich nicht weiter gekommen. Im Prinzip geht es ja, wenn die im Code-Speicher liegen. Das Gerät heißt dann aber am Host nicht mehr "fine" sondern 1323&f2"R53 - oder so ähnlich. Trotzdem schon mal vielen Dank für "compiler_defs.h" - die werde ich mir zu Hause mal "reinziehen". Das Brainstorming hier hat mir auf jeden Fall sehr geholfen. Ich werde dich auf dem Laufenden halten, wenn ich irgendwie weiter gekommen bin. mario
> Die beiden großen Bereiche werden wohl von der USBXpress-Bibliothek > belegt (bzw. halt die FIFOs fürs USB). Hm... Irgendwie kommt mir die Map komisch vor... Laut der USBXpress API Beschreibung holt sich die API 448 Byte im Bereich von 0x0640 - 0x07FF. Ausserdem macht mich der Speicherbedarf des SPI Buffers etwas stutzig. Ist der wirklich so groß? Laut deiner Main.c ist der doch bloß 256 Byte groß, wo kommt der Rest her? Arbeitest du mit (unnötigen) globalen Variablen? Würdest du mir mal deinen kompletten Code zukommen lassen? Ich hab zwar den IAR nicht, aber es würde helfen zu erkennen wo das Problem liegt (liegen könnte). Der Speicherverbrauch kommt mir einfach sehr hoch vor. > Die USB-ISR hat übrigens eine Laufzeit von ca. 2,8 ms mit 448 Byte > Daten. Bei 448 Byte müssten man aber das Intervall auf 14 Sekunden > setzen um auf 250 kbps zu kommen. Das würde aber bedeuten, dass der > USB-Controller 20% der Rechenzeit in der blockierenden USB-ISR "hängt". > Das wird knapp! Ja, moment... Bezüglich dem Hängen, BLOCK_WRITE kehrt zurück, wenn das letzte PAKET in den FIFO geschrieben wurde. Du schubst den SPI Buffer rein, das heisst, vier Pakete (64 Byte x 4 = 256). Deine Rechnung/Messung ist irgendwie falsch. Es müssten mindestens 7ms sein. Ein Paket pro Millisekunde, 448 Byte : 64 Byte = 7(ms). Das heisst, deine 250kbs Daten müssten in etwa 488ms da sein: 64Byte * 488 = 31232 Byte * 8 = ~250.000 Bit. Woher kommen denn die 448 Byte? Dein SPI Buffer ist doch nur 256 Byte groß (laut der letzten angehängten Main.c). Und wie kommst du auf die 14 Sekunden? > Mit den Strings bin ich nicht weiter gekommen. Im Prinzip geht es ja, > wenn die im Code-Speicher liegen. Das Gerät heißt dann aber am Host > nicht mehr "fine" sondern 1323&f2"R53 - oder so ähnlich. Oi! Was ist mit dem Hersteller- bzw. Produktstring? Ist der korrekt? > Das Brainstorming hier hat mir auf jeden Fall sehr geholfen. Ich werde > dich auf dem Laufenden halten, wenn ich irgendwie weiter gekommen bin. Ich helfe gerne :) Ralf
Die 448 Byte habe ich bei der Messung als Puffergröße festgelegt. Das war nachdem ich die main.c hier gepostet habe. ...hätte ich mir auch denken können, dass das Verwirrung stiftet. Es gibt sonst nur eine globale Variable (count). Die Zeit habe ich mittels PortPin (P2.7 siehe USB-ISR) und 'nem Oszi gemessen. Woher hast du denn die eine Millisekunde pro (USB-) Paket? Das würde die gesamte Situation noch verschlechtern, da der USB-Controller dann ja knapp 50% mit USB beschäftigt wäre. Die 14 Sekunden sollen natürlich 14 Millisekunden sein auf die ich folgendermaßen gekommen bin: 250.000 bps / 8 = 31.250 Bps Das macht bei 448 Byte pro Paket ca. 70 Pakete pro Sekunde 31250 Bps / 448 BpP = 69,75 Pps was wiederum ca. 14 ms pro Paket bedeuted. 1 / 70 Pps = 0,01429 spP Hersteller- und Produktstring waren übrigens korrekt. Ich nehme folgende Speicheraufteilung an: 1024 Byte für die FIFOs (am Ende des Speichers - mit 0x1A gefüllt beim Start) 400 Byte für die USBXpress-API (mit 0xCD gefüllt; vielleicht hat der abweichende Wert hier etwas mit der IAR-Portierung zu tun) Es bleiben also noch 624 Byte für die Descriptoren und die Anwendung übrig. Meine Descriptoren sind insgesamt 52 Byte und der InptuBuffer 64 Byte lang. Abzülich der zwei Byte für die Zählvariable und dem einen Byte bei 0x0000 (für was auch immer) bleiben 505 Byte für den SPIbuffer. Die nächstkleinere durch 64 Byte teilbare Zahl ist 448 Byte - wenn ich die Descriptoren aus dem RAM bekomme oder um mindestens 7 Byte verkleinere, vielleicht auch noch 512 Byte. Sind die Strings funktionsrelevant? Eigentlich genügt doch die VendorID und die ProductID - oder? Jedenfalls muss ich wohl damit leben. Ich könnte evtl. die Pakete auf den angeschlossenen µC auslagern und 64 Byte-weise im Intervall) an den USB-Controller schicken. So könnte ich den µC für die Übertragungszeit sperren (oder was anderes machen lassen) und der USB-Controller reicht das einfach nur durch (streamen quasi). Da muss ich aber alles noch mal umbauen. :( Ich werde morgen mal probieren, wie sich das Gesamtsystem mit dem kurzen Polling-Intervall verhält. Bis dahin... Gute Nacht. mario PS: Ach so... die main.c ist der komplette Code. es gibt lediglich noch die Header-Datei für die USB-API und die low_level_init.c - beide sind in der .zip weiter oben enthalten. ...wie auch die Bibliothek.
Zitat aus dem Programmers Guide: "It is useful to use the code keyword preceding the CustomString definitions, so that the strings are located in code space." So viel dazu. Dann wird das aller Wahrscheinlichkeit nach an der Portierung von/für IAR liegen. Die wollen an dieser Stelle BYTE* und der Compiler meckert rum, wenn er __code const BYTE* bekommt. ...zumal daraus eh __code const unsigned cahr * wird. Ist das hier vielleicht noch 'ne Alternative um ein wenig mehr Platz zu bekommen? Gibts das bei IAR auch? (Ich hab bis jetzt solche Kommandos noch nciht benutzt.) "Saving XDATA Space The USB_Init function parameters are passed in direct memory locations in user XDATA space determined by the linker. If user firmware needs this contiguous space, these 17 bytes can be relocated to unused XDATA space within the USBXpress reserved area. To do this, the following should be added to the command line while invoking the linker (the value for “address” is shown in Table 1): XDATA(?XD?_USB_INIT?USB_API(<address>))" Laut Programmers Guide sind in den von dir angesprochenen 448 Bytes, die die Bibliothek belegt, die FIFOs bereits enthalten. Also entweder ich hab irgendeine notwendige Einstellung nicht getroffen oder der Portierer hat gepfuscht. Die main.c ist aber wirklich das ganze Programm. VG mario
> Die 448 Byte habe ich bei der Messung als Puffergröße festgelegt. Das > war nachdem ich die main.c hier gepostet habe. ...hätte ich mir auch > denken können, dass das Verwirrung stiftet. Es gibt sonst nur eine > globale Variable (count). Die Zeit habe ich mittels PortPin (P2.7 siehe > USB-ISR) und 'nem Oszi gemessen. Ah, okay, dann passt's ja wieder :) > Woher hast du denn die eine Millisekunde pro (USB-) Paket? Aus meinem um diese Uhrzeit leicht geschwächten Gedächtnis... Sorry, ich hab Transaktion mit Paket verwechselt. Pro Transaktion können bis zu 19 Pakete versand werden, eine Transaktion erfolgt jede Millisekunde. So müsste das eher was werden :) > Die 14 Sekunden sollen natürlich 14 Millisekunden sein ... Okay, dann wär das auch geklärt. Aber das kann ja nicht sein, dass der Käfer so langsam ist, da haben wir noch irgendwo n Denkfehler bzw. n Bug im Code. > Das macht bei 448 Byte pro Paket ca. 70 Pakete pro Sekunde Ha, da ist das Verständnisproblem zwischen uns beiden: - Ein USB Paket kann nur max.64 Byte haben. Von diesem Wert bin ich natürlich auch bei einigen der obigen Aussagen ausgegangen. Erklärt warum wir aneinander vorbei geredet haben :) Wir müssen zusehen, dass du soviel XRAM wie möglich bekommst, damit der Buffer ordentlich gefüllt wird, und innerhalb einer USB Transaktion soviele Pakete wie möglich abgeschickt werden (Das Problem bei BulkTransfers die Priorität am niedrigsten, dafür die Bandbreite am höchsten ist). > Hersteller- und Produktstring waren übrigens korrekt. ??? Oi... Interessant... Gucken wir uns auch noch an... Verwende bitte mal Großbuchstaben. > Ich nehme folgende Speicheraufteilung an: > 1024 Byte für die FIFOs (am Ende des Speichers - mit 0x1A gefüllt beim > Start) 400 Byte für die USBXpress-API (mit 0xCD gefüllt; vielleicht hat > der abweichende Wert hier etwas mit der IAR-Portierung zu tun) ??? Ne, das sind weniger für API + USB-FIFO, zumindest lt. der Beschreibung im PG. > Es bleiben also noch 624 Byte für die Descriptoren und die Anwendung > übrig. > Meine Descriptoren sind insgesamt 52 Byte und der InptuBuffer 64 Byte > lang. Abzülich der zwei Byte für die Zählvariable und dem einen Byte bei > 0x0000 (für was auch immer) bleiben 505 Byte für den SPIbuffer. Die > nächstkleinere durch 64 Byte teilbare Zahl ist 448 Byte - wenn ich die > Descriptoren aus dem RAM bekomme oder um mindestens 7 Byte verkleinere, > vielleicht auch noch 512 Byte. Das nächstkleinere Vielfache von 64 ist ja nicht relevant, wenn du das Maximum hergibst, ist das letzte Paket halt kleiner, was soll's? Ja, die Descriptoren stopfen wir in den Code-Speicher und kneten die USB_INIT() dass sie die Dinger auch annimmt... > Sind die Strings funktionsrelevant? Eigentlich genügt doch die VendorID > und die ProductID - oder? Würd ich nicht drauf wetten, ich könnt mir vorstellen, dass die Strings zumindest bei einigen Sachen relevant sind für die Treiber. Komisch ist, dass eben nur der String der Seriennummer falsch übermittelt wird... > Jedenfalls muss ich wohl damit leben... Nana, nicht gleich aufgeben... :) > ... Da muss ich aber alles noch mal umbauen. :( Ja, aber an der richtigen Stelle, kann doch nicht sein, dass das nicht geht. Andere User haben schon weit mehr Daten rausgepustet. > Ich werde morgen mal probieren, wie sich das Gesamtsystem mit dem kurzen > Polling-Intervall verhält. Kannst du probeweise mal machen. > PS: Ach so... die main.c ist der komplette Code. es gibt lediglich noch > die Header-Datei für die USB-API und die low_level_init.c - beide sind > in der .zip weiter oben enthalten. ...wie auch die Bibliothek. Roger, ich guck mal rein (aber jetzt nimmer). > So viel dazu. Dann wird das aller Wahrscheinlichkeit nach an der > Portierung von/für IAR liegen. Die wollen an dieser Stelle BYTE* und der > Compiler meckert rum, wenn er __code const BYTE* bekommt. ...zumal > daraus eh __code const unsigned cahr * wird. > Ist das hier vielleicht noch 'ne Alternative um ein wenig mehr Platz zu > bekommen? Gibts das bei IAR auch? (Ich hab bis jetzt solche Kommandos > noch nciht benutzt.) Hm... Hast du das IAR Handbuch parat? Guck doch bitte mal im Kapitel Pointer, wie ein Generic-Pointer definiert ist, leg die Strings in den Code-Speicher, und mach einen TypeCast auf den Pointer-Typ, den USB_INIT() haben will. Wobei, das ja eigentlich nicht nötig sein sollte, wenn wir das mit der Seriennummer hinkriegen, schließlich tun die anderen beiden Strings ja... > Laut Programmers Guide sind in den von dir angesprochenen 448 Bytes, die > die Bibliothek belegt, die FIFOs bereits enthalten. Also entweder ich > hab irgendeine notwendige Einstellung nicht getroffen oder der Portierer > hat gepfuscht. Das ist ja das was mich kekst, offenbar ist die API fest auf einen Endpunkt und Buffergröße beschränkt! argl > Die main.c ist aber wirklich das ganze Programm. Okay, ich guck morgen nochmal in aller Ruhe drüber, vielleicht find ich was. Übrigens, auf welchen SiLabs Beispielen genau basiert deine Main.c? Guäts Nächtle... Ralf
Hallo Ralf! So... ich hab jetzt folgendes gemacht: Polling-Intervall auf 14 Millisekunden: Führte dazu, das einige der stochasisch ankommenden SPI-Pakete verloren gegangen sind. Das könnte man sperren, was aber dazu führen wird, dass der angeschlossene µC für diese Zeit keine Pakete mehr aus dem Netz empfangen kann. -> Verringerung der Datenrate! Descriptoren auf einen Buchstaben verkürzt: Die Dinger sind tatsächlich völlig irrelevant. Durch diese Verkleinerung konnte ich die Größe des Puffers auf 512 Byte erhöhen. Das ergibt aber immer noch ein Polling-Intervall von 16 Millisekunden um auf 250 kbps zu kommen. Testweise die Bibliothek aus dem Projekt entfernt: Die Puffergröße war trotzdem auf einen Wert zwischen 786 und 1024 Byte beschränkt (hab ich nicht weiter ausprobiert). Im Datenblatt des USB-Controllers steht auch - wie Peter schon gesagt hat, dass die USB-FIFOs 1 kB RAM verbrauchen. Vom Rest gehen nochmal 400 Byte für die Bibliothek weg. Das, was dann noch übrig ist, ist das, womit man leben muss. Die Beispiele waren übrigens nicht von SiLabs, sondern von IAR. In dem Ordner hab ich auch noch ein Beispiel für eine Dateiübertragung gefunden. Die benutzen den Flash als Zwischenspeicher (hab ich mal angehängt). Damit werde ich mich jetzt mal ein wenig beschäftigen. Wenn das auch nicht geht, dann werde ich das gesamte Kommunikationskonzept noch mal überarbeiten - die Logik einfach komplett auf den PC auslagern (momentan filtert der angeschlossene µC irrelevante Daten aus). Vielen Dank nochmal mario
> Polling-Intervall auf 14 Millisekunden: ... > Verringerung der Datenrate! Muss aber möglich sein, ohne Datenverlust die gewünschte Menge zu übertragen (eigentlich sogar noch mehr Daten). > Descriptoren auf einen Buchstaben verkürzt: ... Ja, versuchsweise okay, aber wenn ich ein Gerät kaufe, welches sich nur mit einem Buchstaben anmeldet, würd ich nicht mal den Treiber installieren :) Aber das gleiche sollte doch ohne Stringkürzung möglich sein, wenn die Descriptoren im Flash abgelegt sind. Hast du es auch mal nur mit Ziffern probiert? > Testweise die Bibliothek aus dem Projekt entfernt: Die Puffergröße war > trotzdem auf einen Wert zwischen 786 und 1024 Byte beschränkt (hab ich > nicht weiter ausprobiert). Irgendwie stimmt da was mit den Projekteinstellungen nicht... Wieviele Dialoge für die Projekteinstellungen gibts im IAR? Wenn es nicht allzuviele sind, kannst du mal ScreenShots posten? > Im Datenblatt des USB-Controllers steht auch - wie Peter schon gesagt > hat, dass die USB-FIFOs 1 kB RAM verbrauchen. Nein, da steht, dass 1kB des XRAMs als FIFO für die Endpunkte dienen können, wobei jeder Endpunkt eine bestimmte Teilmenge des FIFOs erhält... Würde ich also so interpretieren, dass nicht verwendete Endpunkte auch keinen FIFO-Speicher brauchen - was die Sache wieder etwas besser machen sollte... > Vom Rest gehen nochmal 400 Byte für die Bibliothek weg. Das, was dann > noch übrig ist, ist das, womit man leben muss. Dann muss das entweder ein wahnsinnig schlechter Port der Keil Lib sein, oder IAR hat da was völlig eigenes hochgezogen... > Die Beispiele waren übrigens nicht von SiLabs, sondern von IAR. In dem > Ordner hab ich auch noch ein Beispiel für eine Dateiübertragung > gefunden. Die benutzen den Flash als Zwischenspeicher (hab ich mal > angehängt). Die verwenden den Flash halt quasi als Ultra-Mini-Speicherkarte :) Ganz ehrlich, momentan befürchte ich, dass der F320 nicht das Problem ist, sondern der IAR... Bist du an den IAR gebunden? Ralf
Es gibt eine Portierung auf den SDCC, siehe: http://sdccokr.dl9sec.de/resources.htm Als Vorlage diente die Keil Version.
Noch ein Hinweis, SDCC läßt sich sehr gut in die Silabs IDE einbinden: http://www.silabs.com/Support%20Documents/TechnicalDocs/an198.pdf So hat man quasi die Keil Umgebung mit einem freien C Compiler.
> Muss aber möglich sein, ohne Datenverlust die gewünschte Menge zu > übertragen (eigentlich sogar noch mehr Daten). Das ist im momentanen Gesamtsystem problematisch, da nicht vorhergesehen werden kann, wann per SPI ein Paket kommt. Duch das kurze Polling-Intervall kommt es dadurch weitaus häufiger vor, dass ein Paket kommt, während die USB-API den SPI-Interrupt blockiert. > Ja, versuchsweise okay, aber wenn ich ein Gerät kaufe, welches sich nur > mit einem Buchstaben anmeldet, würd ich nicht mal den Treiber > installieren :) Das soll nicht verkauft werden. Es war ja eigentlich auch recht unproblematisch mit den Descriptoren im Flash - wird halt der Name falsch angezeigt. Die "paar" Byte helfen aber auch nicht großartig weiter. > Irgendwie stimmt da was mit den Projekteinstellungen nicht... Wieviele > Dialoge für die Projekteinstellungen gibts im IAR? Wenn es nicht > allzuviele sind, kannst du mal ScreenShots posten? Screenshots von allen Einstellungen sind angehängt. > Dann muss das entweder ein wahnsinnig schlechter Port der Keil Lib sein, > oder IAR hat da was völlig eigenes hochgezogen... Im ProgrammersGuide steht aber, das die Bibliothek 448 Byte im RAM belegt. Van daher wäre die Portierung ja sogar noch besser. > Ganz ehrlich, momentan befürchte ich, dass der F320 nicht das Problem > ist, sondern der IAR... Bist du an den IAR gebunden? Jein. Mehr ja als nein. IAR wird mir halt zur Verfügung gestellt. Ich hab mir nochmal den Speicher angeschaut. Ab USB_Clock_Start(); wird der Speicher von 0x0400 bis 0x063F und von 0x0740 bis 0x07FF vollgeschrieben. Zwischendrin sind nochmal 256 Byte frei bzw. es steht 0x00 drin. Ich frage mich nur, was die Bibliothek mit den 400 Byte macht. Da steht selbst nach einer Zeit in Betrieb ausschließlich 0xCD drin. Lediglich die 16 Byte danach ändern sich. (Danach kommt der InputBuffer.) Ich werde das gesamte System einfach nochmal überdenken. Die Vorraussetzungen haben sich ja schon gewaltig verändert. Ich war bei USB von 12 Mbps bzw. mindestens von 1,5 Mbps ausgegangen. Brutto hat der das bestimmt auch. Durch die Bibliothek geht aber zu viel Zeit verloren. Das Polling-Intervall kann ich um einiges verkürzen, wenn ich die Verarbeitung der Daten komplett auf dem PC dürchführe und den µC quasi mit dem USB-Controller synchronisiere - ist halt nur 'n bissl Arbeit. Nichts desto trotz kannst du ja mal schauen, ob ich vielleicht doch irgendwo 'nen Fehler in den Einstellungen habe. Danke nochmal mario
> Das ist im momentanen Gesamtsystem problematisch, da nicht vorhergesehen > werden kann, wann per SPI ein Paket kommt. Duch das kurze > Polling-Intervall kommt es dadurch weitaus häufiger vor, dass ein Paket > kommt, während die USB-API den SPI-Interrupt blockiert. Wie ist denn die Paketgröße, die in einem Rutsch von deinem SPI empfangen wird? Mit welcher Geschwindigkeit wird der SPI-Bus getaktet? > Das soll nicht verkauft werden. Es war ja eigentlich auch recht > unproblematisch mit den Descriptoren im Flash - wird halt der Name > falsch angezeigt. Die "paar" Byte helfen aber auch nicht großartig > weiter. Mag sein, aber es macht halt stutzig, wenn schon sowas "einfaches" nicht richtig tut... > Im ProgrammersGuide steht aber, das die Bibliothek 448 Byte im RAM > belegt. Van daher wäre die Portierung ja sogar noch besser. Du hast geschrieben, dass die 1kB weg sind PLUS die 400 der Lib. Halte ich für schlechter :) > Ich hab mir nochmal den Speicher angeschaut. Ab USB_Clock_Start(); wird > der Speicher von 0x0400 bis 0x063F und von 0x0740 bis 0x07FF > vollgeschrieben. Zwischendrin sind nochmal 256 Byte frei bzw. es steht > 0x00 drin. Ab hier wird es interessant, denn: - wir gehen zwar immer hübsch von den Angaben der USBXpress Unterlagen aus, aber die sind wie gesagt für den Keil Compiler geschrieben. Die Unterlagen sagen, dass die Lib den Speicher von 0x640-0x7FF verwendet -> die angegebenen 448 Byte, entsprechen vom Adressbereich den FIFOs der Endpunkte 0 bis 2 -> Endpunkt 0 ist bei jedem Gerät immer aktiv, laut Beschreibung wird aber für die Daten nur Endpunkt 2 verwendet, das heisst, der FIFO des Endpunkt 1 ist für die Lib-internen Daten. - Dein Debugger sagt, der Speicher von 0x400-0x63F sowie 0x740-0x7FF wird verwendet -> 576 Byte + 192 Byte = 768 Byte, vom Adressbereich sind das die FIFOs der Endpunkte 0, 1 und 3 sowie die 64 freien Byte im FIFO. Die 256 Byte dazwischen entsprechen genau dem FIFO des Endpunktes 2. - Du sagst, die 256 Byte bleiben quasi unberührt. Entweder sagt der Debugger was falsches, oder der IAR Port der API verwendet für die Daten die Endpunkte 1 und 3 (unwahrscheinlich, denn dann wär's ja absolut nicht kompatibel) > Ich frage mich nur, was die Bibliothek mit den 400 Byte macht. Da steht > selbst nach einer Zeit in Betrieb ausschließlich 0xCD drin. Lediglich > die 16 Byte danach ändern sich. (Danach kommt der InputBuffer.) Absolut keine Änderung? Das hört sich danach an, als ob der Debugger da keinen richtigen Zugriff bekommt. Die Lib will den Speicher sicher nicht umsonst :) > Screenshots von allen Einstellungen sind angehängt. Target.PNG: - DataModell von LARGE auf SMALL ändern, sonst landen alle nicht explizit einem Speichertyp zugewiesenen Variablen in XDATA -> Es bietet sich bei allen Projekten an, auf SMALL zu bleiben, da dort auf die Variablen am schnellsten zugegriffen werden kann. Große Buffer usw. legt man explizit in XDATA ab. - Location for constants and strings = CODE memory. Guck mal, ob das was bringt (trotz der bereits explizit in CODE abgelegten Strings) - Calling convention kenne ich nicht, müsste ich nachlesen. Ich vermute, dass sich die Einstellung automatisch ändert, wenn das DataModell angepasst wird. Optimizations.PNG: - Level auf High setzen, in der Liste die Größenoptimierung wählen STACK-HEAP.PNG: - bin nicht sicher, ob eine Änderung hier was bringt (wenn du das DataModell umstellst, sollte das eigentlich reichen), aber mal angenommen, das ursprüngliche DataModell = LARGE verwendet XDATA, dann würde ja ab 0x1A0 irgendein Stack angelegt werden -> evtl. wird Speicher frei, wenn DataModell SMALL ist OUTPUT2-4.PNG: - Hm...auch hier bin ich nicht sicher, ob da irgendwelche der DEBUG-Infos im Programm landen, oder nur in speziellen Dateien für den Debugger > Ich war bei USB von 12 Mbps bzw. mindestens von 1,5 Mbps ausgegangen. > Brutto hat der das bestimmt auch. Durch die Bibliothek geht aber zu viel > Zeit verloren. Das Polling-Intervall kann ich um einiges verkürzen, wenn > ich die Verarbeitung der Daten komplett auf dem PC dürchführe und den µC > quasi mit dem USB-Controller synchronisiere - ist halt nur 'n bissl > Arbeit. USB basiert auf fest einzuhaltenden Timings, die 12Mbps sind also sicher da :) Sicherlich ist da LowLevel-Protokoll-Overhead mit dabei, aber mehr als maximal 10% gehen da nicht hops. Deswegen interessiert mich ja dein Problem so arg (abgesehen von meiner angeborenen, natürlichen Hilfsbereitschaft), denn ich hab hier mehrere SiLabs DevKits rumflöten :) Hm... Ich könnte mal deine Main.C nehmen, und dir ein HEX-File mit dem Keil Compiler und der "originalen" Lib generieren. Wäre alles ohne Gewähr auf Funktion, und natürlich auf eigenes Risiko deinerseits. Ralf
> Wie ist denn die Paketgröße, die in einem Rutsch von deinem SPI > empfangen wird? Mit welcher Geschwindigkeit wird der SPI-Bus getaktet? Der SPI-BUS läuft mit knapp 500 kbps - kann aber noch schneller (ca. 2x). Die Pakete haben unterschiedliche Größen (momentan 10 bis 25 Byte). Sie kommen per Funk am µC an, werden dort vom Overhead befreit und gleich per SPI weiter gesendet. Der USB-Controller sammelt die Pakete hintereinander im Puffer und schickt den alle 100 Millisekunden an den PC (so wars jedenfalls konzipiert). > Du hast geschrieben, dass die 1kB weg sind PLUS die 400 der Lib. Halte > ich für schlechter :) Das sind ja zwei unterschiedliche Dinge. Laut Datenblatt geht 1 kB für die (LowLevel-) USB-FIFOs weg. Die Bibliothek bruach extra nochmal 448 Byte - wenn ich das richtig verstanden habe. > USB basiert auf fest einzuhaltenden Timings, die 12Mbps sind also sicher > da :) Sicherlich ist da LowLevel-Protokoll-Overhead mit dabei, aber mehr > als maximal 10% gehen da nicht hops. Deswegen interessiert mich ja dein > Problem so arg (abgesehen von meiner angeborenen, natürlichen > Hilfsbereitschaft), denn ich hab hier mehrere SiLabs DevKits rumflöten > :) Nach meiner Rechnung dürfte die Übertragung von 512 Byte mit 12 Mbps ca. 342 Mikrosekunden dauern. Selbst mit viel Overhead vielleicht so 'ne halbe Millisekunde. Gemessen hab ich über zwei Millisekunden (für die USBXpress-ISR). Da scheint also noch mal über das dreifache der eingentlichen Übertragungszeit für Funktionsaufrufe und Logik allg. drauf zu gehen. ...oder durch den Bulk-Transfer. Laut Beschreibung werden die Daten da bis zu drei mal wiederholt. USBXpress ist damit von Grund auf "suboptimal". Vielleicht sollte ich mal 'ne USB-Leitung auftröseln und die Pakete mitm Logikanalysator anschauen... > Hm... Ich könnte mal deine Main.C nehmen, und dir ein HEX-File mit dem > Keil Compiler und der "originalen" Lib generieren. Wäre alles ohne > Gewähr auf Funktion, und natürlich auf eigenes Risiko deinerseits. Den Service würde ich gern in Anspruch nehmen. ;-) Danke! mario
> Der SPI-BUS läuft mit knapp 500 kbps - kann aber noch schneller (ca. > 2x). Die Pakete haben unterschiedliche Größen (momentan 10 bis 25 Byte). > Sie kommen per Funk am µC an, werden dort vom Overhead befreit und > gleich per SPI weiter gesendet. Der USB-Controller sammelt die Pakete > hintereinander im Puffer und schickt den alle 100 Millisekunden an den > PC (so wars jedenfalls konzipiert). Hm... Okay, dann blick ich da schon ein bisschen besser durch was da passiert bzw. passieren soll. > Das sind ja zwei unterschiedliche Dinge. Laut Datenblatt geht 1 kB für > die (LowLevel-) USB-FIFOs weg. Die Bibliothek bruach extra nochmal 448 > Byte - wenn ich das richtig verstanden habe. Tja, das ist jetzt die Frage. In der USBXpress Beschreibung auf Seite 24 in der Tabelle steht:
1 | XDATA space reserved by the library: |
2 | 448 bytes XDATA (0x0640 to 0x07FF) *[includes USB FIFO space]* |
Ebenfalls steht dort, dass nur Endpunkt 2 verwendet wird, was die Aussage, dass der FIFO-Speicher bereits mit verwendet wird, untermauert, da der passende Adressbereich belegt wird. > Nach meiner Rechnung dürfte die Übertragung von 512 Byte mit 12 Mbps ca. > 342 Mikrosekunden dauern. Selbst mit viel Overhead vielleicht so 'ne > halbe Millisekunde. Gemessen hab ich über zwei Millisekunden (für die > USBXpress-ISR). Da scheint also noch mal über das dreifache der > eingentlichen Übertragungszeit für Funktionsaufrufe und Logik allg. > drauf zu gehen. Nachdem ich jetzt ein bisschen besser durchblicke, was da passieren soll, glaube ich, dass es auch daran liegen kann, wie du die USB Interrupts programmiert hast. Weiter unten schreib ich noch was dazu (*) > ...oder durch den Bulk-Transfer. Laut Beschreibung werden die Daten da > bis zu drei mal wiederholt. USBXpress ist damit von Grund auf > "suboptimal". Okay, so gesehen schon, denn BULK garantiert zwar Bandbreite, hat aber die niedrigste Priorität auf dem Bus. Wobei... Die benötigte Bandbreite muss ja in den Descriptoren stehen... Was steht denn im entsprechenden Descriptor? > Vielleicht sollte ich mal 'ne USB-Leitung auftröseln und die Pakete mitm > Logikanalysator anschauen... Lass mal sein, ich glaub nicht, dass ein normaler LA ohne passende Messstrippen das genau genug erkennen kann bzw. den Bus evtl. kapazitiv zu arg belastet. Ausserdem sollte er dann das Protokoll unterstützen, sonst suchst du dir ja n Wolf... Nimm für den Anfang lieber mal einen Software-USB-Analyzer, die sollten für den Anfang reichen... > Den Service würde ich gern in Anspruch nehmen. ;-) Danke! Jo, mach ich. Soll ich die Main.c vom 10.02.2010 17:52 nehmen oder willst du mir die aktuelle Version "opfern"? (*)Bzgl. der USB-Interrupts, ich kann momentan nur von der auskommentierten Variante der Main.c ausgehen, bei der du offenbar im RX_Interrupt darauf reagierst, bei Datenempfang vom Rechner den kompletten SPI-Buffer zu schicken. Hab ich das so richtig erfasst? Das ist alles irgendwie wachsweich, mit SPI-Interrupt sperren, etc und dann aus dem RX-Interrupt raus senden(selbst wenn's in dem Fall ja nur für's Messen war). Das hängt wahrscheinlich auch ein bisschen damit zusammen, dass du den 805x-Kern noch nicht durchschaut hast :) Ist ja nicht schlimm, ich kann versuchen, aus der Main.c eine Version zu machen, von der ich glaube, dass sie das besser umsetzt. Falls du das willst... Aber heut wird das nix mehr :( Stehst du da arg unter Zeitdruck bei dem Projekt? Ralf
> Okay, so gesehen schon, denn BULK garantiert zwar Bandbreite, hat aber > die niedrigste Priorität auf dem Bus. Wobei... Die benötigte Bandbreite > muss ja in den Descriptoren stehen... Was steht denn im entsprechenden > Descriptor? Wo muss ich denn da suchen? Ich hab nur die drei Strings und die paar anderen Werte für PID und VID... > Nimm für den Anfang lieber mal einen > Software-USB-Analyzer, die sollten für den Anfang reichen... Das mach ich. ...wusste bis eben nicht, dass es sowas für USB gibt. > Jo, mach ich. Soll ich die Main.c vom 10.02.2010 17:52 nehmen oder > willst du mir die aktuelle Version "opfern"? Ich poste morgen nochmal 'ne aktuelle Version. ~hab zwar nicht viel geändert, aber sicher ist sicher. > (*)Bzgl. der USB-Interrupts, ich kann momentan nur von der > auskommentierten Variante der Main.c ausgehen, bei der du offenbar im > RX_Interrupt darauf reagierst, bei Datenempfang vom Rechner den > kompletten SPI-Buffer zu schicken. Hab ich das so richtig erfasst? Ja. Wenn ich Device-seitig die Paketgröße auf die tatsächliche Größe anpasse, bekomme ich Host-seitig Probleme, da ich ja dort die Anzahl der zu empfangenden Bytes angeben muss - die der Host ja nicht kennt. > Das ist alles irgendwie wachsweich, mit SPI-Interrupt sperren, etc und > dann aus dem RX-Interrupt raus senden(selbst wenn's in dem Fall ja nur > für's Messen war). Das hängt wahrscheinlich auch ein bisschen damit > zusammen, dass du den 805x-Kern noch nicht durchschaut hast :) Ist ja > nicht schlimm, ich kann versuchen, aus der Main.c eine Version zu > machen, von der ich glaube, dass sie das besser umsetzt. Falls du das > willst... > Aber heut wird das nix mehr :( Stehst du da arg unter Zeitdruck bei dem > Projekt? Zeitdruck habe ich nicht. Das System funktioniert aufgrund der beschränkten Anzahl an Funkteilnehmern problemlos. Ich will aber die maximale Datenrate des Netzes auch zum PC garantieren können. Das Sperren des SPI-Interrupts wollte ich im nächsten Schritt auf den µC auslagern. Der sollte quasi die Daten weiter sammeln, bis der USB-Controller wieder Zeit hat. Das wäre im Prinzip die Lösung dafür, das Polling-Intervall stark zu verkürzen. Durch die schnelle SPI-Übertragung könnte man da locker in den Bereich so um zehn Millisekunden kommen. Synchronisieren würde ich das über einen PortPin, oder indem ich den USB-Controller zum SPI-Master mache. Das Verlagert das Problem zwar nur, der µC (übrigens auch ein 8051) ist aber ein klein wenig flexibler. ...oder ich nehme einfach einen Transceiver mit integriertem USB-Controller (CC2531 von TI z.B.). Alles irgendwie "wachsweich". Eigentlich hatte ich mich gefreut, dass es diese Bibliothek gibt. Über RS232 wäre alles viel einfacher gewesen... aber nicht so schön. :) Es würde mich auf jeden Fall außerordentlich freuen, wenn du eine effektivere Lösung für dieses Problem "erfinden" würdest. So langsam bekomme ich aber ein schlechtes Gewissen - bei dem Lebenszeitverlust, den du mit mir hast. ;) mario
Moin Mario, > Wo muss ich denn da suchen? Ich hab nur die drei Strings und die paar > anderen Werte für PID und VID... Hm... wenn man es in der API-Headerdatei nicht umstellen kann, wird es wohl fest in der Lib codiert sein :( > Das mach ich. ...wusste bis eben nicht, dass es sowas für USB gibt. Doch doch, wir haben hier auch ein oder zwei im Einsatz. > Ich poste morgen nochmal 'ne aktuelle Version. ~hab zwar nicht viel > geändert, aber sicher ist sicher. Okay. N kompletter Schaltplan wäre vielleicht noch sinnvoll. > Ja. Wenn ich Device-seitig die Paketgröße auf die tatsächliche Größe > anpasse, bekomme ich Host-seitig Probleme, da ich ja dort die Anzahl der > zu empfangenden Bytes angeben muss - die der Host ja nicht kennt. Das müsste aber wurscht sein. Wenn der Host 128 Byte anfordert, das Gerät aber grad nur 100 Byte hat, müssten die 100 abgeholt werden und das Gerät dann die Kommunikation abbrechen, wenn ich's richtig im Kopf hab. Und es müsste alles vom jeweiligen Treiber abgefangen werden. Nebenbei: Wie sieht denn eigentlich die Gegenstelle aus? Also welche Software aufm PC? > Zeitdruck habe ich nicht. Okay, dann können wir über's Wochenende ein bisschen experimentieren :) Falls das für dich okay ist. > Alles irgendwie "wachsweich". Eigentlich hatte ich mich gefreut, dass > es diese Bibliothek gibt. Sollst du auch :) Genau deswegen behaupte ich auch, dass es möglich sein muss. Im SiLabs-Forum sind höhere Datenraten mit XPress realisiert worden, also muss es gehen. > Über RS232 wäre alles viel einfacher gewesen... aber nicht so schön. :) Nja, schon, aber die stirbt halt langsam aus... andersrum machts ja auch Spass mal was neues zu lernen. > Es würde mich auf jeden Fall außerordentlich freuen, wenn du eine > effektivere Lösung für dieses Problem "erfinden" würdest. So langsam > bekomme ich aber ein schlechtes Gewissen - bei dem Lebenszeitverlust, > den du mit mir hast. ;) Okay, meine Zeit auf dieser Welt ist (wie bei jedem anderen auch) natürlich beschränkt, aber ich hab ja auch n bisschen was davon, wenn ich dir helfe :) Ich hoffe im Gegensatz nur, dass es dann auch tatsächlich klappt :) Ralf
Mario G. schrieb: > Das ist im momentanen Gesamtsystem problematisch, da nicht vorhergesehen > werden kann, wann per SPI ein Paket kommt. Duch das kurze > Polling-Intervall kommt es dadurch weitaus häufiger vor, dass ein Paket > kommt, während die USB-API den SPI-Interrupt blockiert. Warum redest Du immer wieder von Polling und Blockieren? Der MC hat doch ein Hardware-USB. Und da erwarte ich, daß man die Sendedaten in den FIFO schreibt und fertig, d.h. ich kann nun andere Sachen machen. Und irgendwann kriege ich einen Interrupt, daß der PC die Daten abgeholt hat. Bzw. da das ja ein FIFO ist, muß es auch eine Funktion geben, die mir sagt, wieviel im FIFO noch frei ist. D.h. ich habe z.B. 16 Byte zu senden, frage ab und wenn dann >=16Byte frei sind, schreibe ich die in den FIFO, auch wenn der noch nicht leer ist. Die Zeit für die Übertragung zum PC geht Dir also nicht verloren, die kannst Du fürs SPI und anderes benutzen. Außerdem hat der 8051 vier Interruptprioritäten. Wenn der USB-Interrupt zu lange dauern sollte, dann mußt Du nur dem SPI-Interrupt eine höhere Priorität zuweisen und dann unterbricht er einfach das USB. Peter
Genau das wären so ein paar der Ansätze, die ich dann optimiert hätte. Ralf
Hallo! Entschuldigt bitte mein langes Schweigen - hatte heute keine Zeit für das Projekt. > Das müsste aber wurscht sein. Wenn der Host 128 Byte anfordert, das > Gerät aber grad nur 100 Byte hat, müssten die 100 abgeholt werden und > das Gerät dann die Kommunikation abbrechen, wenn ich's richtig im Kopf > hab. Und es müsste alles vom jeweiligen Treiber abgefangen werden. Der Treiber fängt das leider nicht ab. Ich lese die Daten am Host mit der Bibliotheksfunktion SI_Read aus. Dort muss man die Anzahl der zu lesenden Bytes angeben. Kommen weniger als angegeben an, meldet die Bibliothek nach einem Timeout einen Fehler. > Nebenbei: Wie sieht denn eigentlich die Gegenstelle aus? Also welche > Software aufm PC? Auf dem PC habe ich den Treiber von SiLabs, die DLL von SiLabs und 'nen Wrapper für C# für die DLL. > Okay, dann können wir über's Wochenende ein bisschen experimentieren :) > Falls das für dich okay ist. Im Prinzip ist das vollkommen OK für mich, ich hab aber die Hardware nicht zu Hause - wird also leider nichts. Der Treiber läuft nur unter XP - selbst, wenn ich wöllte, könnte ich zu Hause nicht. > ...andersrum machts ja auch Spass mal was neues zu lernen. Ja! Allerdings! Peter Dannegger schrieb: > Warum redest Du immer wieder von Polling und Blockieren? > > Der MC hat doch ein Hardware-USB. > Und da erwarte ich, daß man die Sendedaten in den FIFO schreibt und > fertig, d.h. ich kann nun andere Sachen machen. > Und irgendwann kriege ich einen Interrupt, daß der PC die Daten abgeholt > hat. Durch die USBXpress-Bibliothek jabe ich keinen direkten Zugriff auf die FIFOs - die Hardware wird -wie auch immer- von der LIB gehandhabt und die blockiert mein Programm. Ohne die LIB müsste ich mich um LowLevel-USB kümmern, wozu ich aber eigentlich keine Zeit habe. Ich habe mich heute mit meinem ElCommandante darauf geeinigt, dass die Datenrate erstmal zweitrangig ist. Die werden wir eh nicht voll ausnutzen. Das eigentliche Thema sind energieeffiziente Routingprotokolle in drahtlosen AdHoc-Netzwerken, was wir natürlich auch testen wollen. Ich werden die beiden Controller daher jetzt noch synchonisieren - dass der µC dem USB-Controller nur Daten schickt, wenn der grad nicht in der Bibliothek festhängt. Damit komme ich auch auf 250 kbps mit dem Nachteil, dass der µC ein kleines bisschen weniger Daten aus dem Funknetz aufnehmen kann. Das unterstützt aber Hardware-Acknowledge, weshalb da keine Daten verloren gehen. In Zukunft werden wir dann sehr wahrscheinlich den CC2531 einsetzen. Das ist ein Transceiver mit integriertem USB-Controller. TI bietet dafür eine USB Firmware-Library an, die im Quellcode für IAR vorliegt. http://www.ti.com/litv/zip/swrc088c Deine Vorschläge zu den Projekteinstellungen werde ich am Montag mal ausprobieren und die Ergebnisse hier posten. Ich hab ja die Hoffnung, dass das Synchonisieren erstmal zu einem Teilerfolg führt. Vielen Dank nochmal und ein schönes Wochenende. mario
Mario G. schrieb: > Der Treiber fängt das leider nicht ab. Ich lese die Daten am Host mit > der Bibliotheksfunktion SI_Read aus. Dort muss man die Anzahl der zu > lesenden Bytes angeben. Kommen weniger als angegeben an, meldet die > Bibliothek nach einem Timeout einen Fehler. Dann mußt Du eben ein Protokoll aufsetzen. Z.B. Du sendest immer 2 Pakete. Das erste Paket hat eine konstante Länge und teilt nur die Länge des zweiten Datenpakets mit. > Durch die USBXpress-Bibliothek jabe ich keinen direkten Zugriff auf die > FIFOs - die Hardware wird -wie auch immer- von der LIB gehandhabt und > die blockiert mein Programm. Das kann ich nicht glauben, daß die Bibliothek so schlampig implemeniert sein soll. Das hieße ja, Du bleibst für immer hängen, wenn der PC die Daten mal nicht abholt. Eine Bibliothek muß verschiedene Funktionen bereitstellen, die auch direkt nach Aufruf wiederkehren. Eine Funktion zur Statusabfrage muß sagen, ob Du was in den Sendepuffer schreiben darfst. Eine Funktion kopiert dann die Daten in den Sendepuffer. Und dann kann Dir wieder die Statusabfrage mitteilen, ob das Senden erfolgt ist. Es kann natürlich sein, wenn Du ohne Statusabfrage die Sendefunktion aufrufst, daß die dann solange wartet, bis das nächste Senden möglich ist. Dann ist das Warten aber Deine Schuld. Du solltest nochmal genau nachsehen, welche Funktionen Dir die Bibliothek zur Verfügung stellt und wie diese funktionieren. Man könnte notfalls auch das gesamte SPI-Handling als höher priorisierten Interrupt ausführen. Peter
> Der Treiber fängt das leider nicht ab. Ich lese die Daten am Host mit > der Bibliotheksfunktion SI_Read aus. Dort muss man die Anzahl der zu > lesenden Bytes angeben. Kommen weniger als angegeben an, meldet die > Bibliothek nach einem Timeout einen Fehler. Aber mit SI_CheckRXQueue(...) bekommst du doch die Anzahl der Bytes, die ein Device gerade im Buffer hat. Wenn du das vor dem SI_READ(...) ausführst und die Anzahl der Daten übernimmst, müsste das doch ohne Fehler gehen? Ralf
> Das kann ich nicht glauben, daß die Bibliothek so schlampig implemeniert > sein soll. > Das hieße ja, Du bleibst für immer hängen, wenn der PC die Daten mal > nicht abholt. Das hab ich noch nicht probiert. Laut Programmers Guide gibt die Block_Write Funktion 0 zurück, wenn ein Fehler aufgetreten ist. > Eine Bibliothek muß verschiedene Funktionen bereitstellen, die auch > direkt nach Aufruf wiederkehren. > Eine Funktion zur Statusabfrage muß sagen, ob Du was in den Sendepuffer > schreiben darfst. > Eine Funktion kopiert dann die Daten in den Sendepuffer. > Und dann kann Dir wieder die Statusabfrage mitteilen, ob das Senden > erfolgt ist. Sowas gibt es in der Bibliothek nicht. Die ist für besonders einfache Handhabung und schelle Entwicklung geschrieben worden. Für den Datentransfer gibt es folgende Funktionen:
1 | UINT Block_Write (BYTE *Buffer, UINT NumBytes) |
2 | BYTE Block_Read (BYTE *Buffer, BYTE NumBytes) |
Der Bibliothek wird quasi ein "User"-Puffer übergeben - den Rest macht sie von selbst. Weitere Funktionen dienen nur der Initialisierung und dem (virtuellen) Interrupt: USB_Clock_Start() - Initializes the USB clock USB_Init() - Enables the USB interface Get_Interrupt_Source() - Indicates the reason for an API interrupt USB_Int_Enable() - Enables the API interrupts USB_Int_Disable() - Disables API interrupts USB_Disable() - Disables the USB interface USB_Suspend() - Suspend the USB interrupts USB_Get_Library_Version() - Returns the USBXpress firmware library version Die FIFOs müssen vom User unberührt bleiben, sonst kommt die Bibliothek durcheinander. > Es kann natürlich sein, wenn Du ohne Statusabfrage die Sendefunktion > aufrufst, daß die dann solange wartet, bis das nächste Senden möglich > ist. > Dann ist das Warten aber Deine Schuld. Block_Write braucht mit einem 512 Byte großem Puffer ca. 3 Millisekunden - daran lässt sich nichts ändern. > Du solltest nochmal genau nachsehen, welche Funktionen Dir die > Bibliothek zur Verfügung stellt und wie diese funktionieren. Ich denke wir haben da ein unterschiedliches Verständnis von "Bibliothek". Die USB-Firmware-Library von TI z.B. bietet solche Funktionen an, wie du sie beschreibst. USBXpress von SiLabs ist für DumbAss-User wie mich gemacht, die rein gar nichts von den USB-internen Abläufen wissen (wollen) - allerdings mit oben angesprochener Einschränkung der Übertragungsrate. > Man könnte notfalls auch das gesamte SPI-Handling als höher > priorisierten Interrupt ausführen. Ich hab mich mal im Datenblatt schlau gemacht. Der SPI-Interrupt ist standardmäßig höher priorisiert als der USB-Interrupt. Es kann allerdings sein, dass die Bibliothek diese Einstellung verändert. Wenn ich aber darauf verzichten würde, nur komplette Pakete per USB weiter zu senden, könnte ich auch auf das Blockieren des SPI-Interrupts während der Laufzeit von Block_Write verzichten. Die von Ralf angesprochene Host-Funktion könnte dabei sehr hilfreich sein, die Pakete im Host wieder zusammen zu bauen. > Aber mit SI_CheckRXQueue(...) bekommst du doch die Anzahl der Bytes, die > ein Device gerade im Buffer hat. Wenn du das vor dem SI_READ(...) > ausführst und die Anzahl der Daten übernimmst, müsste das doch ohne > Fehler gehen? Wer lesen kann ist klar im Vorteil. Würde es am liebsten gleich ausprobieren... aber so kann ich mir das am Wochenende nochmal alles durch den Kopf gehen lassen. VG mario
> Wer lesen kann ist klar im Vorteil.
Ich hoff bloß, dass ich's richtig gelesen hab :) Bzw. die Funktion von
SI_CheckRXQueue richtig verstanden hab.
Ralf
Ja, die Synchronisierung arbeitet wunderbar - manchmal passiert es aber, dass am PC Murks ankommt. Ich versuche mal kurz das System zu erklären: µC: - empfängt Daten per Funk - entfernt Overhead und schreibt die Daten in einen Puffer - kommt an Pin 0.1 ein steigende Flanke wird ein Interrupt ausgelöst und der Puffer per SPI an den USB-Controller gesendet Während des Sendens per SPI sind Interrupts global deaktiviert um Inkonsistenzen auszuschließen. Es kann dann nichts mehr über Funk empfangen werden. USB-Controller: - empfängt über USB Daten vom Host und sendet unmittelbar darauf den "SPIbuffer" an den PC - danach wird der entprechende Pin manipuliert um beim µC einen Interrupt auszulösen, der daraufhin über SPI die Daten sendet Durch die Quasisynchronisation wird sichergestellt, dass währen Block_Read und Block_Write keine Daten per SPI ankommen, die dann verloren gehen würden. Aus diesem Grund kann man das Polling-Intervall um einiges verkürzen. Ich arbeite jetzt mit 15 Millisekunden und komme damit auf rund 270 kbps. Das ganze Funktioniert auch die meiste Zeit. Manchmal scheint es aber, als würden Pakete per SPI unvollständig ankommen. Ich habe deswegen schon die Übertragungsrate gesenkt und eine Pause zwischen den Bytes eingeführt. ~denke aber, dass der USB-Controller trotzdem manchmal falsch detektiert - vielleicht weil die Bibliothek da irgendetwas anderes macht. Das lässt sich ziemlich bescheiden debuggen. Dass die Daten richtig gesendet werden sehe ich am Logikanalysator. Ich werde daher das ganze System nochmal neu aufsetzen - ohne Datenaggregation im µC. Die ankommenden Pakete werden dann einfach als Rohdaten zum Rechner durchgereicht, der die "Netzlogik" dann komplett übernimmt. Das ist zwar mit Aufwand verbunden und ich weiß auch nicht, ob die Probleme dadurch weniger werden, ich denke aber, dass ich mich momentan in einer Entwicklungssackgasse befinde (was das System angeht ;). Durch das Auslagern der Logik auf den PC wird das Übertragungssystem weitaus weniger komplex - das "Spielen" mit Parametern somit wesentlich vereinfacht. Da das ganze ja auch mal bidirektional funktionieren soll, ist das wahrscheinlich die beste Lösung.
Hi Mario, allgemein gesagt freut es mich a) dass die Übertragung jetzt wohl mit der Wunschgeschwindigkeit funktioniert und b) dass du einen Ansatz gefunden hast, der auch ein einfacheres Gesamtsystem ermöglicht. Verwirrend in deiner letzten Antwort ist, dass du einmal zwischen µC und USB-Controller unterscheidest, aber weiter unten quasi offen lässt, wer denn jetzt welcher ist (weiss ich ja) bzw. welcher Pin bei welchem welche Funktion hat :) Da ich aufgrund dieser leichten Verwirrung meinerseits jetzt nicht ganz durchblicke, kann ich bzgl. der erwähnten Buffer-Fehler nur folgenden Vorschlag machen (aus Sicht des F320): Implementiere zwei Buffer im Ping-Pong-Verfahren. Zusätzlich implementierst du eine (Bit-)Variable, die anzeigt, in welchen Buffer geschrieben wird. Einer der Buffer wird in Abhängigkeit der (Bit-)Variablen mit den Daten durch den SPI-Interrupt gefüllt, und zwar nicht-blockierend, wenn nötig SPI-Interrupt hochsetzen. Kein Warten auf irgendwelche Pinzustände, höchstens abfragen. Kommt die Anfrage vom Host, wird die (Bit-)Variable geändert und somit der andere Buffer weiter beschrieben. Ausserdem wird der ursprüngliche Buffer an den Host gesendet. Wie gesagt, kann es jetzt nicht abschätzen, aber das sollte alles Kommunikationsprobleme beseitigen und vor allem verhindern, dass du den SPI-Interrupt sperren musst. Ralf
Hallo Ralf! > Verwirrend in deiner letzten Antwort ist, dass du einmal zwischen µC und > USB-Controller unterscheidest, aber weiter unten quasi offen lässt, wer > denn jetzt welcher ist (weiss ich ja) bzw. welcher Pin bei welchem > welche Funktion hat :) PortPins mit Funktionen gibt es fünf: Vier fürs SPI (P0.0-P0.3) und einen zur Synchronisation (P1.3 am USB Controller = P0.1 am anderen Controller). Mit µC habe ich den CC2431 Transceiver bezeichnet, der per Funk die Daten sammelt. PC <---USB---> USB-Controller <---SPI---> CC2431 < Funk > viele andere CC243x > Da ich aufgrund dieser leichten Verwirrung meinerseits jetzt nicht ganz > durchblicke, kann ich bzgl. der erwähnten Buffer-Fehler nur folgenden > Vorschlag machen (aus Sicht des F320): > > Implementiere zwei Buffer im Ping-Pong-Verfahren. > Zusätzlich implementierst du eine (Bit-)Variable, die anzeigt, in > welchen Buffer geschrieben wird. > Einer der Buffer wird in Abhängigkeit der (Bit-)Variablen mit den Daten > durch den SPI-Interrupt gefüllt, und zwar nicht-blockierend, wenn nötig > SPI-Interrupt hochsetzen. Kein Warten auf irgendwelche Pinzustände, > höchstens abfragen. > Kommt die Anfrage vom Host, wird die (Bit-)Variable geändert und somit > der andere Buffer weiter beschrieben. Ausserdem wird der ursprüngliche > Buffer an den Host gesendet. > Wie gesagt, kann es jetzt nicht abschätzen, aber das sollte alles > Kommunikationsprobleme beseitigen und vor allem verhindern, dass du den > SPI-Interrupt sperren musst. Das war auch mein ursprünglicher Plan - Doublebuffering. Aufgrund des arg beschränkten Arbeitsspeichers des F320 hätte man das Polling-Intervall aber noch mehr verkürzen müssen. Den SPI-Interrupt lasse ich momentan auch an... die USBXpress-Bibliothek schaltet offenbar aber Interrupts global ab. Wenn das nicht wäre, hätte ich keine Probleme. Die Synchronisation der beiden Controller klapp von der Sache her ganz gut. Problem ist jetzt nur noch, dass der USB-Controller manchmal etwas anderes empfängt, als ihm auf dem SPI-BUS gesendet wurde - aber auch erst, seitdem ich synchronisiere - keine Ahnung warum. Vielleicht sollte SPI vor der USB-Abarbeitung übertragen statt danach. Das ist aber 'ne Sache für sich und hat nichts mit dem eigentlichen Problem zu tun. Fakt ist jedenfalls, dass bei USBXpress (zumindest bei der IAR-Portierung) die Nettodatenrate durch den beschränkten RAM, die blockierenden Funktionen und den Bulk-Transfer auf etwa 1,5 Mbps beschränkt ist. Hängen noch andere Systeme dran (der USB-Controller quasi als Repeater) halbiert sich diese Datenrate schlimmstenfalls nochmal. Durch meine unsaubere Umsetzung (da ich anfangs noch dachte mit USB-Datenrete verschwenderisch umgehen zu können), hat sie sich noch weiter verringert - zu weit. Deine Hilfe und die von Peter haben mir die Augen geöffnet. USBXpress ist ansich 'ne schöne Sache - für meinen Fall aber grenzwertig. Mit einer sauberen Umsetzung wirds aber gehen. Ich schreibs hier rein, wenn es einwandfrei läuft. Vielen Dank nochmal mario
Okay, dann werd ich jetzt mal bis auf weiteres mein Hirn zu dem Thema abschalten :) Freut mich, wenn ich helfen konnte. Ralf
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.