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.