mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Atmega32U2, LUFA, mehrere HID Geräte


Autor: Artur H. (hohoho)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich mache gerade meine ersten Schritte mit USB mithilfe eines 
ATmega32U2.
Was ich vorhabe, ist ein Gerät, welches sowohl als MIDI Device ( HID ) 
als auch als Generic HID Device ( für normale Steuerbefehle ) angemeldet 
wird.

Mithilfe der Beispiele von LUFA ist mir auch entweder das eine oder das 
andere gelungen, aber dank USB sollte es doch möglich sein, beides auf 
einem USB-Gerät zu verbinden ( 2 Endpoints für MIDI, 2 Endpoints für 
Generic HID ).

Leider fehlt mir ein vernünftiger Ansatz, das zu schaffen, es scheitert 
an den Descriptors, insbesondere dem ConfigurationDescriptor.

Der ist bei beiden Geräten anders definiert...
für MIDI:
typedef struct
    {
      USB_Descriptor_Configuration_Header_t Config;
      USB_Descriptor_Interface_t            Audio_ControlInterface;
      USB_Audio_Interface_AC_t              Audio_ControlInterface_SPC;
      USB_Descriptor_Interface_t            Audio_StreamInterface;
      USB_Audio_Interface_MIDI_AS_t         Audio_StreamInterface_SPC;
      USB_MIDI_In_Jack_t                    MIDI_In_Jack_Emb;
      USB_MIDI_In_Jack_t                    MIDI_In_Jack_Ext;
      USB_MIDI_Out_Jack_t                   MIDI_Out_Jack_Emb;
      USB_MIDI_Out_Jack_t                   MIDI_Out_Jack_Ext;
      USB_Audio_StreamEndpoint_Std_t        MIDI_In_Jack_Endpoint;
      USB_MIDI_Jack_Endpoint_t              MIDI_In_Jack_Endpoint_SPC;
      USB_Audio_StreamEndpoint_Std_t        MIDI_Out_Jack_Endpoint;
      USB_MIDI_Jack_Endpoint_t              MIDI_Out_Jack_Endpoint_SPC;
    } USB_Descriptor_Configuration_t;

Für Generic HID:
typedef struct
    {
      USB_Descriptor_Configuration_Header_t Config;
      USB_Descriptor_Interface_t            HID_Interface;
      USB_Descriptor_HID_t                  HID_GenericHID;
          USB_Descriptor_Endpoint_t             HID_ReportINEndpoint;
          USB_Descriptor_Endpoint_t             HID_ReportOUTEndpoint;
    } USB_Descriptor_Configuration_t;

Die frage ist nun, wie bringe ich das unter einen Hut ?
Einfach beides zusammenkopieren hat nicht geholfen, dann übersteht das 
Gerät nicht mal die Enumeration-Phase.

Hätte jemand einen Tipp, wie man das angeht ?

Gruß,
Artur

Autor: René König (king)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast für mehrere Interfaces nur eine Configuration. Also eher so:
typedef struct
    {
      USB_Descriptor_Configuration_Header_t Config;
      USB_Descriptor_Interface_t            Audio_ControlInterface;
      USB_Audio_Interface_AC_t              Audio_ControlInterface_SPC;
      USB_Descriptor_Interface_t            Audio_StreamInterface;
      USB_Audio_Interface_MIDI_AS_t         Audio_StreamInterface_SPC;
      USB_MIDI_In_Jack_t                    MIDI_In_Jack_Emb;
      USB_MIDI_In_Jack_t                    MIDI_In_Jack_Ext;
      USB_MIDI_Out_Jack_t                   MIDI_Out_Jack_Emb;
      USB_MIDI_Out_Jack_t                   MIDI_Out_Jack_Ext;
      USB_Audio_StreamEndpoint_Std_t        MIDI_In_Jack_Endpoint;
      USB_MIDI_Jack_Endpoint_t              MIDI_In_Jack_Endpoint_SPC;
      USB_Audio_StreamEndpoint_Std_t        MIDI_Out_Jack_Endpoint;
      USB_MIDI_Jack_Endpoint_t              MIDI_Out_Jack_Endpoint_SPC;

      USB_Descriptor_Interface_t            HID_Interface;
      USB_Descriptor_HID_t                  HID_GenericHID;
          USB_Descriptor_Endpoint_t             HID_ReportINEndpoint;
          USB_Descriptor_Endpoint_t             HID_ReportOUTEndpoint;
    } USB_Descriptor_Configuration_t;

Im Configuration-Descriptor setzt Du nun aber bNumInterfaces auf 3 und 
sorgst dafür, das die drei Interface-Descriptoren unterschiedliche Werte 
für bInterfaceNumber aufweisen.

Da sowohl MIDI als auch Audio nicht HID ist und Du bereits für Audio 
mehrere Interface-Descriptoren hast, die logisch zusammen gehören, wirst 
Du wohl auch um den Interface Association Descriptor nicht herumkommen 
(wie ihn die Version 2 der Audio Device Class Definition sogar 
vorschreibt). Siehe: 
http://www.usb.org/developers/whitepapers/iadclass...

Autor: Artur H. (hohoho)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank schonmal für diese Informationen ...
also habe ich das richtig verstanden ... die AudioControl und 
AudioStream Interfaces in einer IAD und das GenericHID Interface in 
einer anderen IAD zusammenfassen ?

Das würde dann so aussehen ( diesmal nicht die Typdefinition, sondern 
die konkreten Werte ):
USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
{
  .Config = 
    {
      .Header                   = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration},

      .TotalConfigurationSize   = sizeof(USB_Descriptor_Configuration_t),
      .TotalInterfaces          = 3,

      .ConfigurationNumber      = 1,
      .ConfigurationStrIndex    = NO_DESCRIPTOR,
        
      .ConfigAttributes         = (USB_CONFIG_ATTR_BUSPOWERED | USB_CONFIG_ATTR_SELFPOWERED),
      
      .MaxPowerConsumption      = USB_CONFIG_POWER_MA(100)
    },

  .Audio_ControlInterface_IAD =
  {
    .Header                 = {.Size = sizeof(USB_Descriptor_Interface_Association_t), .Type = DTYPE_InterfaceAssociation},

    .FirstInterfaceIndex    = 0,
    .TotalInterfaces        = 2,

    .Class                  = 0x01,
    .SubClass               = 0x03,
    .Protocol               = 0x00,

    .IADStrIndex            = NO_DESCRIPTOR
  },
    
  .Audio_ControlInterface = 
    {
      .Header                   = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

      .InterfaceNumber          = 0,
      .AlternateSetting         = 0,
      
      .TotalEndpoints           = 0,
        
      .Class                    = 0x01,
      .SubClass                 = 0x01,
      .Protocol                 = 0x00,
        
      .InterfaceStrIndex        = NO_DESCRIPTOR      
    },
  
  .Audio_ControlInterface_SPC = 
    {
      .Header                   = {.Size = sizeof(USB_Audio_Interface_AC_t), .Type = DTYPE_AudioInterface},
      .Subtype                  = DSUBTYPE_Header,
      
      .ACSpecification          = VERSION_BCD(01.00),
      .TotalLength              = sizeof(USB_Audio_Interface_AC_t),
      
      .InCollection             = 1,
      .InterfaceNumbers         = {1},      
    },

  .Audio_StreamInterface = 
    {
      .Header                   = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

      .InterfaceNumber          = 1,
      .AlternateSetting         = 0,
      
      .TotalEndpoints           = 2,
        
      .Class                    = 0x01,
      .SubClass                 = 0x03,
      .Protocol                 = 0x00,
        
      .InterfaceStrIndex        = NO_DESCRIPTOR
    },
    
  .Audio_StreamInterface_SPC = 
    {
      .Header                   = {.Size = sizeof(USB_Audio_Interface_MIDI_AS_t), .Type = DTYPE_AudioInterface},
      .Subtype                  = DSUBTYPE_General,

      .AudioSpecification       = VERSION_BCD(01.00),
      
      .TotalLength              = (sizeof(USB_Descriptor_Configuration_t) -
                                   offsetof(USB_Descriptor_Configuration_t, Audio_StreamInterface_SPC))
    },

  .HID_IAD =
  {
    .Header                 = {.Size = sizeof(USB_Descriptor_Interface_Association_t), .Type = DTYPE_InterfaceAssociation},

    .FirstInterfaceIndex    = 2,
    .TotalInterfaces        = 1,

    .Class                  = 0x03,
    .SubClass               = 0x00,
    .Protocol               = 0x00,

    .IADStrIndex            = NO_DESCRIPTOR
  },

  .HID_Interface = 
    {
      .Header                 = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},

      .InterfaceNumber        = 0x02,
      .AlternateSetting       = 0x00,
      
      .TotalEndpoints         = 2,
        
      .Class                  = 0x03,
      .SubClass               = 0x00,
      .Protocol               = 0x00,
        
      .InterfaceStrIndex      = NO_DESCRIPTOR
    },

  .HID_GenericHID = 
    {
      .Header                 = {.Size = sizeof(USB_Descriptor_HID_t), .Type = DTYPE_HID},
                   
      .HIDSpec                = VERSION_BCD(01.11),
      .CountryCode            = 0x00,
      .TotalReportDescriptors = 1,
      .HIDReportType          = DTYPE_Report,
      .HIDReportLength        = sizeof(GenericReport)
    },

  .HID_ReportINEndpoint = 
    {
      .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
                     
      .EndpointAddress        = (ENDPOINT_DESCRIPTOR_DIR_IN | GENERIC_IN_EPNUM),
      .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
      .EndpointSize           = GENERIC_EPSIZE,
      .PollingIntervalMS      = 0x0A
    },

  .HID_ReportOUTEndpoint = 
    {
      .Header                 = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
                     
      .EndpointAddress        = (ENDPOINT_DESCRIPTOR_DIR_OUT | GENERIC_OUT_EPNUM),
      .Attributes             = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
      .EndpointSize           = GENERIC_EPSIZE,
      .PollingIntervalMS      = 0x0A
    },

... die Midi Jack Descriptoren habe ich alle aus der LUFA Demo kopiert, daher lass ich sie hier mal raus
};
funktioniert leider immer noch nicht ... beim Anstecken sucht Windows 
die Treiber, findet sie aber nicht und trägt das Gerät einfach nur als 
"USB Composite Device" ein, mit der Info, dass das Gerät nicht gestartet 
werden konnte.

Autor: René König (king)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Artur H. schrieb:
> Vielen Dank schonmal für diese Informationen ...
> also habe ich das richtig verstanden ... die AudioControl und
> AudioStream Interfaces in einer IAD und das GenericHID Interface in
> einer anderen IAD zusammenfassen ?

Das HID würde ich einfach folgen lassen. Es gibt hierfür ja nur ein 
Interface, da brauchst Du nichts zusammenzufassen.

Für den IAD musst Du den Device Descriptor aber auch anpassen, um 
anzuzeigen, dass Du eben den IAD verwenden willst (Tabelle 1-1 aus dem 
oben verlinkten PDF). Hast Du das beachtet?

> funktioniert leider immer noch nicht ... beim Anstecken sucht Windows
> die Treiber, findet sie aber nicht und trägt das Gerät einfach nur als
> "USB Composite Device" ein, mit der Info, dass das Gerät nicht gestartet
> werden konnte.

Welches Gerät? Sind beide betroffen, oder wird zumindest eines 
verwendet?

Autor: Artur H. (hohoho)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
René König schrieb:
> Das HID würde ich einfach folgen lassen. Es gibt hierfür ja nur ein
> Interface, da brauchst Du nichts zusammenzufassen.
Ok, habe ich mal gemacht.

> Für den IAD musst Du den Device Descriptor aber auch anpassen, um
> anzuzeigen, dass Du eben den IAD verwenden willst (Tabelle 1-1 aus dem
> oben verlinkten PDF). Hast Du das beachtet?
Jawohl, funktioniert immer noch nicht.

> Welches Gerät? Sind beide betroffen, oder wird zumindest eines
> verwendet?
Beide sind betroffen, keins funktioniert.
Wenn ich jedoch den kompletten Generic-HID-Teil rauskommentiere, 
funktioniert zumindest das MIDI-Device ohne Probleme ... mein Ziel ist 
aber, beides zusammen hinzukriegen.

Autor: René König (king)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Artur H. schrieb:
>       .EndpointSize           = GENERIC_EPSIZE,
>       .PollingIntervalMS      = 0x0A
>     },
> 
> ... die Midi Jack Descriptoren habe ich alle aus der LUFA Demo kopiert,
> daher lass ich sie hier mal raus
> };
> 

Das sehe ich ja jetzt erst: Wenn Du sie tatsächlich hier rausgelassen 
hast, funktioniert das auch nicht. Ich hoffe, Du hast sie weiter oben, 
also bereits vor dem HID_Interface, rausgelassen.

Ansonsten: Funktioniert das HID allein? Wenn ja, hast Du vielleicht 
Endpoint-Adressen doppelt vergeben? HID IN und HID OUT darf sich nicht 
mit Deinen MIDI Jacks beißen.

Hast Du Dir das mal mit einem Protokoll-Analyzer angesehen? Bis wohin 
läuft denn die Enumeration?

Autor: Artur H. (hohoho)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
René König schrieb:
> Das sehe ich ja jetzt erst: Wenn Du sie tatsächlich hier rausgelassen
> hast, funktioniert das auch nicht. Ich hoffe, Du hast sie weiter oben,
> also bereits vor dem HID_Interface, rausgelassen.
In der Tat, das hat nun einiges geändert ... beim Anstöpseln will er nun 
insgesamt 3 Treiber installieren ...
1) USB Composite Device, den Treiber findet er offenbar auch
2) USB Audio Device, den Treiber findet er nicht
3) USB Input Device ( also das Generic HID ), den findet er auch
Generic HID funktioniert nun, aber MIDI klappt nicht.

Endpoint Adressen habe ich 1(IN), 2(OUT) für MIDI und 3(IN), 4(OUT) für 
Generic HID, das sollte also kein Problem geben.

> Hast Du Dir das mal mit einem Protokoll-Analyzer angesehen? Bis wohin
> läuft denn die Enumeration?
Noch nicht, werd mich gleich mal auf die Suche nach solchen Programmen 
machen.

Nebenbei bemerkt: Vielen Dank für deine Geduld, René :)

Autor: René König (king)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmh. Also wenn MIDI inklusive IAD ohne das HID funktioniert, sollte es 
auch zusammen mit dem HID funktionieren. Ein Schuß ins Blaue: Stimmt die 
Kalkulation von Audio_StreamInterface_SPC.TotalLength, oder kommt da 
zusammen mit dem HID ein anderer Wert heraus?

Autor: Artur H. (hohoho)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
René König schrieb:
> Hmh. Also wenn MIDI inklusive IAD ohne das HID funktioniert, sollte es
> auch zusammen mit dem HID funktionieren. Ein Schuß ins Blaue: Stimmt die
> Kalkulation von Audio_StreamInterface_SPC.TotalLength, oder kommt da
> zusammen mit dem HID ein anderer Wert heraus?
Wow, volltreffer!
Ich habe die Länge der HID-Structs raussubtrahiert, und nun geht beides.
Vielen Dank!

Autor: Artur H. (hohoho)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Edit: Hat sich erledigt, hatte ein break an der falschen stelle gelöscht

Autor: Kaspar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entschuldigt das ich diesen alten Thread wieder ausgrabe aber ich habe 
ein sehr aehnliches problem. Ich versuche ein CDC + MIDI geraet ueber 
IAD anzumelden. An sich klappt das auch aber irgendwo laueft doch was 
schief und die CDC kommunikation bricht ab.

Bis jetzt hatte ich die Audio_StreamInterface_SPC.TotalLength noch nicht 
veraendert. Wie definiere ich denn die Laenge meines CDC-Structs? Wie 
wurde denn die laenge des HID-Structs konkret im Kode definiert und 
subtrahiert? Macht es in welcher reihenvolge ich die CDC-Endpoints und 
die MIDI-Endpoints habe?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.