Hallo Liebe µC Gemeinde, ich war mir eigentlich sicher diesen Thread schon vor 20min geschrieben zu haben aber offensichtlich habe ich ihn garnicht abgeschickt. Egal, falls ich das doch getan haben sollte tut mir das leid. Zum Thema: Ich arbeite mich gerade in die USB Geschichte ein und will dazu USB Controller auf dem LPC1837 Controller von NXP (32Bit) ansteuern. Dieser treibt mich allerdings in den Wahnsinn. Im Datenblatt steht geschrieben, das ich einen Speicher in Form eines Arrays anlegen soll, der die sogenannten EndPointQueueHeads enthält. Somit ist dieser eine Liste von EndPointQueueHeads, im Datenblatt bezeichnet als EndPointQueueList. Für diese Liste gibt es einen Register, in dem ich die Adresse dieser Liste ablegen soll. Das dumme daran: Dieser Register ist von LPC_OPEN definiert als int Zahl. Dazu kommt, das die untersten 10Bits von diesem Register reserviert sind. WIe soll ich bitte auf einem 32Bit System eine Adresse übergeben wenn, die unteren 10bit garnicht gelesen werden? Wenn ich diesen Register nun beschreiben will mit der Adresse dann steht am Ende da natürlich jede Menge unfug drinne, aber nicht die Adresse meiner QueueList. Hat das Jemand von euch schon mal gemacht? Ich habe gesehen das dieses Prinzip der EndPointQueueList nicht auf LPC begrenzt ist.
Bei GCC mit aligned attibute:
1 | void * EndPointQueueList[SIZE] __attribute__((aligned(1024))) |
Damit sind die unteren 10 Bits von EndPointQueueList gleich null. Übrigens würde ich mich nach Beispielcode vom Hersteller umsehen, USB hat etliche Fallstricke bevor man das zu Fuß funktionierend programmiert hat.
Ludwig S. schrieb: > USB Controller auf dem LPC1837... Erstmal eines: Lies das Manual nochmal gründlich. Manchmal hat es in den µC einen völlig separaten RAM-Bereich, der NUR für USB oder (evt. exclusiv) für Ethernet reserviert ist. Vielleicht ist SOWAS gemeint. Im normalen Programm so einen speziellen Puffer zu erwarten wäre m.E. viel zu unwahrscheinlich. Den von dir genannten µC hab ich noch nicht unter den Fingern gehabt, aber vielleicht hilft dir zum Verstehen einiger Dinge ein Blick auf nen Treiber, den ich für nen älteren LPC mal geschrieben hatte. Ich häng ihn die hier mal an. Aber: nur für verstehendes Lesen, nicht für copy&paste. W.S.
W.S. schrieb: > Aber: nur für verstehendes Lesen, nicht für copy&paste. Ich bin ja nicht doof ;) Danke Danke dein Beispiel wird mir denke ich, sehr weiterhelfen. Wegen der QueueList: Du meintest das deiner Meinung nach unwahrscheinlich ist das man so einen speicher selber machen soll. Ehrlich gesagt denke ich das auch. Aber es steht eigentlich unmissverständlich im Datenblatt! Nichtsdesotrotz werde ich mich morgen nocheinmal gründlich mit dem datenblatt auseinandersetzen. Heute schaff ich das nicht mehr. Ich werde die Community natürlich auf dem laufenden halten ;)
Ach und an Jim Meba: es gibt ein Beispiel vom Hersteller das ist allerdings mit den internen API Befehlen geschrieben. Die gibts bei dem Chip auf einem extra teil im ROM. Wenn ich allerdings die allgemeine Funktion des Controllers nicht kapiere, dann denk ich mal nutzen mir die API Befehle auch nix. Hab schon nach nem anderen Beispiel gesucht, aber bisher bin ich nich wirklich fündig geworden. Bin ehrlich gesagt was USB betrifft, auch Neueinsteiger! Das mit dem align is bestimmt praktisch aber wenn ich den register beschreibe werden wie ich jetzt herausgefunden hab, sowieso alle bits unten abgeschnitten, bzw nach links verschoben
W.S. schrieb: > Erstmal eines: Lies das Manual nochmal gründlich. Manchmal hat es in den > µC einen völlig separaten RAM-Bereich, der NUR für USB oder (evt. > exclusiv) für Ethernet reserviert ist. Vielleicht ist SOWAS gemeint. Definitiv nicht, wenn man das Manual liesst. Dort steht dann auch drin, dass untergeordnete Strukturen auf 64 Byte aligned sein müssen. NXP hat sich da ein paar Addressbits gespart, vermutlich weil das Peripherial auch High-Speed können soll. Ludwig S. schrieb: > es gibt ein Beispiel vom Hersteller das ist > allerdings mit den internen API Befehlen geschrieben. Die gibts bei dem > Chip auf einem extra teil im ROM. Dann nutze die doch! Habe ich beim LPC1343 für HID auch so gemacht, ist viel einfacher als den Mist selbst zu schreiben. Und der LPC18xx scheint sogar CDC im ROM zu unterstützen. USB auf low Level zu debuggen ist eher unangenehm, weil dabei der Host öfters mit Timeout oder Fehlern aussteigt.
problem is, ich weiß bei den APIs da nicht so richtig wo ich anfangen soll. Weil ich ja keine Ahnung hab, was der controller als erstes braucht. Ne Clock - das is klar! Dazu kommt, das sowie mein programmzeiger im ROM verschwunden ist, weiß ich ja dann auch nicht mehr richtig was er so tut. Ich weiß auch ehrlich gesagt nicht so richtig wie ich ihn dann zurückholen kann... im cdc beispiel gibts dafür callback funktionen aber woher weiß ich wie die aussehen müssen wenn ich keine ahnung hab wie die funkionen aussehen? Du siehst mit fehlt noch immer so'n bisschen ne Vorstellung von dem Ding.
Ludwig S. schrieb: > Ne Clock - das is klar! Dazu kommt, das sowie mein > programmzeiger im ROM verschwunden ist, weiß ich ja dann auch nicht mehr > richtig was er so tut. O je, das blutet ja noch... Also, mal der Reihe nach: 1. Clock, Power, Portbeine, Interrupt aktivieren bzw. freischalten 2. Die Register für die gewünschten Endpoints einrichten Ich hab jetzt mal im UM10430 nachgesehen: Der USB-Core enthält RAM, und zwar 356 Words bzw. 128 Words pro Endpoint. Siehe 23.4.4 3. den 2k7 Widerstand am USB aktivieren 4. jetzt sollte das erste Setup-Paket vom Host eintrudeln und anschließend der zuständige Interrupt losgehen. 5. Denk bloß nicht mal im Traum daran, dort herumdebuggen zu wollen. Du wirst nach 3 ms vom Host herausgekickt und Ende der Vorstellung. Allenfalls kannst du dir ne Art Postmortem-Debugger schreiben: einfach das, was du dir selbst zu sagen hast, in einen bereitgestellten RAM-Puffer schreiben (aber hurri hurri Egon - alles getimed! Also kein sprintf und Konsorten) und später per UART zum PC schaufeln. W.S.
Ok Danke... das probiere ich jetzt mal so aus! Trotzdem würde mich schon interessieren was es mit diesem verfluchten ENDPOINTLISTADR Register auf sich hat. W.S. schrieb: > 2. Die Register für die gewünschten Endpoints einrichten > Ich hab jetzt mal im UM10430 nachgesehen: Der USB-Core enthält RAM, und > zwar 356 Words bzw. 128 Words pro Endpoint. Siehe 23.4.4 Aber wie komm ich da ran?
Ludwig S. schrieb: > W.S. schrieb: >> 2. Die Register für die gewünschten Endpoints einrichten >> Ich hab jetzt mal im UM10430 nachgesehen: Der USB-Core enthält RAM, und >> zwar 356 Words bzw. 128 Words pro Endpoint. Siehe 23.4.4 > > Aber wie komm ich da ran? Gar nicht. Der wird vom USB peripherial verwaltet und gefüttert. Dafür ist u.a. die oben genannte EndPointQueueList die Voraussetzung. Da USB ein AHB Master ist, läuft der Datenaustausch als DMA ab (direkt, ohne Verwendung des DMA peripherials). Hintergrund ist dass der USB RAM asynchron auf einer anderen Taktfrequenz laufen kann als der System RAM - bei High Speed muss der Zugriff sehr schnell erfolgen.
Ok Ok... Aber die Queue List wird schon von den API Befehlen selber angelegt oder was? Ich konnte bisher bei allen Beispielen keine QueueList finden.
:
Bearbeitet durch User
Ist in den LPCOpen Beispielen nichts brauchbares dabei? Da sind doch einige die LPCUSBLib benutzen (ohne ROM Unterstützung) und auch welche mit ROM: https://www.lpcware.com/content/nxpfile/lpcopen-software-development-platform-lpc18xx-packages-0
Ludwig S. schrieb: > Aber wie komm ich da ran? durch das wirklich gründliche Lesen des Manuals. Sonst nicht. Glaube bitte nicht, daß ich den Treiber, den ich dir gepostet habe, mal eben so ohne x-maliges Durchlesen des RefMan's zuwege gekriegt habe. Wie ist das denn heute so (im Gegensatz zu früher) "ohne Preis kein Fleiß" ?-) W.S.
So ich bin zwar jetzt nicht viel weiter aber immerhin ein bisschen: also ich habe mich denn doch dazu entschieden die APIs zu benutzen. Aber das Rätsel um die QueueHeads sind dennoch ziemlich mysteriös. In der app_usbd_cfg.h steht folgendes geschrieben: /* On LPC18xx/43xx the USB controller requires endpoint queue heads to start on a 4KB aligned memory. Hence the mem_base value passed to USB stack init should be 4KB aligned. The following manifest constants are used to define this memory. */ #define USB_STACK_MEM_BASE 0x20000000 #define USB_STACK_MEM_SIZE 0x00002000 Also 0x2000 sind erstmal 8kb, daher gehe ich mal davon aus das er hier gerade den speicher für 2 endpoint also zwei queueheads definiert?! Woher kommen die 0x20000000? Das einzige was ich unter der adresse finden konnte ist, das dort der sram losgeht. Dann habe ich einfach mal losgelegt und nach und nach versucht mich durch zu fummeln. Mein Ziel ist es probehalber mein Device als MassStorageDevice am PC anzumelden. Problem ist jetzt, das ich nachdem ausführen der Funktion Init einen Wert zurückbekomme. Dies ist ein ErrorHandler und als Wert bekomme ich 0x40008 -> Bad InterfaceDescriptor Ich kann an meinem InterfaceDescriptor aber keinen Fehler erkennen?! (Quelltext folgt gleich)
Das ist der Quelltext
1 | #include "chip.h" |
2 | #include "usbd.h" |
3 | #include "usbd_rom_api.h" |
4 | |
5 | USBD_API_T *usbrom; |
6 | |
7 | USBD_MSC_INIT_PARAM_T usbstack; |
8 | USBD_HANDLE_T MEINUSB; |
9 | |
10 | uint8_t string[28]="Hallo"; |
11 | |
12 | /*Hier habe ich Dummy Funktionen angegeben*/
|
13 | void write(uint32_t offset, uint8_t** src, uint32_t length, uint32_t high_offset){ |
14 | ;
|
15 | }
|
16 | void read(uint32_t offset, uint8_t** src, uint32_t length, uint32_t high_offset){ |
17 | ;
|
18 | }
|
19 | ErrorCode_t verify( uint32_t offset, uint8_t buf[], uint32_t length, uint32_t high_offset){ |
20 | return 0; |
21 | }
|
22 | /*Hier definiere ich meinen InterfaceDescriptor*/
|
23 | #define bLength 0x09
|
24 | #define bDescriptorType 0x04
|
25 | #define bInterfaceNumber 0x00
|
26 | #define bAlternateSetting 0x00
|
27 | #define bNumEndpoints 0x02
|
28 | #define bInterfaceClass 0x08
|
29 | #define bInterfaceSubClass 0x01
|
30 | #define bInterfaceProtocol 0x01
|
31 | #define iInterface 0x00
|
32 | |
33 | uint8_t InterfaceDescriptor[9]={bLength, |
34 | bDescriptorType, |
35 | bInterfaceNumber, |
36 | bAlternateSetting, |
37 | bNumEndpoints, |
38 | bInterfaceClass, |
39 | bInterfaceSubClass, |
40 | bInterfaceProtocol, |
41 | iInterface}; |
42 | |
43 | int main(void) |
44 | {
|
45 | ErrorCode_t ret = LPC_OK; |
46 | |
47 | /*Zeiger auf ROM mit den APIs*/
|
48 | usbrom=(USBD_API_T *)LPC_ROM_API->usbdApiBase; |
49 | |
50 | Chip_USB0_Init(); |
51 | NVIC_EnableIRQ(USB0_IRQn); |
52 | |
53 | /*Setze meinen USB Controller in den DeviceMode*/
|
54 | LPC_USB0->USBMODE_D=0x02; |
55 | |
56 | usbstack.mem_size=USB_STACK_MEM_SIZE; |
57 | usbstack.mem_base=USB_STACK_MEM_BASE; |
58 | usbstack.InquiryStr=&string[0]; |
59 | usbstack.intf_desc=&InterfaceDescriptor[0]; |
60 | usbstack.BlockCount=2; |
61 | usbstack.BlockSize=8; |
62 | usbstack.MemorySize=16; |
63 | |
64 | /*Hier bin ich mir unsicher ob ich hier Funktionen bekomme, oder ob ich welche angeben soll. Falls ich welche angeben sollte habe ich die weiter
|
65 | * vorsichtshalber gleich ein paar Dummy Funktionen deklariert, wo er ja theoretisch reinspringen müsste wenn sie gebraucht werden.*/
|
66 | usbstack.MSC_Write=write; |
67 | usbstack.MSC_Read=read; |
68 | usbstack.MSC_Verify=verify; |
69 | |
70 | /*Ich führe die Funktion "init" aus dem ROM aus*/
|
71 | ret=usbrom->msc->init(MEINUSB,&usbstack); |
72 | |
73 | return 0 ; |
74 | }
|
75 | |
76 | void USB0_IRQHandler(void) |
77 | {
|
78 | }
|
:
Bearbeitet durch User
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.