Forum: Mikrocontroller und Digitale Elektronik USB Contoller im LPC1837 von NXP


von Ludwig S. (big_l)


Lesenswert?

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.

von Jim M. (turboj)


Lesenswert?

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.

von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Ludwig S. (big_l)


Lesenswert?

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 ;)

von Ludwig S. (big_l)


Lesenswert?

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

von Jim M. (turboj)


Lesenswert?

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.

von Ludwig S. (big_l)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Ludwig S. (big_l)


Lesenswert?

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?

von Jim M. (turboj)


Lesenswert?

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.

von Ludwig S. (big_l)


Lesenswert?

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
von Jojo S. (Gast)


Lesenswert?

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

von W.S. (Gast)


Lesenswert?

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.

von Ludwig S. (big_l)


Lesenswert?

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)

von Ludwig S. (big_l)


Lesenswert?

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