; USB Protokollaufzeichnung ; Die vorliegende Software kann mit der Programmiersoftware FLIP von Atmel mit Hilfe des Bootstrap Loader des 89C5131 in das Flash des Controllers geschrieben werden http://www.atmel.com/dyn/resources/prod_documents/flip-2_4_2.zip ; Schreibt alle über den USB-Bus eingehenden Daten in das IXRAM ab Adresse 0000. ; Hardware vgl. Atmels Demo-Board (Schaltplan online erhältlich: http://www.atmel.com/dyn/resources/prod_documents/doc4371.pdf) ; LED an P3.3, P3.5, P3.6 zeigen interne Zustände an ; Das IXRAM kann über die serielle Schnittstelle (8, N, 1, 19200 Baud) gelesen werden. ; Serielle Befehle: ; 'q' liest das IXRAM von 0000h bis 00F0h. ; 'y' löscht das IXRAM, es wird mit FFh beschrieben. ; 'a' zeigt alle USB-Register für Endpoint 0 an. ; 'b' zeigt alle USB-Register für Endpoint 1 an. ; 'v' sendet 8 Byte '-Hallo--' über Endpoint 1 an den Host. ; Verwenden Sie zur seriellen Kommunikation unser serielles Terminalprogramm www.controllertechnik.de/download/terminal.zip. ; Die Kommunikationsversuche haben nur mit dem USB-Treiber von ; Thesycon® Systemsoftware & Consulting GmbH ; Werner-von-Siemens-Str. 2 - D-98693 Ilmenau - GERMANY ; Tel: +49 3677 / 8462-0 ; Fax: +49 3677 / 8462-18 ; e-mail: USBIO@thesycon.de ; http://www.thesycon.de genauer: http://www.thesycon.de/deu/usbio_demo.shtml ; brauchbare Ergebnisse gezeigt. ; Thesycon® bietet eine Demo-Version an mit voller Funktionalität, sie läuft vier Stunden, danach muss der Rechner gebootet werden und sie läuft wieder vier Stunden etc. ; Die Light-Version unterstützt nur zwei Endpoints, läuft dafür aber uneingeschänkt. ; Die Systemtreiber von Windows (HID-Class) zusammen mit der Beispiel-Firmware von Atmel 'usb_kbd' funktionierten unter XP nicht, unter Win98 haben sie das System zerschossen, sie waren also unbrauchbar. ; Die nachfolgende Software baut auf Atmels Beispiel-Firmware auf (diese stammt nicht von Atmel, sondern wurde einer französischen Firma in Auftrag gegeben http://www.atmel.com/dyn/resources/prod_documents/c5131-usb-kbd-stand-alone-1_0_2.zip). Sie benutzt im Gegensatz zum nachfolgenden Beispiel nicht die Polling-Methode, sondern benutzt die USB-Interrupts. Dabei hat sich herausgestellt, dass im Chip ein Hardwarefehler existiert. Dieser setzt die USB Interrupt Freigaberegister nach den erten beiden USB Dateneingängen stets auf ihre Resetwerte, sodass zu Beginn der USB-Interrupt nicht verwendbar ist. Atmel schweigt dazu. #cpu = 89C5131 ; @ 24 MHz ; Sie benötigen den 89C5131 CPU-Treiber ? www.Controllertechnik/download/89C5131.cpu ; Sie benötigen den passenden Assembler ? www.Controllertechnik/download/assv4.zip (4MB) #Byte 1kHz Teiler, 50 Hz Teiler, 4 Hz Teiler, 1 Hz Teiler, Serieller Pointer #Byte USB Configuration number, Endpoint 1 Status, Endpoint 0 Status, HID Idle Dauer #Byte Descriptorlänge, Descriptoradresse MSB, Descriptoradresse LSB #Byte bmRequestType, bRequest, wValueLow, wValueHigh, wIndexLow, wIndexHigh, wLengthLow, wLengthHigh ; Reihenfolge beibehalten ! #Byte Eingangsbyte #Bit 1 Sekunde vollendet, 4 Hz, Tastenabfrage, Zero Length Packet #Bit TXCMPL = acc.0, RXSETUP = acc.2, STLCRC = acc.3 #Bit Suspend Interrupt = acc.0, Start of Frame Interrupt = acc.3, End Of Reset Interrupt = acc.4, Wake Up CPU Interrupt = acc.5 #Bit Sendebusy, Empfang #def lösche TXCMPL {anl UEPSTAX, #FEh} #def setze STALLRQ {orl UEPSTAX, #20h} #def lösche STALLRQ + STLCRC {anl UEPSTAX, #D7h} #def lösche STALLRQ {anl UEPSTAX, #DFh} #def lösche RXSETUP {anl UEPSTAX, #FBh} #def lösche RXOUTB0 {anl UEPSTAX, #FDh} #def setze TXRDY {orl UEPSTAX, #10h} #def lösche TXRDY {anl UEPSTAX, #EFh} #def lösche DIR und RXOUTB0 {anl UEPSTAX, #7Dh} #def lösche DIR {anl UEPSTAX, #7Fh} #use lcall ; Programmstart sjmp Initialisierung Timer 0: ; Timer 0 Interupt sjmp Timer 0 Interrupt SINT: ; serieller Interrupt ; Herkunft ermitteln if bit TI then ; Senden clr TI: clr Sendebusy else ; Empfangen clr RI: setb Empfang end if reti Timer 0 Interrupt: djnz 1kHz Teiler, reti mov 1kHz Teiler, #10 ; f = 1 kHz, 1 ms djnz 50 Hz Teiler, hier + 8 50 Hz Teiler = #20 ; f = 50 Hz setb Tastenabfrage djnz 4 Hz Teiler, Reti mov 4 Hz Teiler, #250 ; f = 4 Hz setb 4 Hz djnz 1 Hz Teiler, Reti mov 1 Hz Teiler, #4 ; f = 1 Hz setb 1 Sekunde vollendet Reti: reti Initialisierung: clr a for r0 = #0: @r0 = a: next ; alle Bits und Bytes löschen SP = #BFh inc AUXR ; ALE abschalten sjmp USB Initialisierung USB: ; = USB Interrupt Vector ajmp USB Interrupteinsprung USB Initialisierung: 1 kHz Teiler = #10: 50 Hz Teiler = #20: 4 Hz Teiler = #250: 1 Hz Teiler = #4 WDTPRG = #4h ; Watchdog Periode = 131 ms Serieller Pointer = #30h: a = #FFh for r7 = #FFh: movx @dptr, a: inc dptr: next ; Timer 0 als Zeitbasis orl CKCON0, #2 ; 12 Takte für Timer 0 Inkrement orl TMOD, #2 ; Timer 0 im 8-Bit Autoreload-Modus ; Die Überlauffrequenz des Timer 0 beträgt 10000 Hz, die Periodendauer 0,1 ms. TH0 = #38h ; Reloadwert setb TR0 ; Timer 0 läuft. ; Serieller Port mov SCON, # 50h ; Modus 1, asynchron, 10 Bit, Baudrate Timer 1/2 Überlauf, Datenempfang freigeben RCAP2L = # D9h: RCAP2H = # FFh ; Reloadwerte für 19230,77 Baud mov T2CON, # 34h ; Timer 2 als Baudratengenerator, Timer 2 Run ; Interrupts setb ES: setb ET0: setb PT0L ; Timer 0 Interrupt freigeben orl IPL0, #10h: orl IPH0, #10h ; serieller Port höchste Priorität setb EA ; globale Interruptfreigabe orl USBCON, #80h ; setb USB Enable orl USBCON, #10h ; setb DETACH PLLDIV = #10h ; @ 24 MHz orl PLLCON, #2 ; setzt PLL Enable Bit loop: a = PLLCON: until bit acc.0 ; auf PLL Lock Indicator warten loop: a = 50 Hz Teiler: until a = #15 ; 5 ms warten anl USBCON, #EFh ; clr DETACH xrl UEPRST, #1: xrl UEPRST, #1 ; Endpoint 0 FIFO Reset acall USB Variableninitialisierung IEN1 = #40h ; USB Interrupt enable ; ________ Hauptprogramm Start ________ loop USBIEN = #0 ; Reset Interrupt abschalten, wegen Hardwarefehler UEPIEN = #3 ; Endpoint 0 und 1 Interrupt freigeben clr EA: WDTRST = #1Eh: WDTRST = #E1h: setb EA ; Watchdog Reset if bit 4 Hz then clr 4 Hz cpl P3.5 end if if bit Empfang then ; serieller Port IEN1 = #0 a = SBUF if a = #'a' then UEPNUM = #0: Register senden elseif a = #'b' then UEPNUM = #1: Register senden elseif a = #'q' then acall XRAM senden elseif a = #'y' then acall XRAM löschen cpl P3.6 ; als optischer Test elseif a = #'v' then Eingangsbyte = a ; sendet 8-Byte-Text: '-Hallo--' end if clr Empfang IEN1 = #40h end if acall USB EP1 Daten senden end loop ; ________ Hauptprogramm Ende ________ USB EP1 Daten senden: IEN1 = #0 ; USB Interrupt aus a = Eingangsbyte if a = #'v' then Eingangsbyte = #0 dptr = #Data Hallo: UEPNUM = #1 for r7 = #8 clr a: movc a, @a+dptr: inc dptr ; sendet '-Hallo--' UEPDATX = a next setze TXRDY ; Daten absenden UEPNUM = #0 end if IEN1 = #40h ; USB Interrupt aus ret XRAM löschen: inc AUXR1 dptr = #0: a = #FFh for r7 = #FFh: movx @dptr, a: inc dptr: next dptr = #0 dec AUXR1 ret XRAM senden: dptr = #0 for r7 = #F0h movx a, @dptr: inc dptr: Sende next ret USB Interrupteinsprung: a = UEPINT ; Endpoint Interruptnummer if a > #0 then UEPNUM = #0 ; Endpunkt 0 wählen a = UEPSTAX if bit RXSETUP then: USB Read Request: end if ; Enumeration Process UEPNUM = #1 ; Endpunkt 1 wählen a = UEPSTAX if bit TXCMPL then ; Transmitted IN Data Complete lösche TXCMPL cpl P3.3 end if end if reti USB Variableninitialisierung: r0 = #Endpoint 0 Status: clr a @r0 = a: inc r0: @r0 = a ; Endpoint 1 Status USB Configuration number = a ret USB clr RXSETUP setb DIR: lösche RXSETUP: orl UEPSTAX, #80h ; setb DIR ret USB RXSETUP und TXRDY setzen: lösche RXSETUP: setze TXRDY ret RXSETUP clr STALLRQ set: lösche RXSETUP: setze STALLRQ ret FIFO 0 beschreiben: ; Anzahl der Daten in r5 if r5 = #0 then ret UEPNUM = #0 r0 = #Descriptoradresse MSB DPH = @r0: dec r0: DPL = @r0 a = @r0: add a, r5: @r0 = a: inc r0 ; Descriptoradresse + Zahl der Daten a = @r0: addc a, #0: @r0 = a for r5 clr a: movc a, @a+dptr ; Datentabelle lesen UEPDATX = a ; Endpoint FIFO beschreiben inc dptr next ret USB Daten senden: ; Rückgabe RXOUTB0/1 in a setze TXRDY loop a = UEPSTAX: anl a, #43h ; auf RXOUTB0/1 oder TXCMPL warten until a > #0 lösche TXCMPL a = UEPSTAX: anl a, #42h ; RXOUTB0/1 testen ret USB Read Request: ; This function reads the SETUP request sent to the default control endpoint ; and the appropriate function. When exiting of the Usb Read Request ; function, the device is ready to manage the next request ; __________ Daten protokollieren __________ inc AUXR1 ; Datenpointer 1 verwenden a = UBYCTLx: movx @dptr, a: inc dptr ; Anzahl r0 = #bmRequestType for r6 = a ; beschreibt das IXRAM und die Register bmRequestType, bRequest, wValueLow, wValueHigh, wIndexLow, wIndexHigh, wLengthLow, wLengthHigh a = UEPDATX: movx @dptr, a: @r0 = a inc dptr: dec r0 next dec AUXR1 ; __________ Daten protokollieren __________ a = bRequest ; Standardrequest, falls bmRequestType = 0 cjne a, #0Bh, hier + 3 ; ändert das Carry jnc Urr Default ; es werden nur Requests < #0Bh berücksichtigt. dptr = #Sprungtabelle: r0 = a: add a, r0: add a, r0 ; mal 3 jmp @a+dptr Sprungtabelle: ljmp Urr Get Status ; 0 = Request Nummer ljmp Urr Clear Feature ; 1 ljmp Urr HID Get Idle ; 2 ljmp Urr Set Feature ; 3 ljmp Urr Default ; 4 ljmp Urr Set Address ; 5 ljmp Urr Get Descriptor ; 6 ljmp Urr Default ; 7 ljmp Urr Get Configuration ; 8 ljmp Urr Set Configuration ; 9 ljmp Urr Get Interface ; Ah Urr Get Status: lcall USB Get Status sjmp Urr Exit Urr Clear Feature: lcall USB clear feature sjmp Urr Exit Urr HID Get Idle: lcall USB HID Get Idle sjmp Urr Exit Urr Set Feature: lcall USB Set Feature sjmp Urr Exit Urr Set Address: lcall USB Set Address sjmp Urr Exit Urr Get Descriptor: lcall USB Get Descriptor sjmp Urr Exit Urr Get Configuration: lcall USB Get Configuration sjmp Urr Exit Urr Set Configuration: a = bmRequestType if a = #0 then lcall USB Set Configuration sjmp Urr Exit end if lcall USB HID Set Report ; wenn bmRequestType = 21h sjmp Urr Exit Urr Get Interface: a = bmRequestType if a = #81h then lcall USB Get Interface sjmp Urr Exit end if lcall USB HID Set Idle ; wenn bmRequestType = 21h sjmp Urr Exit Urr Default: ; bei nicht unterstützten Requests wird STALL gesendet lcall RXSETUP clr STALLRQ set loop: a = UEPSTAX: until bit STLCRC lösche STALLRQ + STLCRC Urr Exit: lösche DIR ret USB Get Status: r7 = wIndexLow USB clr RXSETUP setb DIR a = bmRequestType if a = #80h then ; Gerät, Richtung IN UEPDATX = #1 elseif a = #81h then ; Interface UEPDATX = #0 elseif a = #82h then ; Endpoint, Nummer in r7 if r7 = #0 then: UEPDATX = Endpoint 0 Status else: UEPDATX = Endpoint 1 Status: end if end if UEPDATX = #0: setze TXRDY loop loop: a = UEPSTAX: until bit TXCMPL until not bit RXSETUP ; kann doch nicht richtig sein ??!! ; when a valid SETUP packet has been received from the host, führt das zu einer Endlosschleife. lösche TXCMPL loop loop: a = UEPSTAX: anl a, #42h: until a > #0 a = UEPSTAX until not bit RXSETUP ; kann doch nicht richtig sein ??!! lösche DIR und RXOUTB0 ret USB clear feature: a = bmRequestType: anl a, #FEh if a = #0 then ; Gerät OUT oder Interface OUT, wird mit STALL beantwortet. RXSETUP clr STALLRQ set loop: a = UEPSTAX: until bit STLCRC lösche STALLRQ ret end if if a = #2 then ; Endpoint OUT a = wValueLow if a = #0 then ; if wValue LSB = 0 a = wIndexLow ; = Endpoint Nummer jz Ucf1 ; If Endpoint = 0 if a = #81h then ; If Endpoint = 1, 81h = Endpoint 1 IN UEPNUM = #1: lösche STALLRQ UEPRST = #2: clr a: UEPRST = a ; FIFO 1 Reset UEPNUM = a: Endpoint 1 Status = a Ucf1: USB RXSETUP und TXRDY setzen loop: a = UEPSTAX: until bit TXCMPL ; Sendvorgang abwarten lösche TXCMPL ret end if ; sonst RXSETUP clr STALLRQ set loop: a = UEPSTAX: until bit STLCRC ; Sendvorgang abwarten lösche STALLRQ end if end if ret USB HID Get Idle: USB clr RXSETUP setb DIR UEPDATX = HID Idle Dauer setze TXRDY ; ZLP als STATUS senden loop: a = UEPSTAX: until bit TXCMPL ; Sendvorgang abwarten lösche TXCMPL loop: a = UEPSTAX: anl a, #42h: until a > #0 ; Empfang abwarten lösche DIR und RXOUTB0 ret USB Set Feature: a = bmRequestType: anl a, #FEh if a = #0 then ; Gerät oder Interface, wird mit STALL beantwortet RXSETUP clr STALLRQ set loop: a = UEPSTAX: until bit STLCRC ; Sendvorgang abwarten lösche STALLRQ ret end if if a = #2 then ; Endpoint a = wValueLow if a = #0 then a = wIndexLow if a = #81h ; if Endpoint 1, 81h = Endpoint1 Richtung IN UEPNUM = #1 setze STALLRQ UEPNUM = #0: Endpoint 1 Status = #1 USB RXSETUP und TXRDY setzen loop: a = UEPSTAX: until bit TXCMPL lösche TXCMPL ret end if ; sonst RXSETUP clr STALLRQ set loop: a = UEPSTAX: until bit STLCRC lösche STALLRQ + STLCRC end if end if ret USB Set Address: r7 = wValueLow ; = Adresse USB RXSETUP und TXRDY setzen ; send a ZLP for STATUS phase orl USBCON, #1 ; setb FADDEN loop: a = UEPSTAX: until bit TXCMPL ; Sendevorgang abwarten lösche TXCMPL USBADDR = r7: orl USBADDR, #80h ; bit FEN setzen und Adresse schreiben ret USB Get Descriptor: clr Zero Length Packet ; no zero length packet r7 = wValueLow ; = String Type r6 = wValueHigh ; = Descriptor Type if r6 = #1 then ; Descriptor Type = Device Descriptorlänge = #12h Descriptoradresse MSB = #high(Data Device Descriptor) ; Tabellenadresse Descriptoradresse LSB = #low(Data Device Descriptor) ajmp Descriptor Main end if if r6 = #2 then ; Descriptor Type = Configuration Descriptorlänge = #5Dh Descriptoradresse MSB = #high(Data Configuration Descriptor) Descriptoradresse LSB = #low(Data Configuration Descriptor) ; schickt alle Daten ab Data Configuration Descriptor bis einschließlich Data Report ajmp Descriptor Main end if if r6 = #21h then ; Descriptor Type = HID Descriptorlänge = #9 Descriptoradresse MSB = #high(Data HID Descriptor) Descriptoradresse LSB = #low(Data HID Descriptor) ajmp Descriptor Main end if if r6 = #22h then ; Descriptor Type = Report Descriptorlänge = #3Bh Descriptoradresse MSB = #high(Data Report) Descriptoradresse LSB = #low(Data Report) sjmp Descriptor Main end if ; if r6 = #6 then ; Get Device Qualifier ; if r6 = #7 then ; Get other Configuration if r6 = #3 then ; Descriptor Type = String if r7 = #0 then ; String Type = Language ID Descriptorlänge = #4 Descriptoradresse MSB = #high(Data String Descriptor Language ID) Descriptoradresse LSB = #low(Data String Descriptor Language ID) sjmp Descriptor Main end if if r7 = #1 then ; Descriptor Type = Manufacturer Index Descriptorlänge = #12 Descriptoradresse MSB = #high(Data String Descriptor manufacturer) Descriptoradresse LSB = #low(Data String Descriptor manufacturer) sjmp Descriptor Main end if if r7 = #2 then ; Descriptor Type = Product Index Descriptorlänge = #38h Descriptoradresse MSB = #high(Data String Descriptor Product Name) Descriptoradresse LSB = #low(Data String Descriptor Product Name) sjmp Descriptor Main end if if r7 = #3 then ; Descriptor Type = Serial Number Descriptorlänge = #12 Descriptoradresse MSB = #high(Data String Descriptor Serial Number) Descriptoradresse LSB = #low(Data String Descriptor Serial Number) sjmp Descriptor Main end if end if ; Wenn keine der vorstehenden Bedingungen zutrifft, wird ein STALL zurückgegeben: RXSETUP clr STALLRQ set loop a = UEPSTAX if bit STLCRC then exit loop until not bit RXSETUP ; diese Konstruktion ist äußerst bedenklich ! anl UEPSTAX, #57h ; clr STLCRC, clr STALLRQ, clr DIR ret Descriptor Main: ; Ist die Fortsetzung von USB Get Descriptor a = wLengthLow: setb c: subb a, Descriptorlänge a = wLengthHigh: subb a, #0 if not bit c then ; die angeforderten Daten sind größer als die Descriptorlänge. a = Descriptorlänge: anl a, #1Fh if a = #0 then: setb Zero Length Packet: end if ; ZLP wird bei Descriptorlänge mod 20h = 0 benötigt. else ; angeforderte Daten <= Descriptorlänge Descriptorlänge = wLength low ; es wird nur die angeforderte Zahl an Daten gesendet. end if Descriptor Main 1: ; Sendet längere Daten in Paketen von 32 Byte: USB clr RXSETUP setb DIR loop a = Descriptorlänge: setb c: subb a, #20h if bit c then exit loop ; Descriptorlänge <= 20h r5 = #20h a = Descriptorlänge: clr c: subb a, r5: Descriptorlänge = a FIFO 0 beschreiben ; Zahl der Daten in r5 USB Daten senden ; Rückgabe RXOUTB0/1 in a jnz L0180h ; bei Abbruch durch den Host end loop ; Restliche Daten senden r5 = Descriptorlänge: Descriptorlänge = #0 FIFO 0 beschreiben ; Zahl der Daten in r5 USB Daten senden ; Rückgabe RXOUTB0/1 in a jnz L0180h ; bei Abbruch durch den Host if bit Zero Length Packet then USB Daten senden ; ZLP senden if a > #0 then ; bei Abbruch durch den Host L0180h: lösche TXRDY sjmp L019Eh end if end if loop a = UEPSTAX: anl a, #46h ; auf RXOUTB0/1 oder RXSETUP warten until a > #0 if not bit RXSETUP then anl a, #42h if a > #0 then ; RXOUTB1 oder RXOUTB0 lösche DIR ; clr DIR L019Eh: lösche RXOUTB0 end if end if ret USB Get Configuration: USB clr RXSETUP setb DIR UEPDATX = USB Configuration number setze TXRDY ; Senden starten loop: a = UEPSTAX: until bit TXCMPL ; Übertragungsende abwarten lösche TXCMPL loop: a = UEPSTAX: anl a, #42h: until a > #0 ; Antwort abwarten lösche DIR und RXOUTB0 ret USB Set Configuration: a = wValueLow ; Configuration Number lesen anl UEPSTAX, #7Bh ; clr DIR, clr RXSETUP if a = #0 then ; falls Configuration Number = 0 USB Configuration number = a anl USBCON, #FDh ; Configured löschen elseif a = #1 then ; oder 1 USB Configuration number = a orl USBCON, #2 ; Configured setzen else ; sonst STALL an Host senden setze STALLRQ loop: a = UEPSTAX: until bit STLCRC lösche STALLRQ + STLCRC ret end if setze TXRDY ; sendet ein ZLP als Antwort loop: a = UEPSTAX: until bit TXCMPL lösche TXCMPL UEPNUM = #1: UEPCONX = #87h ; Endpoint 1 = Interrupt IN UEPRST = #2: UEPRST = #0 ; Endpoint 1 FIFO Reset ret USB HID Set Report: ; Diese Routine kann verwendet werden, wenn der HID Set Report keine USB-Standardanforderung ist, sondern von Request-Type Class, Vendor, Interface, Endpoint und/oder Other ist. ; Dann können zusätzliche Daten vom Host an das Gerät geschickt werden. lösche RXSETUP ; wartet auf eingehende Daten = Paketspeicherung im FIFO, kann bis zu 20 µs dauern: loop: a = UEPSTAX: anl a, #42h: until a > #0 ; Bits RXOUTR0/1 ; __________ Daten protokollieren __________ a = bmRequestType if a = #43h then ; Type Vendor, Recipient Other inc AUXR1 for r6 = wLengthLow ; in wLengthLow steht die Zahl nachfolgender Daten a = UEPDATX: movx @dptr, a: inc dptr next dec AUXR1 end if ; __________ Daten protokollieren __________ lösche RXOUTB0 setze TXRDY ; antwortet mit einem ZLP loop: a = UEPSTAX: until bit TXCMPL lösche TXCMPL ret USB Get Interface: USB clr RXSETUP setb DIR setze STALLRQ ; Stall senden, d.h. diese Anforderung wird nicht unterstützt. loop: a = UEPSTAX: until bit STLCRC ; bit STLCRC testen anl UEPSTAX, #5Eh ; clr STALLRQ, clr TXCMPL, clr DIR ret USB HID Set Idle: HID Idle Dauer = wValueHigh USB RXSETUP und TXRDY setzen ; ZLP als Antwort senden loop: a = UEPSTAX: until bit TXCMPL lösche TXCMPL ret Seriellen Stack beschreiben: r0 = #Serieller Pointer @r0 = a: inc Serieller Pointer ret Sende: ; Sendewert in a jb Sendebusy, hier ; auf Sendefreigabe warten mov SBUF, a setb Sendebusy ret Bin to Hex: r7 = a: anl a, #F0h: swap a: Bin to Hex 2 a = r7: anl a, #0Fh Bin to Hex 2: clr c: subb a, #10 if bit c then: add a, #'0' + 10: else: add a, #'A': end if sjmp Sende Register senden: dptr = #Registertext Register senden 1: a = USBCON: Bin to Hex Register senden 1: a = USBINT: Bin to Hex Register senden 1: a = USBIEN: Bin to Hex Register senden 1: a = USBADDR: Bin to Hex Register senden 1: a = UEPNUM: Bin to Hex Register senden 1: a = UEPCONx: Bin to Hex Register senden 1: a = UEPSTAx: Bin to Hex Register senden 1: a = UEPDATx: Bin to Hex Register senden 1: a = UBYCTLx: Bin to Hex Register senden 1: a = UBYCTHx: Bin to Hex Register senden 1: a = UEPRST: Bin to Hex Register senden 1: a = UEPINT: Bin to Hex Register senden 1: a = UEPIEN: Bin to Hex Register senden 1: a = UFNUMH: Bin to Hex Register senden 1: a = UFNUML: Bin to Hex ret Register senden 1: loop clr a: movc a, @a+dptr inc dptr if a = #0 then ret Sende end loop Registertext: DB ' USBCON:', 0, ' USBINT:', 0, ' USBIEN:', 0, ' USBADDR:', 0, ' UEPNUM:', 0, ' UEPCONx:', 0, ' UEPSTAx:', 0, ' UEPDATx:', 0, ' UBYCTLx:', 0, ' UBYCTHx:', 0, ' UEPRST:', 0, ' UEPINT:', 0, ' UEPIEN:', 0, ' UFNUMH:', 0, ' UFNUML:', 0 Data Hallo: DB '-Hallo--' ; USB-Descriptoren: Data Device Descriptor: DB 12h ; Descriptor Länge = 18 Byte DB 1 ; Kennung = Device DB 10h, 01h ; USB Version = 1.1 DB 0 ; Device Class DB 0 ; Device SubClass DB 0 ; Device Protocol DB 20h ; Control-Endpunkt Länge = 32 Byte DB EBh, 03h ; Vendor ID = 03EBh = Atmel DB 03h, 20h ; Product ID: 2003h = HID keyboard DB 00h, 01h ; Release Nummer DB 1 ; Stringindex für den Hersteller = Data String Descriptor manufacturer DB 2 ; Stringindex für das Produkt = Data String Descriptor Product Name DB 3 ; Stringindex für die Seriennummer = Data String Descriptor Serial Number DB 1 ; Anzahl möglicher Konfigurationen Data String Descriptor manufacturer: DB 12d, 3, 'A', 00h, 'T', 00h, 'M', 00h, 'E', 00h, 'L', 00h Data String Descriptor Product Name: DB 38h, 3, 'A', 0, 'T', 0, '8', 0, '9', 0, 'C', 0, '5', 0, '1', 0, '3', 0, '1', 0, ' ', 0, 'E', 0, 'v', 0, 'a', 0, 'B', 0, ' ', 0, 'H', 0, 'I', 0, 'D', 0, ' ', 0, 'K', 0, 'e', 0, 'y', 0, 'b', 0, 'o', 0, 'a', 0, 'r', 0, 'd', 0 Data String Descriptor Serial Number: ; = 1.0.0 DB 12d, 3, '1', 0, '.', 0, '0', 0, '.', 0, '0', 0 Data String Descriptor Language ID: ; = 0007h = deutsch DB 4, 3, 7, 0 ; Ab hier Reihenfolge nicht ändern! Data Configuration Descriptor: DB 9 ; Descriptor Länge DB 2 ; Konfiguration DB 22h, 0 ; Gesamtlänge der Daten (34 Byte, Conf+Interf+HID+Endpoint) DB 1 ; unterstützte Schnittstellen DB 1 ; Konfigurationswert DB 0 ; Index des String Descriptors (0 = keiner) DB 40h ; Konfiguration (80h = Stromversorgung über Bus) DB 0 ;32h ; maximale Stromaufnahme (100 mA) Data Interface Descriptor: DB 9 ; Descriptor Länge DB 4 ; Interface DB 0 ; Interfacenummer DB 0 ; alternative Einstellung DB 1 ; Zahl der unterstützten Endpunkte DB 3 ; Klassencode (3 = HID) DB 0 ; Subklassencode (0 = keiner) DB 0 ; Protokollcode (0 = keiner) DB 0 ; Index der Zeichenkette (0 = keiner) Data HID Descriptor: DB 9 ; Descriptor Länge DB 21h ; HID DB 11h, 01h ;Versionsnummer der HID-Klasse (1.11) DB 0 ; 8 ; lokalisierter Ländercode (0 = keiner) DB 1 ; Zahl der nachfolgenden HID-Klassendescriptoren DB 22h ; Descriptortype des Reports (HID) DB 3Bh, 0 ; Gesamtlänge der Reportdescriptoren (hier 3Bh Byte) Data Endpoint Descriptor: DB 7 ; Descriptorlänge DB 5 ; EndPoint DB 81h ; kodierte Adresse (81h = IN, Endpoint 1) DB 3 ; Interrupt Transfer DB 8, 0 ; maximale Paketgröße (8 Byte) DB 20h ; Polling Intervall (32 ms) Data Report: ; Datenlänge = 3Bh Byte ; Bei Änderung der Datenlänge müssen letzte Zeile im HID Descriptor und ; in 'USB Get Descriptor' Routine die Descriptorlänge 'if r6 = #2 then' angepasst werden. DB 5, 1 ; Usage Page (Generic Desktop) DB 9, 6 ; Usage (Keyboard) DB A1h, 1 ; Collection (Application) ; IN Report DB 5, 7 ; Usage Page (Keyboard) DB 19h, 224 ; Usage Minimum (224) DB 29h, 231 ; Usage Maximum (231) DB 15h, 0 ; Logical Minimum (0) DB 25h, 1 ; Logical Maximum (1) DB 75h, 1 ; Report Size (1) (Bits) DB 95h, 8 ; Report Count (8) (Felder) DB 81h, 2 ; Input (Data, Variable, Absolute) DB 81h, 1 ; Input (Constant) DB 19h, 0 ; Usage Minimum (0) DB 29h, 101 ; Usage Maximum (101) DB 15h, 0 ; Logical Minimum (0) DB 25h, 101 ; Logical Maximum (101) DB 75h, 8 ; Report Size (8) (Bits), nicht änderbar DB 95h, 6 ; Report Count (6) (Felder), nicht änderbar DB 81h, 0 ; Input (Data, Array) ; OUT Report DB 5, 8 ; Usage Page (LED) DB 19h, 1 ; Usage Minimum (1) DB 29h, 5 ; Usage Maximum (5) DB 15h, 0 ; Logical Minimum (0) DB 25h, 1 ; Logical Maximum (1) ; DB 75h, 1 ; Report Size (1) (Bits) DB 75h, 2 ; Report Size (2) (Bits), änderbar DB 95h, 5 ; Report Count (5) (Felder) DB 91h, 2 ; Output (Data, Variable, Absolute) DB 95h, 3 ; Report Count (3) (Felder) DB 91h, 1 ; Output (Constant) DB C0h ; End Collection ;Version 2. April 2005