Forum: Projekte & Code AT90USB162 USB CDC Kommunikationsablauf


von Alexander L. (lippi2000)


Angehängte Dateien:

Lesenswert?

Hallo,

ich arbeite mich momentan mit dem AT90USB162 in USB ein und möchte 
diesen über einen COM-Port von Windows/Linux aus ansteuern. Ich möchte 
dies als CDC-Gerät umsetzen. Bis jetzt funktioniert das Auslesen der 
Standartdeskriptoren, Aktivieren der Konfiguration und die Änderung der 
Device-Adresse.

Leider funktioniert die Kommunikation mit den anderen Endpunkten für den 
Datenaustausch des µC mit dem Host nicht. Irgendwas mache ich mit dem 
Bulk-Transfer falsch.

-----------------
CDC-System
----------------
   2 Interfaces
         -> Communication Class: 1x Interrupt IN Endpunkt (EP1)
         -> Data Class: 1x Bulk IN (EP2), 1x Bulk OUT Endpunkt (EP3)

   Geräteklassen: CDC-Device, ACM (Abstract Control Model)

   Behandelte StdRequests:
              - Set_Adress
              - Get_Descriptor (DeviceDesc., Conf.Desc., StringDesc.)
              - Set_Configuration

   Behandelte klassnespezifische Requests:
              - Set_Line_Coding
              - Get_Line_Coding
              - Set_Control_Line_State

Erfolgreiche Initialisierung siehe Wireshark-Log 
"CDC_Initialisierung.png".

------------------
Firmware
------------------
Der Endpunkt EP0 (Control EP) wird über den SETUP-IRQ behandelt. Alle 
anderen IRQ's nur durch pollen abgefragt.

Nach der Initialisierung wird der AVR unter Ubuntu /dev/ttyACM0 
aufgeführt und unter Windows 7 als COM-Port im Gerätemanager aufgeführt.
Bis jetzt hängt sich allerdings Windows auf, sobald man den COM-Port 
öffnet. Daher erst einmal die Analyse in Ubuntu.

Nach der Initialisierung wird dem Device mit Set_Control_Line_State 
mitgeteilt, dass die DTE nicht verfügbar ist. Anschließend werden die 
Konfigurationsdaten (Baudrate, Daten-/Stopbits, Parität) mitgeteilt.
Es findet kein weiterer Transfer statt.

Wird die COM-Schnittstelle (dev/ttyACM0) über ein Terminalprogramm 
geöffnet, laufen einige Abfragen (Bulk IN, Bulk OUT) ab, die ich noch 
nicht ganz nachvollziehen kann. Letztendlich wird aber über den EP0 
mittels Set_Control_Line_State = 0x0003 signalisiert, dass die DTE 
verfügbar ist. Es findet jetzt keine weitere Kommunikation statt.

Warum???? Sollte nicht zyklisch der Eingangspuffer mittels Bulk IN 
abgefragt werden???

Jedes in das Terminalprogramm eingetippte Zeichen wird einzeln über 
einen Bulk-Transfer übertragen (ist im Wireshark ersichtlich). Nur der 
Eingangspuffer wird nicht abgefragt.



Im Hauptprogramm gibt es eine Endlosschleife, in der die Endpunkte des 
Data Class Interface abgefragt werden. Der Interrupt Endpunkt des 
Communication Interfaces wird momentan überhaupt nicht behandelt.
1
void USB_Device_Service(void)
2
{
3
  U8 rx_data_ready = 0;
4
  
5
  if ( USB_State & USB_Connected_bm )
6
  {
7
    
8
    /*
9
    *  USB CDC DATAIN endpoint
10
    */
11
    Usb_select_EP(CDC_DATAIN_EP);
12
    if ( Is_usb_TXIN_IRQ_set() )
13
    {
14
      usb_write_IN_data(&UART_TX_BUFFER[0], sizeof(UART_TX_BUFFER));
15
      rx_data_ready = FALSE;
16
    }
17
    
18
    /*
19
    *  USB CDC DATAOUT endpoint 
20
    */
21
    Usb_select_EP(CDC_DATAOUT_EP);
22
    if ( Is_usb_RXOUT_IRQ_set() )
23
    {
24
      usb_read_OUT_data(&UART_TX_BUFFER[0], sizeof(UART_TX_BUFFER));
25
      rx_data_ready = TRUE;
26
            
27
    }
28
  
29
  } 
30
  else
31
  {
32
    usb_init_device();
33
    USB_State |= USB_Connected_bm;
34
    Usb_enable_EORST_IRQ();
35
  }
36
  
37
  
38
}
Stimmt die Kommunikation des Bulk-Transfers?
1
uint16_t usb_read_OUT_data(unsigned char *pBuffer, unsigned int bLength)
2
{
3
  U8 buffer_byte_counter = 0;
4
  U16 read_counter = 0;
5
  
6
  
7
  Ack_RXOUT_IRQ();
8
  buffer_byte_counter = Usb_FIFO_Bytes();
9
  if ( buffer_byte_counter == 0 )
10
  {
11
    //zlp from host
12
    Ack_FIFOCON_IRQ();
13
    return read_counter;
14
  }
15
  
16
  while (buffer_byte_counter != 0)  
17
  {
18
      *pBuffer++ = Usb_FIFO();
19
      buffer_byte_counter--;
20
      read_counter++;
21
      if ( buffer_byte_counter == 0 )
22
      {
23
        // all bytes read
24
        Ack_FIFOCON_IRQ();
25
        return read_counter;
26
    
27
      }
28
  }
29
  
30
}
31
32
33
void usb_write_IN_data(unsigned char *pBuffer, unsigned int bLength)
34
{
35
  Ack_NAKIN_IRQ();    // clear FIFO and finish STATUS stage
36
  
37
  
38
  while (bLength != 0)
39
  {
40
    // wait until there are space in FIFO memory
41
    while ( !Is_usb_TXIN_IRQ_set() );
42
    Ack_TXIN_IRQ();
43
    //write data until all date written or FIFO full
44
    while ( (bLength != 0) && !Is_usb_RWAL_IRQ_set() )
45
    {
46
      Usb_FIFO() = *pBuffer++;
47
      bLength--;
48
      break;
49
    }
50
    
51
    Ack_FIFOCON_IRQ();    //send FIFO data to host
52
53
  }

Ich habe den kompletten Framemitschnitt von Wireshark mal angehängt. Am 
besten die Filtereinstellung 
(usb.device_adress==0)||(usb.device_adress==5) setzen, damit nicht der 
gesamte Traffic angezeigt wird.

von Peter (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Alexander,

ich habe Dir mal zwei Screenshots angehängt, wie die Enumeration 
auszusehen hat.

Nach der Enumeration geht es dann mit den Anfragen an den IN-EP weiter.

Gruß Peter

von Alexander L. (lippi2000)


Lesenswert?

Danke Peter für die Frameanalyse.

Die Enumeration läuft und das OS erkennt erfolgreich ein CDC - Device.

Windows 7 64Bit: COM-Port
Ubuntu 12 32Bit: dev/ttyACM0  CDC - Device

Die Einstellung von Baudrate, Stop-/Datenbits durch das OS funktioniert 
auch.

Ich habe jetzt den AVR im Debug-Modus (JTAG ICE debugWire).

Ich Hänge an folgender Stelle:
Im Wireshark sehe ich, das ein Bulk OUT - Transfer vom Host an EP3 
(CDC_DATAOUT_EP) gesendet wird. z.B. wenn ich Daten über ein Terminal 
versende.

In einer Endlosschleife des Hauptprogrammes wird  "Usb_Device_Service()" 
(siehe letzter Post) ausgeführt. Setze ich einen Breakpoint nach der 
Abfrage ob RXOUT-IRQ am Bulk OUT-EP gesetzt ist, wird dieser nie 
erreicht.

 - Konfiguration des EP wird nach Set-Configuration während der 
Enumeration durch das Flag CFGOK = 1 erfolgreich gemeldet
- keine Fehlermeldungen (Broken Pipes etc. vom OS) während und nach der 
Enumeration

Es werden auch alle im Terminal eingegeben Zeichen gesendet, aber nicht 
durch den USB Controller erkannt.

Leider habe ich keinen Hardware-Protokollanalyser. Ich arbeite mit 
Wireshark unter Ubuntu, welches in einer VM in Windows 7 läuft. Somit 
kann ich gleichzeitig die Frames in Ubuntu analysieren und im AVR Studio 
6 debuggen.

Die USB Transaktionsabläufe sind mir klar. Nur der USB Controller des 
AT90USB162 ist sehr schlecht dokumentiert. Die Abbildungen im Datenblatt 
sind mit Vorsicht zu genießen.

Wie läuft ein ordentlicher IN und OUT Transfer?

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.