XMEGA USB - ISR "TRNCOMPL" triggert nicht

OP #7805703
Lesenswert?

Hi,

ich beziehe mich wieder auf das XMega-USB-Projekt hier: Beitrag "CDC für xmega"

Ich versuche seit zwei Wochen, den Code von woodym zu verstehen, und bin für meine Verhältnisse sogar relativ weit gekommen. Aber... Testweise habe ich den Code mal auf ein Minimum reduziert, weil bei meinem eigenen Projekt der "Transaction Complete Interrupt" ISR(USB_TRNCOMPL_vect) nie getriggert wurde. Soll heißen, mein eigener Versuch scheiterte schon unnötig früh.

Dabei habe ich diese Zeile hier als Auslöser dafür gefunden, ob der Interrupt anspringt oder nicht:

1
USB_EP_pair_t endpoints[USB_DEF_EP_MAX] GCC_FORCE_ALIGN_2;

Hier wird nach meinem Verständnis Speicher für 16 Endpunkt-Paare reserviert. "GCC_FORCE_ALIGN_2" ist so definiert:

1
#define GCC_FORCE_ALIGN_2  __attribute__((section (".data,\"aw\",@progbits\n.p2align 1;")))

Nicht dass ich verstehen würde, was diese Zeile genau macht, aber sie soll wohl den Speicherbereich in Chunks zu 2 Byte organisieren, unabhängig davon, ob gerade uint8_t oder ein uint16_t gespeichert wird.

Ich habe den Code in mehreren Schritten und Versionen reduziert, und seltsamerweise funktioniert in manchen Fällen das Programm nur mit und manchmal auch ohne "GCC_FORCE_ALIGN_2".

Als ersten Versuch möchte ich euch erstmal ersparen, dass ich meinen gesamten Code poste. Kann sich vielleicht jemand einen Zusammenhang vorstellen, warum der Interrupt nicht getriggert wird, wenn diese Zeile fehlt? Im Manual steht meiner Meinung nichts davon drin, dass Endpunkt auf diese Weise organisiert werden müssen.

Vielen Dank schon mal!

(Firma: L-E-A) #7805796
Lesenswert?

Peder schrieb:

Hier wird nach meinem Verständnis Speicher für 16 Endpunkt-Paare reserviert. (...)

Nicht dass ich verstehen würde, was diese Zeile genau macht, aber sie soll wohl den Speicherbereich in Chunks zu 2 Byte organisieren,

Der Speicherblock wird auf eine 16-Bit-Grenze ausgerichtet oder für den hippen Neusprachler: "aligned". :-)

Guck doch einfach mal in das Datenblatt, z.B. XMEGA AU [MANUAL]: "20.14.7 EPPTRL – Endpoint Configuration Table Pointer Low

The EPPTRL and EPPTRH registers represent the 16-bit value, EPPTR, that contains the address to the endpoint configuration table. The pointer to the endpoint configuration table must be aligned to a 16-bit word; i.e., EPPTR[0] must be zero."

Ich käme jetzt nicht auf die Idee, den Speicherbereich anders auszurichten und zu hoffen, dass das trotzdem funktioniert.

Grüßle, Volker

OP #7805854
Lesenswert?

Oh wow, danke! Das macht auf einmal vielmehr Sinn. Ich kannte das Alignment-Konzept bis dahin noch nicht, und dementsprechend hab ich das wahrscheinlich als "hoffentlich unnötig" überlesen.

Und das erklärt dann wahrscheinlich auch, warum das manchmal funktioniert hat und manchmal nicht: weil sich je nach Änderung im Code manchmal irgendeine 8-Bit-Variable dazwischen schiebt.

Vielleicht noch eine Frage zum Verständnis: Wird nur der Speicher-Block selbst ausgerichtet oder werden auch darin enthaltene 8-Bit-große Variablen auf 16 Bit "gestreckt"? Dann hätte ich das nämlich genau falsch herum verstanden.

(Firma: L-E-A) #7805868
Lesenswert?

Peder schrieb:

Vielleicht noch eine Frage zum Verständnis: Wird nur der Speicher-Block selbst ausgerichtet oder werden auch darin enthaltene 8-Bit-große Variablen auf 16 Bit "gestreckt"

Hier geht's nur um den Pointer auf den RAM-Bereich mit der "endpoint configuration table". Das hat vermutlich etwas damit zu tun, wie das USB-Interface auf das RAM zugreift. Genaues weiß ich aber nicht.

Ich würde vermuten, dass der Inhalt der Tabelle vom USB-Standard vorgegeben ist, habe mich aber bislang noch nicht im Detail damit beschäftigt.

Grüßle, Volker

OP #7805986
Lesenswert?

Meine Frage bezog sich eher auf C und "align" selbst, gar nicht mal mehr bezogen auf Mikrocontroller. Wie dieser Speicherblock aussieht, steht im XMega-Manual.

Und da sich dort 8-Bit- and 16-Bit-Variablen aneinanderreihen, wollte ich wissen, ob ein "align" nur den Beginn des genannten Speicherblocks ans n*byte-Raster anpasst oder ob der Inhalt dieses Blocks auch an dieses Raster angepasst wird. (was sich meiner Meinung nach mit der Angabe im Manual beißen würde)

Sprich, wenn es sich z.B. um eine struct handelt mit 8-Bit- und 16-Bit-Membern, werden die 8-Bit-Member auf 16-Bit aufgeweitet?

(Firma: L-E-A) #7806118
Lesenswert?

Peder schrieb:

Meine Frage bezog sich eher auf C und "align" selbst, gar nicht mal mehr bezogen auf Mikrocontroller.

M.W. richtet ein C-Compiler die Elemente einer struct entsprechend den "Vorlieben" der MCU aus, also auf char bei einer 8-Bit MCU, short bei einer 16-bittigen und long bei einer 32-bittigen. Wenn er das nicht machen soll, muss man ihn explizit dazu anweisen die struct zu "packen", bei gcc mittels "attribute ((packed))"

Wie dieser Speicherblock aussieht, steht im XMega-Manual.

...und was lesen wir aus Figure 20-6. SRAM memory mapping: Jedes Element liegt an einer Byte-Grenze und die Elemente sind so geschickt angeordnet, dass das LowByte einer 16-Bit-Variablen an einer geraden Adresse beginnt, wie z.B. DATAPTRL.

Und da sich dort 8-Bit- and 16-Bit-Variablen aneinanderreihen,

Wo siehst Du da 16-Bit-Variablen? Ich sehe nur 8-bittige.

wollte ich wissen, ob ein "align" nur den Beginn des genannten Speicherblocks ans n*byte-Raster anpasst oder ob der Inhalt dieses Blocks auch an dieses Raster angepasst wird. (was sich meiner Meinung nach mit der Angabe im Manual beißen würde)

Das musst Du bei der Definition der jeweiligen struct angeben, s.o.

Warum machst Du es nicht einfach so wie in dem von Dir verwendeten Beispielcode? Ich versteh' Deine Probleme nicht.

Grüßle, Volker

OP #7806134
Lesenswert?

Volker B. schrieb:

Wo siehst Du da 16-Bit-Variablen? Ich sehe nur 8-bittige.

Ich hab H&L-Paare jeweils als 16-Bit-Variable betrachtet. Und so wie ich das sehe, tut das auch die Definition eines Endpunktes durch Microchip selbst in der io256a3u.h (auch wenn _WORDREGISTER wiederum nur eine struct aus zwei 8-Bit-Variablen ist):

1
typedef struct USB_EP_struct
2
{
3
    register8_t STATUS;  /* Endpoint Status */
4
    register8_t CTRL;  /* Endpoint Control */
5
    _WORDREGISTER(CNT);  /* USB Endpoint Counter */
6
    _WORDREGISTER(DATAPTR);  /* Data Pointer */
7
    _WORDREGISTER(AUXDATA);  /* Auxiliary Data */
8
} USB_EP_t;

Volker B. schrieb:

Warum machst Du es nicht einfach so wie in dem von Dir verwendeten Beispielcode?

Weil ich ursprünglich meinen eigenen Ansatz erstellen wollte und dann durch Reverse-Engineering verstehen wollte, warum der nicht mal bis zum Interrupt kommt. Mein eigener Ansatz deshalb, weil ich eine andere USB-Klasse brauche, weil ich was lernen möchte und weil ich ungern Code benutze, den ich nicht verstehe. Ich hätte mir das Leben bestimmt leichter machen können, ja.

Ich denke, es ist mittlerweile klar, dass ich mit Programmieren nicht meinen Lebensunterhalt verdiene. ;) Deshalb nochmal vielen Dank für deine Hilfe!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren