Hallo, ich bin neu hier im Forum, und habe mich angemeldet weil ich das
erste mal ein Problem mit meinem Microcontroller habe, das ich selbst
durch mehrwöchiges suchen nach Infos nicht lösen konnte:
Ich habe mir ein par AT90USB162 gekauft, um ein par Projekte mit USB
Schnittstelle umzusetzen, ich habe mir das Datenblatt durchgelesen, das
erste Programm geschrieben und hochgeladen, nach dem es ein par Fehler
gab hab ich ein par Beispiele im Internet gesucht und die Fehler auch
beheben können.
Allerdings gibt es einen Fehler, den ich einfach nicht behoben bekomme:
Die Endpoint Interrupts (USB_COM_vect) werden einfach nicht aufgerufen.
Mein AT90USB wird von Windows als USB Gerät erkannt, die generellen USB
Interrupts werden korrekt aufgerufen und der USB Controller + Endpunkte
konfiguriert, aber nach einigen Sekunden sagt Windows, das der AT90
nicht auf die Anforderung einer Gerätebeschreibung reagiert hat (SETUP
Packet ist wurde nicht beantwortet).
Ich habe auf alle erdenklichen arten und weisen versucht das RXSTPI Bit
abzufragen, Ergebnis: es wird nie gesetzt, und auch sonst werden keine
USB_COM_vext Interrupts ausgelöst, mit dem Oszilloskop hab ich aber
prüfen können, das (zumindest vom Computer/Host aus) Daten an den uC
gesendet werden.
Ich habe ein kurzes Programm geschrieben was zumindest die
Endpunktkonfiguration und die beiden Interrupt Vektoren implementiert,
eventuell kann mir einer weiterhelfen:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
#define LED_1 PD4
5
#define LED_2 PD5
6
7
ISR(USB_COM_vect,ISR_BLOCK)
8
{
9
uint8_tepint=UEINTX;
10
UEINTX=0;
11
if(epint&(1<<RXSTPI))
12
{
13
PORTD|=(1<<LED_2);
14
}
15
}
16
17
ISR(USB_GEN_vect,ISR_BLOCK)
18
{
19
uint8_tuint=UDINT;
20
UDINT=0;
21
if(uint&(1<<EORSTI))
22
{
23
24
UENUM=0;
25
UECONX|=(1<<EPEN);
26
UECFG0X=0;
27
UECFG1X=16;
28
UECFG1X|=(1<<ALLOC);
29
while(UESTA0X&(1<<CFGOK)==0);
30
31
PORTD|=(1<<LED_1);
32
33
}
34
}
35
36
intmain(void)
37
{
38
39
DDRD|=(1<<LED_1)|(1<<LED_2);
40
41
PLLCSR|=(1<<PLLE);
42
PLLCSR&=~(1<<PLLP2);
43
PLLCSR&=~(1<<PLLP1);
44
PLLCSR&=~(1<<PLLP0);
45
while((PLLCSR&(1<<PLOCK))==0);
46
USBCON|=(1<<USBE);
47
USBCON&=~(1<<FRZCLK);
48
UDCON&=~(1<<DETACH);
49
50
sei();
51
UDIEN|=(1<<EORSTE);
52
UEIENX|=(1<<RXSTPE);
53
54
while(1)
55
{
56
if(UEINT&(1<<RXSTPI))PORTD|=(1<<LED_2);
57
}
58
59
}
Verhalten: LED 1 leuchtet auf sobald der das Gerät eingesteckt wurde,
und der Endpunkt konfiguriert wurde, LED 2 sollte aufleuchten sobald das
erste SETUP-Paket eingetroffen ist, tut sie aber nicht (für Testzwecke
hab ich 2 verschiedene Abfragen eingebaut, in der main loop und im
Interrupt).
Fehler von der Elektrischen Seite hab ich schon ausgeschlossen, alles
mehrfach mit Oszilloskop und Multimeter durchgemessen, Daten kommen an
und Leitungen sind korrekt angeschlossen, nach USB Norm und AT90USB
Datenblatt.
Ich hoffe hier kann mir jemand helfen.
Marvin K. schrieb:> Mein AT90USB wird von Windows als USB Gerät erkannt, die generellen USB> Interrupts werden korrekt aufgerufen und der USB Controller + Endpunkte> konfiguriert, aber nach einigen Sekunden sagt Windows, das der AT90> nicht auf die Anforderung einer Gerätebeschreibung reagiert hat (SETUP> Packet ist wurde nicht beantwortet).
Ich sehen in dem Code oben keine korrekte Implementation des
nicht-trivialen EP0, über den alle Desktriptoren abgerufen werden.
Ein Code 43 ist dann die normale Reaktion von Windows.
Beitrag "Re: AT90USB162 Endpoint Interrupts funktionieren nicht"
(Ich weis nicht ob ich das mit dem Verweisen auf einen Beitrag richtig
gemacht hab)
Ich nutze einen 8MHz Quartz, laut dem Datenblatt des uCs müsste ich die
PLLP0-PLLP2 Bits des PLL Registers dann auf 000 setzen, ich habe das im
Beispiel in 3 einzelnen Zeilen gemacht, da ich die beiden verschiedenen
Einstellungen getestet hab, man könnte es aber auch in eine Zeile
schreiben oder weg lassen (000 ist Standart soweit ich weis).
Beitrag "Re: AT90USB162 Endpoint Interrupts funktionieren nicht"
Ich konfiguriere EP0 doch im USB_GEN_vect Interrupt, oder hab ich da was
falsch verstanden?
1
UENUM=0;// EP0 Anwählen
2
UECONX|=(1<<EPEN);// EP0 Aktivieren
3
UECFG0X=0;// Controll-EP
4
UECFG1X=16;// 16 Byte, one Bank
5
UECFG1X|=(1<<ALLOC);// Allocate memory
6
while(UESTA0X&(1<<CFGOK)==0);// Warten auf "CFGOK"
Ich habe hier die Fehlererkennung wenn das setzen des ALLOC Bits
fehlschlägt weggelassen, damit der Code übersichtlich bleibt, und die
aktuelle Konfiguration scheint ja auch zu Funktionieren (CFGOK wird
gesetzt).
Und ich hab auch schon verschiedene Konfigurationen für UECFG1X
ausprobiert, diese hier hab ich aus einem Beispiel-Code von GitHub.
Wenn ich hier was falsch habe, wäre das schonmal ein großer Vorschritt,
ich finde nämlich kaum Infos zum konfigurieren der Endpunkte, das ist
das einzige was ich finden konnte.
Marvin K. schrieb:> Ich konfiguriere EP0 doch im USB_GEN_vect Interrupt, oder hab ich da was> falsch verstanden?
ja und die LED1 geht ja auch an wie du selbst schreibst. Es gibt aber
keinerlei Code für die Chapter9 Requests.
Du must mindestens GetDescriptor(Device und Config), SetAddress() und
SetConfig implementieren, zusätzlich ist es hilfreich den USB Reset
auszuwerten und dort alle wichtigen Variablen zurücksetzen.
Solange das nicht implementiert ist enumeriert nichts. Wo sind den deine
Deskriptoren?
Der Ablauf unter Win ist etwa folgender
- UsbReset
- GetDescriptor(Device)
- UsbReset
- SetAddr()
- GetDescriptor(Device)
- GetDescriptor(Configuration)
- SetConfig()
Ich weis, das hab ich aber in diesem Beispiel weg gelassen, wie ich oben
schon geschrieben habe, das Problem ist das die USB_COM_vect Interrupts
nicht funktionieren, ich kann diese Requests ja nicht einfach wahllos
senden, sondern muss auf das SETUP des Hosts warten, ich empfange aber
keins -> LED 2 leuchtet nicht.
nun das Datenblatt sagt
CONTROL endpoints should not be managed by interrupts, but only by
polling the status bits
Das hast du wohl auch probiert aber die EP Nummer nicht auf 0 gestellt.
Ich muss ehrlicher weise zugeben dass ich kein ATMega Profi bin. Der
Initialisierungsteil sieht aber für mich ok aus, auch wenn die magic
numbers nicht so mein Ding sind.
Dann bleibt natürlich noch D+ und D- vertauscht als Fehler Quelle oder
eine fUSB != 48Mhz. Wobei ich sagen würde die PLL passt für 8 MHz und
ext. Quarz
Edit: Muss da nicht irgendwo der Usb Speicherblock eingestellt werden.
So kenne ich das jedenfalls von anderen Chips.
Also, egal was ich bisher gemacht habe, ich habe noch keinen einzigen
Endpoint Interrupt zum auslösen gebracht (sowohl USB_COM_vect, als auch
die Bits im Register).
Und was meinst du mit Speicherblock ?
Ich kenne nur die Einstellung ob es eine "one Bank" oder eine "double
Bank" ist, da ich bisher nicht wirklich rausfinden konnte, was damit
überhaupt gemeint ist, hab ich es wie in allen Beispielen die ich bisher
gefunden hab auch, bei "one Bank" belassen.
Thomas Z. schrieb:> nochwas 16 Byte EP0 Fifo ist nicht so üblich ich mach immer 8 Bytes.
Sicher?
Ich habe hier nur Code für die größeren USB-AVRs, aber da habe ich 16
Byte für den Interrupt-EP (der bei CDC zwingend vorhanden sein muss,
auch wenn er nichts macht) und 64 Byte für alle anderen EPs.
Auf Anhieb sehe ich jetzt auch nichts. Ich gehe mal davon aus, dass die
PLL einrastet, weil ansonsten auch die erste LED wohl nicht angehen
sollte.
Jörg W. schrieb:> Sicher?
ja ganz sicher BULK EPs sind immer 64Byte das ist sogar in der Spec für
fullspeed vorgeschrieben. Control mach ich immer 8 Bytes, den unnützen
Interrupt EP bei CDC auch. Das vor allem weil bei den meisten Chips nur
begrenzt Fifo Ram vorhanden ist.
Das macht zwar den GetDescriptor Request etwas langsamer weil ev.
mehrere DataStages notwendig sind aber damit kann ich leben. Oft werden
64Bytes für den Control Ep nur dehalb verwendet, weil die FW nicht mit
mehren DataStages korrekt umgehen kann.
@Marvin
OneBank / TwoBank heist bei anderen Chips double buffer.
Zum Speicher siehe 19.6 Memory management.
Thomas Z. schrieb:> Oft werden 64Bytes für den Control Ep nur dehalb verwendet, weil die FW> nicht mit mehren DataStages korrekt umgehen kann.
Nö, das funktioniert bei mir schon, irgendeine der SETUP-Geschichten
passt auch in 64 Byte nicht mehr direkt rein.
Andererseits haben die großen USB-AVRs deutlich mehr FIFO. Die kleinen
haben nur 176 Bytes, wenn man 2 x 64 für die Daten-Endpunkte abzieht,
bleiben nur noch 48 für den Rest. 8 verplempert man für den
Interrupt-EP, damit kann der Control-EP aber trotzdem noch 16 oder 32
Byte groß sein.
Double buffering fällt bei dem bissel FIFO sowieso aus.
while(UESTA0X&(1<<CFGOK)==0);// Warten auf "CFGOK"
24
25
PORTD|=(1<<LED_1);
26
27
}
28
}
29
30
intmain(void)
31
{
32
33
DDRD|=(1<<LED_1)|(1<<LED_2);
34
35
PLLCSR=
36
PLLCSR|=(1<<PLLE);
37
while((PLLCSR&(1<<PLOCK))==0);
38
USBCON|=(1<<USBE);
39
USBCON&=~(1<<FRZCLK);
40
UDCON&=~(1<<DETACH);
41
42
sei();
43
UDIEN|=(1<<EORSTE);
44
UEIENX|=(1<<RXSTPE);
45
46
while(1)
47
{
48
UENUM=0;
49
if(UEINT&(1<<RXSTPI))PORTD|=(1<<LED_2);
50
}
51
52
}
Aber es hat sich nichts geändert, ich hab auch schon alle möglichen EP0
FIFO Größen ausprobiert, und auch schon diverse andere Einstellungen
variiert, es bleibt dabei das weder ein Interrupt noch das RXSTPI Bit
gesetzt wird, ich auch schon D+/D- getauscht um diesen Fehler
auszuschließen.
Ich habe übrigens auch mit dem Windows Tool USBView mal versucht ein par
Infos zu erhalten, es sagt allerdings nur FailedEnumeration und ERROR No
open Pipses, kann das mit dem Endpunkt zusammenhängen, oder liegt das
nur an dem Fehlenden SETUP Package ?
USBView Ausgabe als Bild im Angang.
Die Ausgabe ist immer identisch, egal ob ich die Requests implementiere
oder nicht, oder welchen Code ich verwende.
Nicht wirklich, ich kann kein Chinesisch (Übersetzen geht nicht, das
sind offenbar Bilder), und die anderen Links führen alle zu "404 Seite
nicht gefunden" ...
Ich wollte mich eigentlich nicht mit LUFA beschäftigen, ich habe es mal
ausprobiert, und ca 500 Fehlermeldungen über nicht vorhandene
Definitionen und Fehlende Dateien bekommen (hab eines der Beispiel
Projekte geöffnet).
Generell war mein Ziel eigentlich mir selber eine minimalistische
Bibliothek für diverse USB Projekte erstellen wollte.
Marvin K. schrieb:> Generell war mein Ziel eigentlich mir selber eine minimalistische> Bibliothek für diverse USB Projekte erstellen wollte.
Das ist an sich auch kein schlechter Ansatz. Habe ich damals in μracoli
auch gemacht, nachdem ich mir andere Beispiele angesehen habe und als zu
komplex fand.
Muss heute Abend mal schauen, ob ich für die kleinen AVRs noch was
finde.
Schau mal, das hier habe ich noch gefunden. Das stammt von
https://www.circuitben.com/node/4
(Das entsprechende Interface hatte ich mir damals für meinen Tek492
gebaut.)
Die Funktionen read_reg() und write_reg() gehen auf den
Mikrocontroller-Bus des Tek492, den man auf diese Weise über USB (über
ein vendor class device) zugreifen kann.
Das alles sollte doch klein und fein genug sein, als Basis für
Experimente zu dienen, denke ich mal. Ich habe auch noch ein kleines
Devboard mit einem AT90USB162 da liegen. Falls du nicht weiter kommst,
kann ich damit auch ein wenig spielen.
Ich werde das morgen mal Ausprobieren.
Ich hätte da noch ne kure Frage, die nur indirekt mit dem Problem zu tun
hat, ich wollte gerade mal einen Schaltplan in KiCad erstellen von dem
aktuellen Aufbau mit dem AT90USB, allerdings hab ich eine verbuggte
globale Bibliothek die das Importieren meiner ganzen Bauteile (Darunter
der AT90) verhindert, weis einer wie man Bibliotheken in KiCad löscht
(finde dazu nichts im Internet) ?
Erstens kannst du sie natürlich über Preferences -> Manage Symbol
Libraries warten. Zweitens kannst du auch ganz brutal mit dem File
Manager die entsprechende Datei aus dem Weg räumen. Das gibt dann 'ne
Warnung, aber danach geht es weiter.
Danke, ich hab es dauernd über diesen Bibliothekseditor versucht, aber
der dient wohl nur zum Anzeigen der Bibliotheken, und die Datei löschen
geht nicht, da ich keine Datei habe, das ist das Problem mit der
Bibliothek, die lag auf einer Festplatte die nicht mehr Existiert.
Ich konnte sie aber über die Einstellungen löschen.
Ich habe eben mal den Code (usb_429) auf den AT90 geladen, hat ohne
Probleme geklappt. Ich hab es einfach mal am PC eingesteckt, es wurde
wieder nicht erkannt, mir ist schon klar das ich wahrscheinlich ein par
Anpassungen vornehmen muss, ich wollte nur mal testen ob was passiert.
Und eine Sache hat sich verändert, ich weis aber nicht ob das was zu
bedeuten hat:
USBView zeigt jetzt etwas mehr Infos an, es sagt jetzt
"Companion Port Number: 10"
und
"Companion Hub Symbolic Link Name: USB#ROOT_HUB..."
Bei meinen vorherigen Versuchen waren diese Felder immer 0 oder gar
nicht Vorhanden.
Marvin K. schrieb:> USBView zeigt jetzt etwas mehr Infos an, es sagt jetzt> "Companion Port Number: 10"> und> "Companion Hub Symbolic Link Name: USB#ROOT_HUB..."
das ist weil u nun einen anderen Port benutzt und hat nichts zu sagen.
Ich gehe dvon aus das der Code von Jörg auch ohne Änderungen läuft.
Du hast ein HW Problem (kaputtes Kabel, falsche Verbindung, D+, D-
vertauscht)
Ich glaube auch das es irgend was mit der Hardware zu tun hat, da ich
noch weiter AT90USB habe, werde ich später mal einen anderen testen, ich
bezweifle nämlich das einer der Der Wiederstände oder Kondensatoren
einen Fehler hat (habe ja mit dem Multimeter mal alle Spannungen und mit
dem Oszilloskop D+ und D- gemessen).
Ansonsten zeigt der Code auch nach dem ich alle Vendor Requests und I/O
Pins deaktiviert habe (so das nur noch der SETUP und Request Teil
läuft), exakt das selbe verhalten, bis zum USB_GEN_vect EORSTI läuft
alles, aber das RXTSPI Bit wird nicht gesetzt.
Mir ist auch aufgefallen das der Setup Teil hier über das USB_COM_vect
Interrupt gehandelt wird, ich dachte das sollte sp nicht sein.
Ich zeichne jetzt wo ich meine KiCad Bibliothek laden konnte mal kurz
einen Schaltplan von meinem Aufbau, eventuell liegt da ja ein Fehler den
ich nicht finde.
Ich hab meinen Versuchsaufbau mal als Schaltplan gezeichnet, alles ist
auf einem Steckbrett aufgebaut, und mit Jumper-Kabeln verbunden.
Ich konnte durch Messungen bisher keine Elektrischen Fehler feststellen,
aber
2 Besonderheiten sind zu beachten:
1. Ich hatte keinen 22 Ohm Wiederstand für die D+/D- Leitungen, und habe
daher 2 11 Ohm Wiederständer genommen, sollte aber eingendlich kein
Problem sein, oder ?
Beide Leitungen haben jetzt einen Wiederstand von 20 Ohm (Habe durch
Messungen mit einem Multimeter versucht, zumindest gleiche Werte durch
Variieren der Wiederstände zu bekommen, auf 22 Ohm hab ich es nicht
bekommen).
2. Der AT90USB162 ist nicht in einem DIL/DIP Gehäuse erhältlich, ich
habe eine Adapterplatte gefräst und ihn aufgelötet.
Ich habe alles durchgemessen und die Kontakte sind soweit ich das sagen
kann alle in Ordnung, nur ein I/O Pin hatte ein Problem (Beschädigte
Lötstelle), aber den benutze ich in der Schaltung nicht.
Ein Annotationsfehler hat die Wiederstandswerte überschrieben, ich
musste den Schaltplan neu hochladen, allerdings hab ich nicht
rausgefunden wie ich den Fehlerhaften lösche.
Die Widerstände sind nicht besonders kritisch. Kritischer würde ich
sehen dass nicht alle Gnds und Vcc angeschlossen sind. Aber das müssen
Leute kommentieren die sich besser mit AVR auskennen.
Thomas Z. schrieb:> Kritischer würde ich sehen dass nicht alle Gnds und Vcc angeschlossen> sind.
Sie müssen alle angeschlossen und alle abgeblockt sein – am besten
gleich auf der Adapterplatine. Kleine SMD-Cs lassen sich direkt zwischen
die Pins löten.
Mir ist auch gerade nicht klar, ob das nun "bus-powered" oder
"self-powered" sein soll. Die entsprechenden grundsätzlichen
Applikationsschaltungen finden sich im Datenblatt, mit Varianten für
unterschiedliche Versorgungsspannungen.
Leider gibt's für das "Minimus AVR USB"-Board, welches ich habe, keine
Schaltpläne und auch nur noch eine historische Version der Webseite:
https://web.archive.org/web/20140105020019/http://www.minimususb.com/
Ich ich habe alle VCC und GND abgesehen von den für die Analog Sachen
angeschlossen, ich habe gerade bemerkt das da noch ein Fehler im
Schaltplan ist (UGND nicht angeschlossen).
Ich habe gerade mal die Adapterplatte mit dem AT90USB vom Steckbrett
entfernt, und alle Löstellen neu angelötet, ich habe vorher und nachher
die Wiederstände gemessen, und keine wirkliche Änderung festgestellt.
Alle bei ~0 Ohm (ein Standard Multimeter ist halt auch nicht so genau,
denke ich mal)
Ich habe den Chip wieder eingebaut, und nochmal mit dem PC verbunden,
dieses mal wurde er erkannt, beide LEDs leuchten und USBView zeigt die
Descriptoren an.
Ich weis nicht was das Problem war und was es behoben hat, aber ich
vermute mal ein Wackelkontakt bei einem der Pins, der durch die
Messspitze des Multimeters immer zusammengedrückt wurde, und daher bei
der Messung immer als OK durch ging.
Ich werde jetzt nochmal meinen original Code drauf spielen, mit eigenen
Descriptoren und Requesthandler.
Interesant, laut USBView hängt mein Code nach dem ersten Descriptor.
Es wartet auf den nächsten und zeigt "Enumerating" an, ich hätte nicht
gedacht das Windows so eine Geduld hat und jetzt bestimmt schon 20
Sekunden wartet, bis es einen Fehler anzeigt.
Auf jeden fall funktioniert jetzt die Hardware, ich werde mich dann mal
weiter mit dem Code beschäftigen, und diesen Fehler beheben.
Mein Code läuft jetzt übrigens wie auch das Beispiel "usb_429" (ich weis
leider nicht den richtigen Name des Projektes) komplett über Interrupts,
also auch die Setup Requests, auch wenn es laut USB Spezifikation nicht
gewollt ist, scheint es problemlos zu funktionieren.
Marvin K. schrieb:> Ich ich habe alle VCC und GND abgesehen von den für die Analog Sachen
Auch AVcc muss angeschlossen sein. Dient bei diesem AVR insbesondere
auch der Spannungsversorgung der PLL.
Also, die Hardware funktioniert jetzt, aber beider Software macht jetzt
nichts sinn.
Der Beispielcode funktioniert, aber selbst wenn ich nur ein par
konstanten verschiebe, nicht ändere nur z.B. ganz oben im Code sammle,
funktioniert es nicht mehr (es kompiliert und lässt sich aufspielen,
aber der AT90 wird dann nicht mehr erkannt).
Es wäre mir neu das das ändern der reinfolge der Konstanten eine
änderung ihres wertes zur folge hat (ich rede von einfach Konstanten wie
1
#define INTF_SIZE 9
).
Ich werde morgen nochmal von Grund auf neu anfangen, und versuchen zu
verstehen was da vor sich geht.
Diese Einstellung kenne ich nicht, wo finde ich das den, und was bewirkt
es ?
Ich hab den Code jetzt so weit, das ich die Requests empfange und
auslesen kann (auch schon getestet, Daten werden richtig übertragen, ich
empfange einen GET_DESCRIPTOR request).
Aber wenn ich dann antworte, und den DeviceDescriptor übergebe, bekommt
ich nur immer wieder einen USB Reset vom host, das widerholt sich ca 4-5
mal, dann bricht er ab und es kommt wieder "USB Gerät nicht erkannt".
USBView zeigt wieder überall 0 an, wobei ich nicht weis ob es überhaupt
was anderes anzeigen würde bevor nicht ALLES korrekt übertragen wurde.
Was kann da die Ursache sein ?
Die Daten werden vom AT90 aus korrekt gesendet, ich hab es schon
getestet, hier ist mein Code der das senden der Descriptoren übernimmt:
Die Abfolge ist:
USB Reset
- Get Descriptor (Device)
USB Reset
- Get Descriptor (Device)
USB Reset
- Get Descriptor (Device)
USB Reset
- Get Descriptor (Device)
Abbruch -> Gerät nicht erkannt
Immer 4 mal (gerade durch einen Zähler ca. 10 mal geprüft)
Marvin K. schrieb:> Die Abfolge ist:>> USB Reset> - Get Descriptor (Device)> USB Reset> - Get Descriptor (Device)> USB Reset> - Get Descriptor (Device)> USB Reset> - Get Descriptor (Device)> Abbruch -> Gerät nicht erkannt>> Immer 4 mal (gerade durch einen Zähler ca. 10 mal geprüft)
D.h. einfach: Das Device ist nicht in der Lage, seinen Discriptor
verständlich rauszuballern. Windows versucht das vier mal, dann gibt es
auf, weil nur Bullshit (oder garnix) als Ergebnis des Requests kam.
Mit Linux als Host würde das Spiel genau so laufen, bloß die Zahl der
Wiederholungen wäre möglicherweise anders.
Was soll ein OS auch anderes tun, wenn das Device so blöd ist, dass es
nicht mal die grundlegendsten Requests korrekt beantworten kann?
Ja, ich weis wie das OS da reagiert, meine Frage ist ja ob jemand
erkennt warum das so ist, ich hab den Code ja eingefügt.
Ich habe zum Test mal Stadt in den UEDATX in PORTD geschrieben, und ein
delay eingefügt, und mir 8 LEDs angeschaut die an PORTD hängen.
Sie stimmten überein mit dem Descriptor den ich geschrieben hab, und der
wiederum stimmt mit den USB Normen überein, also, wo ist hier das
Problem ?
Hab ich vergessen wärend des Sendens irgend ein Bit zu setzen oder so ?
Marvin K. schrieb:> Diese Einstellung kenne ich nicht, wo finde ich das den, und was bewirkt> es ?
Dass der Code in vernünftiger Geschwindigkeit abgearbeitet wird und
nicht in Zeitlupe.
> Was kann da die Ursache sein ?
Eben beispielsweise Timing-Probleme.
> Die Daten werden vom AT90 aus korrekt gesendet, ich hab es schon> getestet
Womit hast du das denn getestet?
Wenn du mir einen compilierbaren Code gibst (also nicht nur Schnipsel),
kann ich das hier auf meinem Demoboard mal nachvollziehen.
Ich hab den Fehler gerade gefunden, er war sowas von dämlich -.-
Ich hab im "typedef struct" Bereich vom Descriptor an einer stelle stadt
uint16_t uint8_t genutzt, weshalb der Descriptor 1 Byte zu kurz war, und
abgelehnt wurde, ich hab es korrigiert jezt wurde er erkannt und wird in
USB View angezeigt.
Ich hab mich wahrscheinlich vertippt als ich den Aufbau aus der USB
Spezifikation abgetippt hab und so ein Fehler fällt halt kaum auf
zwischen den ganzen uint8_t und uint16_t ...
Na, das ist doch mal was.
Den Knopf für die Compileroptimierung solltest du trotzdem noch finden.
Auf der Kommandozeile wäre das die Option -O1 oder -Os, aber vermutlich
wirst du wohl irgendeine IDE benutzen, die den Compiler für dich
aufruft.
Endlich, es kommt keine "USB Gerät nicht erkannt Meldung", das ist das
erste mal das einer meiner Codes funktioniert. xD
Jetzt muss ich nur noch die ganzen Descriptoren und Requests
implementieren die noch Fehlen, vieles in USB View ist deshalb noch mit
"ERROR" markiert.
Ich werde gleich noch nach dieser Compiler Option suchen, ich denke mein
Problem mit den Interrupts und dem AT90 ist jetzt gelöst.
Aber weis eigentlich jemand was es mit dieser vendorId auf sich hat?
Ich habe gelesen das die von USB Org vergeben wird, was sollte man den
da nehmen wenn man kein "offizieller Hersteller" ist ?
Marvin K. schrieb:> Ich nutze Atmel Studio 7 bzw. Microchop Studio 7
Da stellt man das in den Projektoptionen unter dem Unterpunkt Toolchain
ein. Vorsicht: es gibt zwei Stellen für Optimierungsoptionen, Compiler
und Linker. Im konkreten Fall dürften allerdings nur die
Compilereinstellungen relevant sein. Wenn überhaupt...
Denn: auf die Interrupt-Performance hat das eher wenig Einfluß. Die ist
ohne Optimierung ganz grausam und mit -02 immer noch sehr armselig.
Asm rules!
Hm, wenn ich das einschalte (option -O2) wird mein AT90 nicht mehr
erkannt und es kommt wieder nur schrott an (Device Descriptor wird
abgelehnt).
Betrifft diese Option in irgend einer Form daten die im Programmspeicher
abgelegt sind ?
Ich habe den Descriptor mit __attribute__((packed)) im PROGMEM
abgelegt.
Marvin K. schrieb:> Aber weis eigentlich jemand was es mit dieser vendorId auf sich hat?> Ich habe gelesen das die von USB Org vergeben wird, was sollte man den> da nehmen wenn man kein "offizieller Hersteller" ist ?
Solange du das Ergebnis nur für dich selber benutzt, spielt das keine
Geige.
Wenn du es aber in irgendeiner Form anderen zugänglich machen willst,
musst du in den sauren Apfel beissen und die Kohle an die Wegelagerer
abdrücken. Da führt praktisch kein Weg dran vorbei.
Für die rein private Nutzung kann man "abandoned" VendorIDs verwenden.
Da ist man ziemlich sicher, dass einem irgendein Treiber eines "legalen"
Gerätes irgendwann unerwartet dazwischen pfuscht.
Interesant, mit "optimize most (-O3)" geht es wieder.
Was sollte ich den nehmen?
Ich meine, bisher hat es auch mit der Standartoption "Optimize debugging
experience (-Og)" funktioniert.
Marvin K. schrieb:> Aber weis eigentlich jemand was es mit dieser vendorId auf sich hat?> Ich habe gelesen das die von USB Org vergeben wird, was sollte man den> da nehmen wenn man kein "offizieller Hersteller" ist ?
Da musst du dir was aus den Fingern saugen. Vielleicht einen Hersteller
wählen, der inzwischen zurückgezogen hat.
Für die Vendor ID lediglich 16 Bits vorzusehen, ist eins der größten
Gurken, die sich USB geleistet hat – zumal zu der Zeit, als sie das
verbrochen haben, das Problem zur Neige gehender IPv4-Adressen schon
längst auf dem Tisch lag. Es hätten wohl drei Finger genügt um
abzuzählen, dass 65000 Hersteller weltweit ganz schnell erreicht sein
werden.
Anfangs konnte man eine Vendor-ID noch für ein überschaubares Sümmchen
"Verwaltungsgebühr" einkaufen, sollen am Anfang wohl USD 500 gewesen
sein, lange Zeit waren es USD 1000. Wurde dann immer teurer.
Um das Übel für Kleinanwender/-hersteller (die im USB-IF halt keine
Fürsprecher groß haben) noch zu verschlimmern: zu Zeiten, da der Preis
noch moderat war, gab es ein paar Leutchen, die sich eine Vendor-ID
erkauft haben und dann ein Mini-Geschäft damit aufgebaut haben, von
dieser Vendor-ID Product-ID-Bereiche für kleines Geld weiter zu
verkaufen. Denen hat das USB-IF unter Androhung juristischer
Konsequenzen ihr Tun untersagt. (Ob sie diese Konsequenzen bspw. in
Europa juristisch überhaupt hätten durch bekommen, angesichts dessen,
dass sie ja die ID offiziell nicht verkaufen sondern "nur" eine
"Verwaltungsgebühr" erheben, ist fraglich. Aber eine derart kleine Firma
lässt es da halt nicht drauf ankommen.)
Marvin K. schrieb:> Interesant, mit "optimize most (-O3)" geht es wieder.
Muss eigentlich mit jeglicher Optimierung zum Laufen zu bekommen sein,
nur -O0 (Optimierung ausgeschaltet) ist fragwürdig.
Ich denke, du hast da noch irgendeine andere Sache drin.
Marvin K. schrieb:> Ich habe den Descriptor mit attribute((packed)) im PROGMEM abgelegt.
Das Attribut kannst du dir bei einem AVR klemmen. Das ist ein
8-Bit-Prozessor, der hat keine Anforderungen an das Alignment, sodass
alle structs immer "packed" sind.
Marvin K. schrieb:> Hm, wenn ich das einschalte (option -O2) wird mein AT90 nicht mehr> erkannt und es kommt wieder nur schrott an (Device Descriptor wird> abgelehnt).
Dann hast du einen "Bug" im Code. Irgendwelchen Kram, der nach der
Reinen Lehre verzichtbar ist und deswegen rausoptimiert wird.
Typisch wären irgendwelche handgestrickten Warteschleifen oder etwas in
der Art. Aber auch UB sorgt immer mal wieder für nette Überraschungen.
Auch wieder: Asm rules. Damit kann man bessere Performance erzielen und
muss sich nicht mit mehr oder weniger überraschenden
Optimierungsergebnissen eines abgehobenen Compilers rumschlagen. Wenn da
was optimiert wird, dann macht man das selber. An den Stellen, wo
tatsächlich optimiert werden muss und nur dort.
c-hater schrieb:> Auch wieder: Asm rules.
Ja klar.
Dann wäre er allerdings wahrscheinlich jetzt noch bei der Vorrede statt
schon irgendwas zu haben, was am USB mitredet. ;-)
> Irgendwelchen Kram, der nach der Reinen Lehre verzichtbar ist und> deswegen rausoptimiert wird.
Sowas simples wie ein vergessenes "volatile" wird es nicht sein. Er
hatte ja zuvor -Og, nicht -O0.
Mutmaßen kann man viel. Wenn ich compilierbaren Code bekomme, schau ich
mir das mal an (wenn's sein muss, finde ich auch einen Zugang zu einem
USB-Analyzer). Atmel-Studio-Dateien brauch' ich nicht, benutze ich
sowieso nicht. Ein Makefile wäre schön, wenngleich das vom Studio
generierte erfahrungsgemäß grauenvoll ist.
Ich mache den Code erstmal soweit fertig das meine ganzen USB Sachen
funktionieren, mit -Og funktioniert es ja, wenn das klapt, lade ich den
Code mal hoch, es kann gut sein das gerade noch unnötiger Kram drin ist,
weil ich an diversen Stellen Debug-Warteschleifen oder ähnliches drin
hab.
z.B. wenn die Adresse gesetzt wurde, zeigt es das mit einer LED an und
wartet eine halbe Sekunde.
Solche Sachen entferne ich jetzt halt nach und nach wenn ich weis das
alles funktioniert.
Hä, ich habe gerade mal alle Descriptornafragen abgefangen die nicht
behandelt wurden, weil kein entsprechender Descriptor implementiert ist,
Windows fragt nach dem Descriptor mit der ID 0x06, es gibt aber keinen
Descriptor mit 0x06 als ID oder ?
Ich hab jetzt
DEVICE 0x01
CONFIG 0x02
STRING 0x03
INTERFACE 0x04
ENDPOINT 0x05
(Hab die Zahlen gerade aus dem Gedächtnis aufgeschrieben, kann sein das
was vertauscht ist)
Marvin K. schrieb:> z.B. wenn die Adresse gesetzt wurde, zeigt es das mit einer LED an und> wartet eine halbe Sekunde.
Wenn du in der Zeit wirklich wartest, kann das für USB schnell tödlich
sein.
Der Host bekommt ganz schnell mal "kalte Füße", wenn da am anderen Ende
keiner mehr reagiert. Zwar deckt der USB-Makro im Controller schon
manches der zeitkritischen Dinge ab (indem er bspw. ein NAK sendet, wenn
er noch keine neuen Infos von der Software hat), aber ganz allgemein
gilt, dass man bei einer USB-Firmware "zeitnah" reagieren können sollte.
Aus dem Grunde ist es auch unpraktikabel, bei so einer Firmware groß mit
dem Debugger ranzugehen: sowie du einen Breakpoint erreicht hast,
schreibt der USB-Host das Device dann ab, weil es nicht mehr reagiert.
Wie eben gesagt: Ich entferne die sachen jetzt nach und nach wenn ich
weis das alles funktioniert.
Das mit dem warten wenn die Adresse gesetzt wurde, war ja z.B. nur weil
ich bisher nichts weiter implementiert hatte, jetzt wo ich weitere
Sachen danach einbaue, kommt das natürlich weg.
Was ich aber festgestellt hab, was mich sehr verwundert hat:
Als ich eine Warte zeit beim senden der Daten hatte, um sie mir am PORTD
ausgeben zu lassen, hat es Windows nicht gestört als ich zwischen den
Bytes teilweise bis zu 500ms Wartezeit hatte, ich hätte da mit einem
Abbruch gerechnet.
Scheinbar verkraftet Windows so große Wartezeiten manchmal sogar.
Marvin K. schrieb:> Hä, ich habe gerade mal alle Descriptornafragen abgefangen die nicht> behandelt wurden, weil kein entsprechender Descriptor implementiert ist,> Windows fragt nach dem Descriptor mit der ID 0x06, es gibt aber keinen> Descriptor mit 0x06 als ID oder ?
Auszug aus dem USB-2.0-Standard.
Wichtig ist, wenn du Dinge nicht implementierst (wie diesen device
qualifier), dass du sie dann sauber ablehnst. Einfach nur "nichts tun"
ist tödlich.
Passage aus meinem µracoli-Code dafür:
1
if(!process_setup_message())
2
{
3
/*
4
* SETUP request not understood: STALL the current
5
* setup message, either during the data or status
6
* phase. Automatically gets cleared when receiving
7
* the next SETUP packet.
8
*/
9
UECONX|=_BV(STALLRQ);
10
UEINTX&=~_BV(RXSTPI);
11
}
process_setup_message() gibt false zurück, wenn sie keine Idee hatte,
was die SETUP-Nachricht denn wollte. Eine Anfrage nach dem device
qualifier descriptor würde bspw. dahin führen.
Das hab ich eingebaut, wenn ein Request nicht zugeordnet werden konnte,
wird ein STALL zurückgegeben.
Ich habe alle Infos zu Descriptoren von einer anderen Webseite, wo es
nur etwas vereinfachter erklärt wird, ich denke die haben das da einfach
weggelassen, weil man es nicht unbedingt braucht.
Mein Code funktioniert jetzt zumindest soweit das ich alle wichtigen
Deskriptoren übertragen kann, morgen mache ich noch die
Endpunk-Deskriptoren und generell nicht-controll Endpunkte für
spezifische Funktionen.
Da fehlt noch das Handling für SetConfiguration bzw GetConfiguration.
USBView zeigt als ConfigValue 0 obwohl im Descriptor 1 steht. Ansonsten
passt das, da du ja noch keine Pipes hast. Das Device kann dann halt nur
auf Control Requests reagieren.
Wegen der IDs würde ich mir keinen Kopf machen. Falls das ein CDC wird,
spielen die sowieso keine wesentliche Rolle. Ich nehme da immer 0xDEAD
0xBEEF. :-)
Ich habe jetzt den ganzen Code in eine eigene .cpp datei verschoben,
eine Include Datei erstellt und alles aufgeräumt, soweit funktioniert
jetzt auch alles, nur 2 Probleme sind eben noch aufgetreten, die mir
beide nicht viel sagen:
Das erste kommt nur sehr selten vor, wenn ich das Gerät z.B. 50 mal
einstecke und wieder raus ziehe aus dem USB Anschluss de PCs, kommt in
ca 1 der 50 Fälle wieder "Gerät nicht erkannt".
Ich habe wieder ein par Debug-LEDs eingebaut, und es scheint in einem
von 50 Fällen nach dem senden des Device Deskriptors keine Antwort mehr
zu bekommen, es hängt in der Warteschleife für das RXOUTI Bit nach dem
senden fest, und bekommt keine Antwort vom Host.
Ich habe ein Timeout eingebaut, das es nur ca 2 Sekunden wartet, und
wenn dann nichts kommt es den Vorgang abbricht, aber das ist denke ich
nur eine vorübergehende Lösung.
Ich habe jetzt auch Compiler Optimierung an, nachdem ich alle Debug
Sachen von vorher entfernt hab läuft das einwandfrei.
Kann es sein das das wirklich am host liegt, oder ist es warscheinlicher
das in meinem Code ein Fehler vorliegt?
Ich mein, in ~ 90% der fälle funktioniert es ja, ich kann mir irgendwie
nicht vorstellen das da ein "Fehler mit Zufallschance" drin ist.
Das 2. Problem tritt immer auf, USBView zeigt nämlich meine String
Deskriptoren nicht am, es sagt immer "String Descriptor for index 1 not
available while device is in low power state.".
Was genau bedeutet das?
Ich habe rausgefunden das das kommt wenn das Gerät länger nicht aktiv
war, und daher in den Suppend-Mode gegangen ist, aber wärend der
Konfiguration und Enumeration ist doch eigentlich dauerhaft Aktivität
auf dem Bus oder ?
Ich sollte noch dazu sagen, jetzt wo das Timeout in der Warteschleife
ist, wird es immer erkannt, aber es dauert halt in einem von 50 Fällen
ungefähr 4 Sekunden bis es erkannt wurde, weil halt ein 2. versuch vom
Host gestartet wird.
Set bez GetConfiguration nicht oder nicht richtig implementiert wie
schon geschrieben.
UsbSpec: ein nicht configuriertes Gerät geht in den Powerdown mode.
Ich habe Set und Get Configuration eigentlich implementiert, ich hab
garnicht bemerkt das da immer noch 0 steht, ich habe es eben mal wieder
abgefangen und es wird gar kein SET_CONFIGURATION Request gesendet.
Ich empfange:
- USB Reset
- SET ADRESS
- GET DESCRIPTOR (mehrfach, für Device und Configuration denke ich mal)
Und dann nichts mehr
USB View zeigt was in dem Screenshot zu sehen ist.
Marvin K. schrieb:> Ich empfange:> - USB Reset> - SET ADRESS> - GET DESCRIPTOR (mehrfach, für Device und Configuration denke ich mal)
für Win ist das so nicht richtig, der Reset kommt mehrfach. Wenn du
keinen SetConfiguration bekommst ist die Enum nicht abgeschlossen.
Windows schickt dein device in den Suspend weil es nicht mit deinen
Antworten zufrieden ist.
Wirf die Delays raus und merke dir den usbstatus in einer Variable.
So etwa StatePowered, StateReset,StateAddressed, StateConfigured,
StateSuspended, (0..4)
Dann kannst du in deiner Mainschleife die LEDs über den usbstatus
anzeigen.
Ich habe keine delays, und ich empfange mehrere Resets, ich habe nur den
letzten hingeschrieben, da der erste ja ebenfalls nur ein GET_DESCRIPTOR
ausführt.
Ich habe zuerst eine Abfrage an den Begin jedes Requests gemacht.
1
if(request.bRequest==xy)PORTD=0xFF;
Wodurch ich verifizieren konnte das ich folgende Requests erhalte:
- GET_DESCRIPTOR
- SET_ADDRESS
Bei allen anderen blieben die LEDs Dunkel
Dann hab ich jedem Request nacheinander eine LED zugewiesen, und die LED
gesetzt wenn ein solcher Request empfangen wurde, daher weis ich die
Reihenfolge NACH DEM LETZTEN USB Reset:
- GET_DESCRIPTOR
- SET_ADDRESS
Aber wieder, kein SET_CONFIGURATION
Da alle Descriptoren ankommen und korrekt in USBView angezeigt werden,
und auch die Adresse korrekt gesetzt wurde, kann es ja schonmal nicht an
den von mir gesendeten Daten liegen (die sind ja angekommen).
Und andere Requests empfange ich nicht, aber irgendwo muss ja ein Fehler
sein.
nun dann kommt nur GetDescriptor(config) in Frage. Dir ist klar dass der
bei dir 2 mal kommen muss?
1. Mit wLength = 0x0009
2. Mit wLength = 0x0012
Im ersten Fall darfst du nur die ersten 9 Bytes senden.
Anders gesagt:
Du darfst niemals mehr als wLength Bytes zurück geben aber weniger falls
ein Descriptor kürzer ist
Ich Empfange einmal ein GET_DESCRIPTOR mit einer wLength von 64 und
einmal mit einer wLength von 18.
Das mit der 64 kommt daher das ich einen EPSIZE von 64 hab oder ?
Sollte ich das eventuell ändern ?
Der erste GetDescriptor(Device) kommt immer mit wLength = 0x0040. Das
ist eine Eigenheit von Windows. Unter Linux und MacOs wäre das 0x0008.
Strings werden übrigens immer mit 0x0100 abgefragt.
Es könnte noch sein das deine Status Stage nicht ok ist.
Das müsste dann ja aber die nach dem letzten GET_DESCRIPTOR sein, das
macht ja aber kein sinn, da die vorherigen auch alle akzeptiert werden,
und auch korrekt in USBView angezeigt werden.
Alle GET_DESCRIPTOR anfragen nutzen den selben Code.
Gibt es eventuell ein Tool mit dem man noch mehr Infos als mit USB View
bekommt ?
Beispielsweise weshalb die Verbindung unterbrochen wurde ?
Marvin K. schrieb:> Gibt es eventuell ein Tool mit dem man noch mehr Infos als mit USB View> bekommt ?
Erstens kannst du natürlich ein anderes OS nehmen und schauen, was die
machen. Eventuell auch eins, bei dem man USB-Debugging einschalten kann
… Ansonsten gibt's (teure) Hardware-USB-Analyzer. Dem Nutzernamen nach
:) würde ich vermuten, dass Thomas sowas hat, ich könnte auch einen
Zugang dazu auftreiben, denke ich. Wie schon mal beschrieben, brauche
ich dann aber einen compilierbaren Sourcecode. Diese Geräte liefern
ziemlich detaillierte Berichte, an welchen Stellen das Gerät sich nicht
korrekt verhält.
Ok, also aktuell habe ich keinen PC zur Verfügung um sowas zu testen
aber ich hatte schon länger mal vor eine VM für sowas einzurichten.
Ich lade den Code gleich mal hoch.
Hier ist der Sourcecode und der Makefile, ich weis nicht genau ob noch
mehr Dateien von Atmel Studio 7 benötigt werden, aber genaugenommen
würde ja sogar der Code alleine reichen, außer der Compiler Optimierung
hab ich nichts verändert.
Ich sollte noch dazu sagen, das ich relativ neu in C++ bin, bisher hab
ich hauptsächlich mit Java und Visual Basic programmiert, aber da Java
und C sich relativ ähnlich sind, konnte ich recht schnell größere
Programme schreiben (nicht nur für AVR).
Marvin K. schrieb:> ich hatte schon länger mal vor eine VM für sowas einzurichten.
Wird in dieem Falle vermutlich nicht so viel helfen, denn der Host muss
ja das USB-Gerät erstmal erkennen, bevor er in der Lage ist, es an den
Gast weiter zu reichen.
Marvin K. schrieb:> Hier ist der Sourcecode und der Makefile
(rant)
Oh ja, ich liebe diese Studio-generierten Makefiles. Mit ihren "Device
packs" jetzt werden die immer schlimmer, da sie nun auch noch die
-B-Option des Compilers verbiegen müssen. Außerdem überall die Programme
mit vollständigem Pfad und .exe am Ende, damit es auch garantiert
unportabel wird … Außerdem ist "all" nicht das erste Target, sodass ein
simples "make" halt dann nicht alles baut wie sonst üblich.
(end-of-rant)
Ich bekomme folgende Warnungen und Fehler, wenn ich das compiliere:
Kann ich hier natürlich reparieren, aber ich frage mich, warum
insbesondere letzterer Fehler bei dir nicht auftaucht. Du versuchst, in
der Initialisierung ein strdup() einzubauen. Das geht so nicht. Das muss
man als separaten String anlegen, auf den verwiesen wird. Denk auch
dran, dass USB-Strings alle UTF-16 sein müssen.
Ich habe das jetzt erstmal so zusammen gehackt:
Ultimativ wirst du die Strings aus den Descriptoren natürlich auch im
PROGMEM haben wollen. Mir ist sowieso nicht klar, warum dein .bString
nicht bereits const char * ist, aber das allein würde ja auch noch
nicht helfen; die Routine, die den Descriptor liest, muss ja dann auch
aus dem Flash lesen statt aus dem RAM.
(OK, wenn man den Descriptor dynamisch zur Laufzeit zusammen bauen
können will, dann geht es mit const natürlich nicht.)
Außerdem erinnere ich mich, dass man noch einen String descriptor für
die language #0 braucht, in dem dann drin steht, welche Sprachen alle
unterstützt werden.
Auch das mit dem fehlenden F_CPU hätte dich stutzig machen sollen: du
hast in main.cpp (aber nur dort) ein F_CPU definiert, allerdings auf 1
MHz – fährst du die CPU denn mit 1 MHz? Fürs USB brauchst du ja einen
8-MHz-Takt.
Warum dein buffer-Zeiger nicht gleich einer auf uint8_t ist, ist mir
auch nicht klar.
Ach, das hab ich vergessen zu entfernen, bei den String-Descriptoren hab
ich nur rumprobiert, ich Wuste ich hab was vergessen, bevor ich es
hochlade -.-
Ich hatte die komplet entfernt als ich die Tests gemacht hab, aber am
ende wieder eingefügt, als ich das Projekt geschlossen hab (um halt den
Forschritt nicht zu verlieren).
Vergiss die einfach und lösch sie raus.
Den F_CPU hatte ich für die aller ersten Tests am Anfang mal gesetzt, um
wenigstens irgend ein Delay zu haben (hab den Code aus der main eines
anderen Projektes kopiert), hab auch das vergessen zu löschen.
Sowas passiert halt leider wenn man alles mögliche versucht um einen
Fehler zu finden, und dann nicht alles rauslöscht ...
Also ja: die CPU läuft mit 8 MHz.
Und der Grund weshalb die String-Sachen so schlimm sind ist, das ich
absolut keinen Plan hatte wie die funktionieren, das war das erste mal
das ich einen String in C gebraucht hab, und in jeder anderen
Programmiersprache hat man ja diverse Typen wie String oder
StringBuilder, aber in C auf einem AVR hab ich sowas noch nie benutzt.
Ach, das wird einer der Gründe sein warum ich so viele Probleme damit
hatte.
Hab ich wohl vergessen, aber wie gesagt, die String Descriptoren sind
mir erstmal egal, ich will das die Konfiguration funktioniert.
Bei mir geht im Moment leider noch gar nichts, aber auch mit der anderen
("known good") Firmware. Scheint irgendwie an FLIP zu liegen hier, muss
ich später mal analysieren.
OK. Der Punkt war, dass auf meinem Demoboard ein 16-MHz-Quarz verbaut
ist, sodass ich die PLL anpassen musste.
Was mir übrigens nicht ganz klar ist, warum du sowas schreibst:
1
set(PLLCSR,PLLP0);
2
clr(PLLCSR,PLLP1);
3
clr(PLLCSR,PLLP2);
4
set(PLLCSR,PLLE);
statt einfach das Register in einem Rutsch zu schreiben:
(_BV macht weiter nichts als die Bitmaske zu einer Bitnummer zu
ermitteln. Der Name ist eher historisch, war in der avr-libc halt schon
immer so.)
Manchmal hat es sicher Sinn sicherzustellen, dass eine bestimmte
Reihenfolge bei den Bits gewährleistet ist, aber gerade hier sieht das
m.E. in einer Zeile übersichtlicher aus. Die auskommentierten Bits
sollen zeigen, dass genau diese Bits halt 0 bleiben.
Nun, an meinem FreeBSD benimmt sich das Teil jetzt völlig normal. Die
Folge der Requests ist:
An einem Windows sieht das nicht so grundlegend anders aus, außer dass
halt zwei Windows-spezifische Anfragen jeweils mit einem STALL
beantwortet werden. Den einen bezeichnet mein Analyzer als "String
Microsoft OS", das andere ist dieser device qualifier.
Das erklärt dann leider weder dieses Problem das ich durch einen Timeout
lösen musste, noch dass ich keine String Descriptoren nutzen kann (oder
anders gesagt, das die Konfiguration nicht gesetzt wird).
Wird sie denn bei deinen Tests korrekt gesetzt ?
Bei mir steht da halt 0x00 und das Gerät geht in diesen Susppend/Power
Down mode.
Und zu diesen umständlichen Konfigurationen, ich weis das das
umständlich ist, macht es aber einfacher mal kurz was zu ändern (einfach
set durch clr z.B. ersetzen).
Wenn ich weis das alles Funktioniert wollte ich noch sowas wie btm (kurz
für "bit mask") machen, wo ich dann z.B: schreiben kann
1
btm(PLLCSR,PLL0,0,1,0);
Also quasi erst der Register, dann das Erste Bit und dann die Bits die
von da aus gesetzt werden sollen.
Oder irgend was in der Art, das ist nur eine vorübergehende Lösung damit
ich schnell Sachen ändern kann, wie gesagt in C besonders in AVR hab ich
noch nicht so viel gemacht, meist nur Simple Sachen mit I/O Ports, und
wenig mit größerer Register manipulation.
Der DeviceQualifier sollte verschwinden sobald usbBCD auf 0x0110
gestellt wird.
Der 0xEE String ist unter Windows Teil der WinUSB Erkennung. MS stellt
damit fest ob WinUSB als Treiber benutzt werden soll.
Marvin K. schrieb:> Das erklärt dann leider weder dieses Problem das ich durch einen Timeout> lösen musste, noch dass ich keine String Descriptoren nutzen kann (oder> anders gesagt, das die Konfiguration nicht gesetzt wird).
Die String indices stehen derzeit ja alle auf 0, insofern werden keine
string descriptors abgefragt.
Dass du für selbige noch bissel was tun musst, hatten wir ja schon
diskutiert. Du brauchst einen String descriptor mit Index 0, bei mir
sieht der so aus:
und du musst die anderen ordentlich UTF-16 codieren.
1
{
2
.bLength=sizeof(structstring_descriptor)+
3
sizeof(USB_VENDOR_NAME)-sizeof(wchar_t),
4
.bDescriptorType=STRING_DESC,
5
.bString=USB_VENDOR_NAME
6
};
mit USB_VENDOR_NAME
1
#define URACOLI_USB_VENDOR_NAME L"URACOLI"
Beim AVR-GCC sind wide strings standardmäßig 16 bit breit, daher geht
das hier so.
> Bei mir steht da halt 0x00 und das Gerät geht in diesen Susppend/Power> Down mode.
Power down erfolgt hier nicht, und die Konfiguration sah unter allen
drei Ziel-Betriebssystemen erstmal soweit erfolgreich aus.
Thomas Z. schrieb:> Der DeviceQualifier sollte verschwinden sobald usbBCD auf 0x0110> gestellt wird.
Was ohnehin zweckmäßig ist, denn mehr als Fullspeed machen diese
Controller eh nicht. Da muss man dann die USB-Version auch nicht auf 2.0
festlegen wollen.
Jörg W. schrieb:> SETUP 0 1,028> 00 09 01 00 00 00 00 00> IN 0 1,029
Dieser Request fehlt in der Windows Variante (SetConfiguration) weshalb
das Ding unter Win nicht enumeriert.
Ich würde deshalb testweise einfach mal einen Bulk EP hinzufügen bei den
Descriptoren hinzufügen. Nur um sicherzugehen dass Win da nichts falsch
versteht.
Thomas Z. schrieb:> Dieser Request fehlt in der Windows Variante (SetConfiguration)
Stimmt.
Du meinst, sie schicken das nicht los, weil es keine Endpoints gibt
außer dem control endpoint?
Jörg W. schrieb:> Du meinst, sie schicken das nicht los, weil es keine Endpoints gibt> außer dem control endpoint?
wäre eine Möglichkeit. Ich bin mir nicht sicher ob ich sowas schon mal
gemacht habe. Bei Windows weis mans nie. Manchmal sind die bei MS total
pingelig manchmal lassen Sie auch grobe Fehler durchgehen.
Zumindest behauptet Windows, das Teil sei konfiguriert. Hat natürlich
keinen Treiber installiert – an der Stelle ist Windows anders als alle
anderen OSe. Die haben nämlich immer einen low-level driver, über den
man (bspw. per libusb) grundsätzlich erst einmal auf das Gerät zugreifen
kann.
Könnte natürlich sein, dass Windows keine Konfiguration auswählen will,
solange kein Treiber da ist. Das Einfachste wäre es vermutlich, du
würdest erstmal ein HID bauen. Das ist relativ simpel, und es hat selbst
in Windows immer einen Treiber.
Ich bin mir nicht zu 100% sicher wer im Treiberstack das SetConfigure()
macht.
Ich teste gerne und oft mit dem Thesicon USBIO Demo Treiber(*), dort
macht SetConfigure() die DemoApp. Es ist also möglich dass das gar nicht
mehr zum Enum Code gehört.
Vielleicht hat Win auch einfach ein Problem wenn es keine Pipe gibt. Was
ich aber sicher sagen kann ist dass ein SetConigure() auch kommt wenn
kein Treiber zugeordnet ist.
(*)
Da es das USBIO demo für W10 nicht mehr frei zum runterladen gibt mache
diese Tests in einer VM mit Win XP.
Ich habe jetzt mal die String Descriptoren korrekt implementiert, und
zum Test einen Language und einen Manufacturer Descriptor erstellt, ich
erhalte aber weiterhin diese Meldung.
1
iManufacturer: 0x01
2
String Descriptor for index 1 not available while device is in low power state.
1. Ich hab doch 16 Bytes, nicht 64. Und ich hab es eben auch nochmal auf
8 reduziert, bewirkt auch keine Änderung.
2. Ach stimmt, vergessen, hab es entfernt (auch keine Änderung).
Marvin K. schrieb:> 1. Ich hab doch 16 Bytes, nicht 64. Und ich hab es eben auch> nochmal auf> 8 reduziert, bewirkt auch keine Änderung.> 2. Ach stimmt, vergessen, hab es entfernt (auch keine Änderung).
die spec sagt ganz klar bulk EPs müssen 64 Bytes haben.
Also entweder stellst du auf Interrupt um un dann kann bInterval ein
Wert zugewiesen werden. oder du machst bulk mit 64 bytes und bInterval
auf 0.
hast du denn mal den Treiberdialog gesehen? Falls ja deinstalliere mal
im Gerätemanager (ausgeblendete Geräte sichtbar), und mit Haken Treiber
entfernen.
Hier ist mein aktuelle vollständiger Sourcecode.
Wie beschrieben funktioniert er soweit einwandfrei, nur dass ich keine
String Deskriptoren nutzen kann, und USBView immer sagt, das Gerät sei
im "low power Modus", und ich auch keinen SET_CONFIGURATION Deskriptor
empfange.
.././usbl.cpp: In function ‘void readUSB(void*, uint16_t)’:
3
.././usbl.cpp:128:14: warning: ISO C++ forbids incrementing a pointer of type ‘void*’ [-Wpointer-arith]
4
128 | *(uint8_t*)buffer++ = UEDATX; // Read data in buffer
5
| ^~~~~~
6
In file included from .././config.h:12,
7
from .././usbl.cpp:12:
8
.././usbl.cpp: In function ‘void writeUSB(const void*, uint16_t, uint8_t, bool)’:
9
.././usbl.cpp:156:27: warning: ISO C++ forbids incrementing a pointer of type ‘const void*’ [-Wpointer-arith]
10
156 | UEDATX = pgm_read_byte(buffer++);
11
| ^~~~~~
12
.././usbl.cpp:160:24: warning: ISO C++ forbids incrementing a pointer of type ‘const void*’ [-Wpointer-arith]
13
160 | UEDATX = *(uint8_t*)buffer++;
14
| ^~~~~~
Und nein, dier Herum-Casterei auf einen uint8_t*, der danach
dereferenziert wird, hat da keinen Sinn. buffer selbst gehört als
uint8_t* deklariert statt als void*.
Ich hab es mit uint_8t* versucht, aber Atmel Studio wollte es dann nie
kompilieren, es ist dann immer zu irgend einer zufälligen Zeile
gesprungen und hat sowas gesagt wie "first use of xy" dabei war an
dieser stelle alles in Ordnung ...
Manchmal springt es dann auch einfach zu einer leeren Zeile und sagt das
da irgend ein Fehler ist.
Ich hab keine Ahnung woran das liegt, eventuell muss ich den Code mal
mit einer anderen IDE öffnen, ich glaub das liegt an Atmel Studio.
Hier der Patch, wie das (halbwegs) korrekt ist. Sind immer noch
typecasts drin, irgendwie muss man halt einen "Zeiger auf irgendwas" in
einen "Zeiger auf Byte" umwandeln, aber jetzt wird zumindest nicht mehr
versucht, einen void-Zeiger zu inkrementieren.
constwchar_t*wString;// List of chars representing the string
6
}__attribute__((packed))USB_String_Descriptor;
funktioniert natürlich so nicht. Der ganze Descriptor wird ja dann
linear "abgearbeitet". Damit gibst du (korrekt) bLength aus, dann
(korrekt) bDescriptorType, danach gibst du den Zeiger auf wString aus,
hernach nur noch Unfug.
Wenn du das so schön hintereinander weg schreiben willst, musst du den
Platz für das Array mit den strings im Descriptor selbst allozieren,
statt da nur einen Pointer hinzulegen.
(Deine Makro-Wurschtelei macht es nicht gerade einfacher, durch den Code
durchzusteigen.)
Hab gerade versucht, das dadurch zu lösen, dass man das Array in die
struct selbst mit aufnimmt. Aber hier stolpert man drüber, dass diese
Initializer in C++ wohl eher neu sind (in C gibt es sie seit C99).
Während ein Clang ein
1
structfoo{
2
wchar_tfoo[42];
3
}foobar={.foo=L"FOOBAR"};
problemlos frisst, erbricht sich der GCC daran und meckert was über "C99
designator ‘foo’ outside aggregate initializer".
Entweder compilierst du den ganzen USB-Kram als C statt C++, oder du
baust die Teile auf C++ um (statische Objekte mit Konstruktor).
Thomas Z. schrieb:> descriptorSize = *blablub[0];
Geht bei AVR und Progmem nicht.
Aber ja, vom Prinzip schon.
Was auch alles andere als nett ist ist, dass in config.h Funktionen
definiert sind. Sowas gehört in eine .c / .cpp Datei.
Jörg W. schrieb:> Thomas Z. schrieb:>> descriptorSize = *blablub[0];>> Geht bei AVR und Progmem nicht.
Ok, da kenn ich mich zu wenig aus ... man kann nicht aus dem ProgMem
derefernzieren?
dann ev descriptorSize = sizeof(blablub);
Nachteil: im Header muss das dann korrekt deklariert werden wenn es sich
nicht im usb.c File befindet.
Thomas Z. schrieb:> Ok, da kenn ich mich zu wenig aus ... man kann nicht aus dem ProgMem> derefernzieren?
Ja, zumindest nicht "klassisch". Mit Johanns Erweiterung __flash geht es
korrekt, aber die gibt es nur im C-Modus, nicht bei C++, weil sich C++
irgendwie gegen neue type qualifier wehrt.
@Marvin: dein hin- und her Gehüpfe zwischen constants.h und config.h ist
lästig. Der language ID descriptor (der ja auch nur ein string
descriptor ist) steht in der einen Datei, die anderen string
descriptoren in der anderen. Dadurch ist dir halt auch entgangen, dass
du bei dem mit der language ID das PROGMEM vergessen hattest, sodass er
im RAM abgelegt worden ist, während die Auslesefunktion ihn natürlich
aus dem Flash lesen will.
Mit dem aktuellen Diff kommen die string descriptors korrekt raus:
Jörg W. schrieb:> Warum Windows immer noch kein set configuration macht, da habe ich aber> keine Idee.
Wie gesagt das ist vermutlich schon Teil des Treibers, denn es ja für
das Teil ja (noch) nicht gibt.
@marvin vieleicht probierst du mal für diese Firmware via zadig einen
LibUsb Treiber zuzuweisen.
Danke, ich probiere das mal aus (alles was bisher so vorgeschlagen
wurde) und schaue ob es dann auch bei mir mal klappen will.
Zu den ganzen "Designfehlern" im C Code, wie dass Funktionen in der .h
stehen:
Ich weis, das das aktuell etwas Chaotisch ist, ich musste halt andauernd
was ändern, weil irgend was nicht Funktioniert hat, ich werde das wenn
es denn mal funktioniert ordentlich sortieren.
Dazu kommt halt das ich in C relativ neu bin, gerade die ganzen Pointer
Sachen musste ich mir erstmal anschauen.
Aber zu dem Problem mit dem Zeiger im struct, das seltsame ist dass ich
diesen Teil aus einem Beispiel von GitHub habe, und da hat es
funktioniert (habe es durch ausgeben der Werte per LEDs getestet).
Allerdings habe ich den Auslesecode nicht übernommen, ich schätze da war
irgend eine Regelung eingebaut, das wenn er an diesen Punkt kommt, er
automatisch das Array des Zeigers lädt, anstatt den Zeiger selbst.
Marvin K. schrieb:> Danke, ich probiere das mal aus (alles was bisher so vorgeschlagen> wurde) und schaue ob es dann auch bei mir mal klappen will.
Ich habe das hier jetzt sowieso in ein Git-Repo lokal reingeschmissen.
Wenn du willst, kann ich das auch auf Github hochladen.
> Aber zu dem Problem mit dem Zeiger im struct, das seltsame ist dass ich> diesen Teil aus einem Beispiel von GitHub habe, und da hat es> funktioniert (habe es durch ausgeben der Werte per LEDs getestet).> Allerdings habe ich den Auslesecode nicht übernommen, ich schätze da war> irgend eine Regelung eingebaut, das wenn er an diesen Punkt kommt, er> automatisch das Array des Zeigers lädt, anstatt den Zeiger selbst.
Wahrscheinlich.
Aber ultimativ willst du diese vendor & product strings sowieso im Flash
haben. Flash-Strings als Zeiger weiterreichen benötigt (zumindest ohne
__flash Schlüsselwort) separat angelegte String-Objekte. Wenn du den
String hingegen gleich im Descriptor-Objekt ablegst, steht er "von sich
aus" im Flash, das ist das, was ich da jetzt gemacht habe.
Außerdem hast du da gleich noch ein Beispiel, wie man einen Makro über
mehrere Zeilen aufsplitten kann, damit er etwas übersichtlicher wird.
;-)
Ich habe jetzt mal alle Änderungen übernommen, jetzt wird mir auch
langsam klar wie das mit den Strings und Arrays funktioniert, ist schon
ziemlich verwirrend wenn man das das erste mal auf einem AVR macht.
Die Strings funktionieren jetzt, ich hab die Deskriptoren mit einem
einfachen uint8_t Array realisiert, das eine fixe Größe hat und im
Progmem liegt.
Nur der Language Deskriptor hat ein par seltsame Probleme, erst habe ich
es hier mit versucht:
Es hat soweit geklappt das manchmal alle Deskriptoren manchmal aber auch
nur 1 oder 2 angezeigt wurde, bei den anderen stand dann wieder das das
Gerät im low power mode sei.
Interesanterweise, hat es sich jedes mal geändert, wenn ich in USBView
"Refresh" gemacht hab, nach jeder Aktuallisierung wurden andere Strings
angezeigt, mal 1 und 3 mal nur 1 mal 2 und 3 etc.
Dann habe ich es das auch durch ein Array ersetzt, was mir sinnvoller
erschien, da die Strings auch in Arrays stehen:
String Descriptor for index 2 not available while device is in low power state.
6
iSerialNumber: 0x03
7
*!*WARNING: 3 is an invalid Language ID
8
ABC!!!!"
Der erste und der 3. Deskriptor wird angezeigt, der 2. nicht, und bei
denen die angezeigt werden steht "xy is an invalid Language ID".
Was hat das zu bedeuten, ich habe die Werte doch gleich belassen, kann
mir einer sagen warum was anderes (offenbar falsches) beim host an
kommt, wenn ich die Werte in einem Array, anstatt in einem struct
speichere ?
Naja, alles Probleme, die ich dir schon gelöst hatte.
Ich habe dir auch vorgemacht, wie man die string descriptors so einbaut,
dass sie eine flexible Länge haben.
Habe das einfach mal auf Github hochgeladen:
https://github.com/dl8dtl/USB162
Mach damit, was du möchtest. ;-) Kannst auch gern Schreibzugriff da
drauf bekommen, wenn du weitere kleine Schritte veröffentlichen willst.
Solche "bare metal" Codes sind oft dann doch Mangelware.
Ich habe auch einige Erfahrungen im SCSI-Bereich, das kann man gut
gebrauchen, wenn es um USB Mass Storage geht. Das Protokoll dafür ist
ein (abgespecktes) SCSI.
statement-expressions are not allowed outside functions or nor template-argument lists
und markiert die stelle
1
sizeof(wchar)
Wenn ich diese stelle durch einen Fixen Wert wie z.B. 4 ersetzt,
funktioniert es, warum darf ich an dieser stelle kein sizeof() nutzen,
bzw. warum funktioniert es dann bei dir ?
Hat das was mit meinem Compiler zu tun ?
Marvin K. schrieb:> Hat das was mit meinem Compiler zu tun ?
Kann natürlich sein. So ganz ist mir nicht klar, was er damit sagt, aber
im C++-Standard kenne ich mich zugegebenermaßen nur wenig aus. sizeof()
ist eigentlich ein Operator (auch wenn es wie eine Funktion aussieht).
Eventuell mal die Einstellung für die Version des C++-Standards suchen
und was anderes auswählen?
Bei mir werkelt ein GCC 10.x, weiß nicht, welche Version der als default
für den C++-Standard benutzt. Habe mal die Version auf C++17 (+ GNU
Erweiterungen) gesetzt, damit compiliert es hier. Habe die
Aktualisierung im Makefile auf Github hochgeladen.
Egal was ich mache, er weigert sich das sizeof(wchar) zu kompilieren.
Ich glaube Atmel Studio ignoriert auch alle meine Einstellungen.
Wenn ich mit -std=c++11 verwende (z.B.) sagt es bei einigen codestellen
dennoch das ich erste c++11 aktivieren wohl, obwohl ich das ja schon
hab.
Und wenn ich es direkt im Makefile ändere überschreibt es das einfach
wieder sobald ich speichern drücke.
Gibt es eventuell noch eine andere Funktion zum ermitteln der länge
eines arrays?
Ich habe es schon mit diversen Pointer-Tricks versucht, die ich im
Internet gefunden habe, aber bei allen sagt Atmel immer "unqualified id
before xy" ...
Marvin K. schrieb:> Und wenn ich es direkt im Makefile ändere überschreibt es das einfach> wieder sobald ich speichern drücke.
Kannst du dem denn nicht irgendwo sagen, dass du dein eigenes Makefile
nimmst und es die Finger davon lassen soll?
Thomas Z. schrieb:> Ich würde dem Parameter wchar im Makro mal einen anderen Namen geben und> dann noch mal testen.
Wobei reserviert nur 'wchar_t' ist, nicht 'wchar'.
Außerdem compiliert der Salat bei mir ja problemlos.
Jörg W. schrieb:> Kannst du dem denn nicht irgendwo sagen, dass du dein eigenes Makefile> nimmst und es die Finger davon lassen soll?
Ich hab bisher keine solche Option finden können, ich hab bestimt
mehrere Stunden in Menüs rumgeklickt, und alle möglichen (für mich)
nutzlosen Optionen gefunden, aber nichts was einen "Custom-Makefile"
oder eine andere Lösung hervorgebracht hat ...
Und wie gesagt, wenn ich sage er soll eine andere Compilerversion nutzen
(diese Einstellung hab ich gefunden) ignoriert er das (im makefile steht
immer noch das gleiche).
Muss ich eventuell den Toolchain updaten oder sowas?
Ich hab bisher nur "normale" AVRs Programmiert (Ohne spezielle
Schnittstellen)
Aber kann es sein das ich für den AT90USB ein Update brauche?
Aktuell hab ich den avr8-gnu-toolchain 5.4.0, hab aber bei einer kurzen
Google Suche auch nichts neueres gefunden (zumindest für Windows).
Marvin K. schrieb:> Aber kann es sein das ich für den AT90USB ein Update brauche?
Für den selbst nicht.
Aber halt möglicherweise für meinen Konstrukt, im Makro via sizeof()
gleich die Länge des Strings zu ermitteln.
> Aktuell hab ich den avr8-gnu-toolchain 5.4.0
Das sagt alles und nichts, weil das rein Atmel/Microchips Nummerierung
ist. Welche Versionen von Compiler und Binutils sich dahinter verbergen,
kann man dem nicht entnehmen.
Ich weis nicht warum, aber auf ein mal kompiliert es.
Ich habe eigentlich nur den Language Descriptor wieder zu einem Array
gemacht, der hatte damit aber eigentlich Garnichts zu tun, er hatte sein
eigenes struct.
Auf jeden fall kann ich es jetzt kompilieren und an den PC anschließen,
aber es sagt weiterhin "String descriptor xy not aviable, device in low
power state".
Ich werde morgen mal einen Treiber dafür schreiben (nur damit es
konfiguriert wird) und schauen ob es sich dann eventuell ändert,
ansonsten funktioniert alles ja schon länger bis auf die besagten
Strings.
Marvin K. schrieb:> Ich werde morgen mal einen Treiber dafür schreiben (nur damit es> konfiguriert wird)
Brauchst du keinen schreiben. Zadig wurde schon genannt, damit kannst du
einfach einen libusb-Treiber drauf konfigurieren lassen.
> und schauen ob es sich dann eventuell ändert,> ansonsten funktioniert alles ja schon länger bis auf die besagten> Strings.
Die sollten aber schon funktionieren.
Meiner Erinnerung nach kann man mittlerweile auch unter Windows mit
irgendeinem Plugin oder Treiber USB-Tracing via Wireshark machen.
Vielleicht bringt dich das ja weiter?
Etwas seltsam ist es schon, denn hier hat das an mehreren
Betriebssystemen problemlos inklusive der Stringdeskriptoren
funktioniert.
Ich hab nochmal die Änderungen von @Jörg W. geladen
(https://github.com/dl8dtl/USB162) und auf den AT90 gespielt, es verhält
sich exakt wie meins.
Die String-Deskriptoren werden nicht angezeigt (low power mode) und es
braucht ewig um von Windows erkannt zu werden, nach dem einstecken
dauert es bestimmt 10 Sekunden bis das "Ding-Ding" kommt, wenn man ein
Gerät einsteckt. Manchmal kommt auch nach ca. 20 Sekunden einfach "Gerät
nicht erkannt".
Als ich es aber damals getestet hab, als ich noch gar keine String
Descriptoren implementiert hatte, hat es einwandfrei funktioniert.
Es scheint als gäbe es wieder irgend ein Hardwareproblem, was auch
erklären würde, weshalb mein Code bei anderen funktioniert.
Was könnte eine so extreme Verlangsamung des Verbindungsaufbaus
verursachen?
Manchmal ist es so extrem das ich wenn ich das Gerät in USBView
anklicke, das Fenster als "Reagiert nicht" markiert wird, und ich ca. 20
Sekunden warten muss bis die Daten angezeigt werden.
Ich hab nichts an der Hardware verändert, und das es jetzt bei jedem
Code ist den ich teste, muss es irgend was Projekt-unabhängiges sein,
die Daten kommen ja durch (bis auf die Strings), und die Datenleitungen
hab ich jetzt mehrfach geprüft, nachdem ich sie neu angelötet hab haben
sie definitiv kontakt.
Marvin K. schrieb:> Was könnte eine so extreme Verlangsamung des Verbindungsaufbaus> verursachen?
Naja, der USB-Pfad in der Hardware selbst. Andererseits ist das ja
gerade mal Fullspeed USB, also 12 Mbit/s. Das ist jetzt keine
Raketenwissenschaft.
Für alle Fälle hier mal ELF- und Hex-Datei aus meinem Compilat, damit du
ausschließen kannst, ob es irgendwie am Compilieren liegt bei dir.
Marvin K. schrieb:> Was könnte eine so extreme Verlangsamung des Verbindungsaufbaus> verursachen?
Ich glaube ja dass du einen Fehler suchst wo gar keiner ist. Das
DingDong was du bekommst ist die Meldung dass Win aufgegeben hat.
Ich glaube auch nicht dass fehlerhafte String Descriptoren die Ursache
sind. Das kannst du aber der leicht testen indem du die String IDs im
Devicedescriptor auf 0 setzt. Dann kommen keine String Requests mehr.
Du solltest im Device Manager mal aufräumen. Win bzw PNP hat oftmals ein
Problem wenn ein fehlerhaftes Device angeschlossen wird. Durch das
Aufräumen erzwingst du neu den Treiber Dialog.
Das Verhalten passt dazu dass kein Treiber geladen wird. Dann muss das
Device deaktiviert werden, die Spec fordert dass inaktive Devices in den
Powerdown geschickt werden. Das ist genau das was usbd mit deinem Device
macht.
Du könntest auch mal bei geöffnetem Device Manager einfach dein Device
anstecken und schauen was da unter USB passiert.
Das DingDong kommt auch wenn ein Gerät erkannt wurde, das hat nichts
damit zu tun das ein Fehler aufgetreten ist.
Wenn ich eine Tastatur oder einen USB Stick einstecke kommt es auch, und
zwar ca. 3 Sekunden nach dem einstecken.
Ich stelle gerade aber fest, das jedes Gerät so eine extreme Verzögerung
beim einstecken hat, das ist aber nicht normal, ich hab seit dem ich mit
dem AT90 rumprobiere, nichts mehr eingesteckt, aus er einem USB Stick
der bekannt war, sehr langsam zu sein (ka warum).
Also verglichen mit der langsamen Reaktionszeit der anderen Geräte die
ich einstecke, verhält sich mein AT90 also sogar ganz normal.
Noch verwirrender ist, das ich nochmal meinem Code draufgeladen habe,
jetzt verbindet es ich innerhalb von ca. 1 Sekunde, wärend andere Geräte
weiterhin sehr langsam sind.
Es scheint als ob es an meinem PC liegt und nicht am Gerät, ich habe
gerade keinen 2. PC zur Verfügung, um es dort zu testen, aber es scheint
als ob sich mein Gerät normal verbindet, und das Problem mit der langen
Wartezeit vom PC kommt.
Eines ändert sich aber nie:
1
String Descriptor for index 2 not available while device is in low power state.
erscheint zufällig bei mindestens einem der 3 Stringdescriptoren.
Ich habe mal die .elf Datei auf den AT90 geladen, sie funktioniert, er
wird erkannt und die Stringdescriptoren werden geladen, weshalb das
Gerät jetzt auch ein Namen hat.
Ich hab meinen Code mal angehängt, eventuell hab ich ja doch noch irgend
einen Fehler, die elf bzw. hex ist auch dabei, vielleicht kann ja
nochmal jemand der die mittel hat den Verlauf analysieren und mir sagen
warum die Strings nur manchmal ankommen, wie gesagt, einige werden immer
mal wieder angezeigt.
Da die elf von Jörg W. funktioniert, muss der Fehler ja am Compiler oder
dem Code liegen (bis auf das mit der großen Verzögerung, das ändert sich
auch mit der elf nicht und ist bei jedem Gerät, offenbar zufällig,
scheint mein PC zu sein).
Jörg W. schrieb:> Für alle Fälle hier mal ELF- und Hex-Datei aus meinem Compilat, damit du> ausschließen kannst, ob es irgendwie am Compilieren liegt bei dir.
Eventuell könntest du mir nochmal den Code senden den du da kompiliert
hast, dann mache ich das auch und schaue ob meine elf ein anderes
verhalten hervorbringt.
Ach, ich hab in dem Code den ich hochgeladen hab der einfach heit halber
nur 1 String Descriptor aktiviert, aber man kann sie einfach alle
aktivieren, dann sollte es das Verhalten zeigen das ich habe (das immer
mal wieder einer ankommt).
In diesem Zustand sagt es bei diesem einen dauerhaft das er nicht
ankommt.
Marvin K. schrieb:> Eventuell könntest du mir nochmal den Code senden den du da kompiliert> hast
Kannst du direkt aus dem Github-Repo nehmen. Wenn du es schaffst, auf
der Kommandozeile den $PATH zu setzen und ein "make" aufzurufen, kannst
du auch das mitgelieferte Makefile benutzen.
Ansonsten kannst du natürlich dein Kompilat (ELF-File) nochmal hier
abladen, welches dein Compiler aus dem gleichen Code produziert hat,
dann könnte man das vergleichen.
Ich hab den Code mit meinem Makefile (Atmel Studio 7) kompilliert und
auf den AT90 geladen, er verhält sich nicht so wie er soll, er verbindet
sich nur in 50% der Fälle, in den anderen sagt Windows "Gerät nicht
erkannt".
Die ELF hab ich angehängt, ich musste im Code aber eine Stelle ändern
damit es zu kompilieren ging:
1
typedef struct
2
{
3
uint8_t bLength; // Byte count of this descriptor
4
uint8_t bDescriptorType; // Type of the Descriptor
5
const wchar_t wString[]; // List of chars representing the string
6
} __attribute__((packed)) USB_String_Descriptor;
wurde zu
1
typedef struct
2
{
3
uint8_t bLength; // Byte count of this descriptor
4
uint8_t bDescriptorType; // Type of the Descriptor
5
const wchar_t wString[42]; // List of chars representing the string
6
} __attribute__((packed)) USB_String_Descriptor;
Ich musste das Array mit einer Größte initialisieren, ansonsten hat es
immer mit 0 initialisiert und der Compiler gab beim setzen des Wertes
aus das das Array mit einer Größe von 0 zu klein für den String xy sei.
Hat das eventuell was zu bedeuten ?
Ich hab es in meinem Code direkt mit einem bestimten Wert initialisiert.
Eine maximallänge für die Strings ist ja nicht schlimm, und es wird ja
sowieso nur der Teil des Arrays ausgelesen den ich angebe (im Feld
bLength).
Marvin K. schrieb:> Ich hab den Code mit meinem Makefile (Atmel Studio 7) kompilliert und> auf den AT90 geladen, er verhält sich nicht so wie er soll, er verbindet> sich nur in 50% der Fälle, in den anderen sagt Windows "Gerät nicht> erkannt".
Das ist natürlich Mist. Computer sollten deterministisch arbeiten.
> Die ELF hab ich angehängt, ich musste im Code aber eine Stelle ändern> damit es zu kompilieren ging:
Naja, flexible array members sind nie in den C++-Standard eingeflossen.
Das C++-Konsortium wünscht offenbar nicht so viele "C-ismen" in seiner
Sprache für Dinge, die man in C++ anders lösen könnte. Geht bestimmt
irgendwo über Templates oder sowas, bin grad zu faul mir das anzutun.
Offenbar akzeptiert meine AVR-GCC-Version das auch im C++-Modus, deine
nicht.
Ist natürlich die Frage, ob du überhaupt C++ brauchst – eigentlich
benutzt du ja kein einziges C++-Feature, wenn ich das richtig sehe.
ELF-File sehe ich mir mal an.
Nur nochmal eine kurze Zusammenfassung, wie die Lage aktuell ist, da es
gerade meiner Meinung nach etwas chaotisch wurde, mit den verschiedenen
Versionen des Codes:
- Code von Jörg als von ihm kompilierte ELF -> Arbeitet einwandfrei
- Code von Jörg als von mir kompilierte ELF -> Funktioniert nur
manchmal, keine Strings
- Mein original Code -> Funktioniert immer, aber keine Strings, bzw nur
manchmal 1-2 von 3
- Code den jemand mir vor längerem gesendet hat (weis leider nicht mehr
wer), der ursprünglich einwandfrei funktioniert hat, und nach dem ich
mich gerichtet hab -> Funktioniert immer, aber eben falls keine Strings
mehr.
Hochgeladen hab ich meinen Originalcode und die ELF die ich mit Jörgs
Code kompiliert habe.
Ich habe durch langes rumprobieren jetzt noch rausgefunden, das meinem
Code zwar anfragen zu String Deskriptoren gesendet werden, allerdings
immer nur für den Language Deskriptor.
Welchen Grund könnte es den geben, das Windows nur den Language
Deskriptor abfragt, und die anderen erst gar nicht versucht zu bekommen
?
Hmm, wollte dein ELF-File gerade hier probieren - aber das geht
natürlich nicht, denn mein Devboard benutzt einen 16-MHz-Quarz.
Wenn du willst, kannst du es mir nochmal mit den PLL-Einstellungen für
16 MHz hochladen, dann teste ich das hier (inklusive USB-Analyzer).
Marvin K. schrieb:> Welchen Grund könnte es den geben, das Windows nur den Language> Deskriptor abfragt, und die anderen erst gar nicht versucht zu bekommen> ?
Vielleicht weil da kein korrekter Descriptor zurück kommt?
Schau dir die Requests mal mit Usblyzer an.
Also ich hab mir mal die Testversion von USBlyzer installiert, und
irgendwie funktioniert es nicht, sobald ich versuche den AT90
Aufzuzeichnen, wird er nicht mehr erkannt ("Fehler beim anfordern einer
Gerätebeschreibung").
Stoppe ich die Aufzeichnung, funktioniert es wieder.
Zeichne ich den ganzen HUB auf, funktioniert es auch, allerdings scheint
die Aufzeichnung dann keine Daten zu den angeschlossenen Geräten sondern
wirklich nur zum HUB zu enthalten.
Gibt es irgend was was ich in USBlyzer einstellen muss, bevor ich die
Setup Requests aufzeichnen kann, ohne das es zu einem "Fehler beim
Anfordern einer Gerätebeschreibung" kommt ?
Hier sind die Infos die ich bekomme wenn ich den AT90 aufzeichne (und
somit einen "Fehler beim Anfordern einer Gerätebeschreibung"
verursache).
Ich verstehe nicht ganz was "Set Power" ist, es ist rot markiert.
Ich habe mir noch ein anderen USB Analyzer runtergeladen, dieser
wiederum Zeigt den AT90 erst gar nicht als Gerät an, alle anderen Geräte
allerdings schon.
Aber warum sagen Die Programme alle das mein Gerät nicht existiert /
erzeugen Fehler beim Aufzeichnen, während USBView und der Gerätemanager
es anzeigen ? (Bis auf den Treiber und die Strings)
nun alle diese USB Analyzer setzen ein Gerät vorraus was durch die Enum
kommt.
Solange das nicht passiert ist sind die nicht so hilfreich.
Es gibt bei usb.org noch ein Tool was dir vielleicht halfen kann USB2CV.
Das schaltet den kompletten Hostcontroller in den Debug mode. Das
funktioniert recht brauchbar am Laptop (mit Touchpad). Damit lassen sich
alle Chapter9 requests einzeln oder zusammen auf Compilance prüfen.
Achtung:
Es ist zwingend notwendig dass Maus und Tastatur nicht über den Host
angesprochen werden der in den Debug mode geschaltet wird. Das ist bei
einem Laptop üblicherweise gegeben.
Auf einem PC sollte das DUT an einem getrennten Host hängen (Steckkarte)
weil sonst der PC nicht mehr bedienbar ist.
https://www.usb.org/document-library/usb20cv-x64-bit
Setpower ist ein HubRequest der betrifft dich nur indirekt.
Aber mein Gerät kommt doch durch die Enumaration, zumindest bin ich
davon ausgegangen das die Meldung "Gerät wurde Erfolgreich eingerichtet"
und die Tatsache das alle Descriptoren (bis auf die Strings) in USB View
korrekt angezeigt werden dies bedeutet, oder hab ich da was falsch
verstanden ?
Ich habe eben auch mal alle Descriptoren von einer simplen
USB-Festplatte übernommen, und es auf den AT90 Geladen, im Gerätemanager
wird er als "USB-Massenspeicher" mit allen Daten des Original Gerätes
angezeigt, im Prinzip eine 1 zu 1 Kopie, mit einem unterschied:
Da steht das das Gerät nicht gestartet werden konnte, kein Grund, nur
das es nicht geklappt hat.
Und das Ausrufezeichen das anzeigt das kein Treiber installiert ist ist
zu sehen.
Ich lade mir das Tool mal runter und probiere es damit aus.
Also, der AT90 kann ja gar kein USB3 und da ich an meinem PC 2
verschiedene Buchsen habe (Blaue und Schwartze) und in der Beschreibung
stand das die Blauen USB 3 Buchsen sind, bin ich davon ausgegangen das
die schwarzen Buchsen weiterhin USB 2 sind.
Mein PC hat an sich laut USBlyzer 5 USB Hostcontroller.
3 Davon sind in Benutzung für die ganzen USB Ports am PC, ich denke mal
das sind dann wohl alles USB 3 Controller die auch USB 2 Ports haben
oder die Farben der Anschlüsse am Gehäuse, stimmen nicht überein mit dem
was in der Anleitung steht.
Und USBView hab ich aus diversen Anleitungen und Dokumentationen zum
AT90.
Ich lade mit mal UsbTreeView und dieses USB3CV runter.
So, ich habe mal dein ELF-File so gepatcht, dass PLLP0 in PLLCSR setzt,
damit es auf meinem 16-MHz-Devboard läuft.
Deine string descriptor haben einfach eine viel zu große Längenangabe,
und dieweil dahinter dann Nullbytes übertragen werden, wird das vom OS
als ungültiger String angesehen.
Deine Variante:
Du siehst hier auch die 10 Sekunden Verzögerung, das scheint
Windows-spezifisch zu sein: wenn der Kram nicht gleich funktioniert,
wartet es 10 Sekunden und probiert's nochmal. Dann erst kommt auch der
"Dödel". Bei meinem ELF-File kommt der "Dödel" sofort beim Reinstecken.
setzt ja voraus, dass sizeof(USB_String_Descriptor) eben nicht bereits
den tatsächlichen Platz für den String enthält, sondern nur den Teil vor
dem eigentlichen String.
Die ganze sizeof-Rechnung kann man sich natürlich auch sparen und da
gleich eine 2 einsetzen. Da von dieser wieder eine 2 am Ende subtrahiert
wird (wegen des abschließenden \0 ist sizeof(wchar) länger), bleibt
davon einfach nichts mehr übrig.
Ich habe den entsprechenden Code ohne flexible array member in mein
Git-Repo geschoben.
Marvin K. schrieb:> ich dachte sizeof ermittelt nur die Länge von dem Pointer des Array
Das wäre beim AVR gleich 2 – aber hier gibt's keinen Pointer, denn das
Array ist ja Bestandteil der Struktur. Ist auch sinnvoll, denn so kann
man das alles hintereinander aus dem Speicher "herunterrattern".
Natürlich sind die flexible array members von C99 noch sinnvoller *),
denn man muss nur den Platz belegen, der wirklich gebraucht wird. Musst
du das C++-Kommittee fragen, warum sie das dort nicht haben wollten.
*) Ein Array unbestimmter Länge am Ende einer struct, wobei die
tatsächliche Länge durch die Initialisierung dann ermittelt wird.
Außerhalb von structs gibt es das ohnehin schon, denn das
1
charfoo[]="Hello, world!";
war schon immer möglich, und es ist auch etwas komplett anderes als
1
constchar*foo="Hello world!";
Letzteres legt nämlich ein anonymes Array an und hinterlegt in foo nur
den Zeiger.
Übrigens waren mir damals bei meinen ersten Gehversuchen mit den
USB-AVRs zwei Dinge wirklich hilfreich:
* eine UART am USB-AVR, mit der man sich Debugausgaben mitmeißeln konnte
* aktiviertes USB-Debugging auf einem FreeBSD-Host (allerdings einem
"Bastelrechner", der sonst keinen USB-Traffic hatte), denn damit konnte
man beispielsweise all das, was ich dir jetzt hier vom USB-Analyzer
gezeigt habe, auch bei fehlgeschlagener Einbindung ins System anhand der
Debug-Daten nachvollziehen