XDEF Entry,main,USB_ISR Include 'derivative.inc' DEFAULT_RAM SECTION SHORT Setup_packet ds $08 ; array for SETUP packet bmReqType equ Setup_packet ; Characteristic of Request bRequest equ Setup_packet+1 ; Request Code wValueL equ Setup_packet+2 ; Low byte Value Field wValueH equ Setup_packet+3 ; High byte Value Field wIndexL equ Setup_packet+4 ; Low byte Index Field wIndexH equ Setup_packet+5 ; High byte Index Field wLengthL equ Setup_packet+6 ; Low byte Length Field wLengthH equ Setup_packet+7 ; High byte Length Field USB_State ds 1 ; Device State Byte POWERED equ 0 ; USB_State=POWERED DEFAULT equ 1 ; USB_State=DEFAULT ADDRESSED equ 2 ; USB_State=ADDRESSED CONFIGURED equ 3 ; USB_State=CONFIGURED SET_ADDRESS equ 5 ; Standard Request code for SET_ADDRESS GET_DESC equ 6 ; Standard Request code for GET_DESCRIPTOR SET_CONFIG equ 9 ; Standard Request code for SET_CONFIGURATION addrset ds 1 ; bit 7=1 indicates device address has ; been received, bits 6-0 = address control ds 1 ; type of transfer in progress descptr ds 2 ; pointer to descriptor being sent descendptr ds 2 ; end pointer to descriptor being sent buffptr ds 2 ; index into the USB data buffer tptr ds 2 ; temporary pointer for storage DEFAULT_ROM SECTION * The following descriptors give the information to the PC what type of * USB device this is and what its capabilities are. They are retrieved * during the configuration phase. * Note that the Vendor and Product IDs specified in this demo are invalid * USB IDs and are given for demonstration purposes only! * Device Descriptor Dev_Desc: dc.b DDesc_End-Dev_Desc ; Descriptor Length dc.b $01 ; Descriptor Type (Device) dc.b $10,$01 ; USB specification Release (1.10) dc.b $00 ; Class Code dc.b $00 ; Subclass Code dc.b $00 ; Protocol Code dc.b $08 ; Maximum Packet Size for EP0 (8 bytes) dc.b $57,$0b ; Vendor ID=none////////////////////////////////////////////////////////////////////// dc.b $24,$80 ; Product ID=none///////////////////////////////////////////////////////////////////// dc.b $01,$00 ; Device Release Number (1.00) dc.b $01 ; Index to Manufacturer String Descriptor dc.b $02 ; Index to Product String Descriptor dc.b $00 ; Index to Device Serial Number String Descriptor dc.b $01 ; Number of possible configurations (1) DDesc_End: * Configuration Descriptor Con_Desc: dc.b CDesc_End-Con_Desc ; Descriptor Length dc.b $02 ; Descriptor Type (Configuration) dc.b E1Desc_End-Con_Desc,$00 ; Total data length (Config-Interface-EP) dc.b $01 ; Interfaces supported dc.b $01 ; Configuration Value dc.b $00 ; Index to String Descriptor dc.b $C0 ; Self powered dc.b $00 ; Maximum power consumption=0mA (not applicable) CDesc_End: * Interface Descriptor Int_Desc: dc.b IDesc_End-Int_Desc ; Descriptor Length dc.b $04 ; Descriptor Type (Interface) dc.b $00 ; Number of Interface dc.b $00 ; No alternate setting dc.b $01 ; Number of endpoints dc.b $03 ; Class Code (HID) dc.b $00 ; Subclass Code dc.b $00 ; Protocol Code dc.b $00 ; Index to String Descriptor IDesc_End: * HID Descriptor HID_Desc: dc.b HDesc_End-HID_Desc ; Descriptor Length dc.b $21 ; Descriptor Type (HID) dc.b $00,$01 ; HID Class Release (1.00) dc.b $00 ; Country Code=$00 dc.b $01 ; number of HID class descriptors dc.b $22 ; Class Descriptor Type (REPORT) dc.b RDesc_End-Rep_Desc,$00 ; length of report descriptor HDesc_End: * Endpoint Descriptor Endp1_Desc: dc.b E1Desc_End-Endp1_Desc ; Descriptor Length dc.b $05 ; Descriptor Type (Endpoint) dc.b $81 ; Endpoint Address and Direction (#1,IN) dc.b $03 ; Endpoint Attribute (Interrupt) dc.b $08,$00 ; Maximum Packet Size for EP1 (1 byte)//////////////////////////////////////////// dc.b $FF ; Polling Interval=255[ms] E1Desc_End: * Report Descriptor Rep_Desc: dc.b $05,$0d ;USAGE_PAGE dc.b $09,$01 dc.b $a1,$01 ;COLLECTION dc.b $85,$02 ;REPORT_ID dc.b $a1,$00 ;COLLECTION dc.b $09,$00 dc.b $15,$00 ;LOGICAL_MINIMUM dc.b $26,$ff dc.b $00,$75 dc.b $08,$95 dc.b $07,$81 dc.b $02,$c0 dc.b $09,$00 dc.b $85,$02 dc.b $95,$01 dc.b $b1,$02 RDesc_End: *************************************************************** * Init_USB - Disables receive and transmit for all endpoints. * * The USB state is set to powered, where the part * * is waiting for an USB reset and for it to be * * addressed and configured. * *************************************************************** Init_USB: mov #POWERED,USB_State ; device in POWERED state clr addrset ; not addressed yet clr control ; waiting for control packets mov #$80,UADDR ; enable USB, address=default clr UCR0 ; disable all for Epnt 0 clr UCR1 ; disable all for Epnt 1 clr UCR2 ; disable all for Epnt 2 mov #$3,UIR0 ; enable TXD0IE, RXD0IE mov #$FF,UIR2 ; Reset all USB flags ;$IF USE_JB8_PULLUP ; mov #$5,UCR3 ; enable EP1, no STALL, internal pullup ;$ELSEIF mov #$1,UCR3 ; enable EP1, no STALL, no internal pullup ;$ENDIF rts ************************************************************** * MAIN_INIT - This is the point where code starts executing * * after a RESET. * ************************************************************** Entry: main: rsp clra clrx mov #$21,CONFIG ; URSTD=1 (USB reset=interrupt),////////////////////////////////////////////////////// mov #$02,POCR ; enable pullups for port B jsr Init_USB ; Initialize USB peripheral cli ; Allow interrupts to happen main_loop: nop ; service cop control register to prevent reset////////////////////////////////////// bra main_loop **************************************************************** * FORCE_STALL - A packet is received in the control stage that * * is not supported. So the device stalls until * * new SETUP packet arrives at endpoint 0. * **************************************************************** FORCE_STALL: lda UCR3 ; request not handled ora #$30 ; set OSTALL0 and ISTALL0 sta UCR3 ; new SETUP packet clears STALL rts ; bits automatically **************************************************************** * SETADDR_PROC - This procedure handles the standard request * * to set the devices address. * **************************************************************** SETADDR_PROC: ldhx #$5 SETADDR_PROC2: lda wValueH-1,x ; if any field but ValueL<>0 then bne SETADDR_STALL ; go stall dbnzx SETADDR_PROC2 lda wValueL ; get address value bmi SETADDR_STALL ; if greater than 7 bits, stall ora #$80 ; set highest bit for flag sta addrset ; store new address in addrset ; change UADDR after last IN packet comes mov #SET_ADDRESS,control ; set flag for control transfer type mov #$3,UIR2 ; clear any TXD0F, RXD0F flag mov #$B0,UCR0 ; allow IN packets, when IN packet comes bra SETADDR_EXIT ; send DATA1 packet with 0 bytes SETADDR_STALL: jsr FORCE_STALL SETADDR_EXIT: rts **************************************************************** * GETDESC_PROC - This procedure handles the standard request * * to get the devices descriptors. * **************************************************************** GETDESC_PROC: ldhx #$0 ; clear H:X pointer lda wValueH ; check which descriptor is wanted cbeqa #$1,GETDEVDESC ; is it device descriptor? cbeqa #$2,GETCONDESC ; is it configuration descriptor? cbeqa #$21,GETHIDDESC ; is it for HID descriptor? cbeqa #$22,GETREPDESC ; is it for Report descriptor? jmp GETDESC_STALL ; else go stall GETDEVDESC: lda Dev_Desc,x ; take device descriptor information sta UE0D0,x ; store in USB endpoint 0 data buffer incx cpx #$8 ; all descriptors more than 8 bytes bne GETDEVDESC ldhx #DDesc_End ; store end location of the descriptor sthx descendptr ldhx #Dev_Desc ; store pointer to next byte in descriptor bra GETDESC_END GETCONDESC: lda Con_Desc,x ; take configuration descriptor information sta UE0D0,x ; store in USB endpoint 0 data buffer incx cpx #$8 ; all descriptors more than 8 bytes bne GETCONDESC ldhx #E1Desc_End ; store end location of the descriptor sthx descendptr ldhx #Con_Desc ; store pointer to next byte in descriptor bra GETDESC_END GETHIDDESC: lda HID_Desc,x ; take HID descriptor information sta UE0D0,x ; store in USB endpoint 0 data buffer incx cpx #$8 ; all descriptors more than 8 bytes bne GETHIDDESC ldhx #HDesc_End ; store end location of the descriptor sthx descendptr ldhx #HID_Desc ; store pointer to next byte in descriptor bra GETDESC_END GETREPDESC: lda Rep_Desc,x ; take report descriptor information sta UE0D0,x ; store in USB endpoint 0 data buffer incx cpx #$8 ; all descriptors more than 8 bytes bne GETREPDESC ldhx #RDesc_End ; store end location of the descriptor sthx descendptr ldhx #Rep_Desc ; store pointer to next byte in descriptor GETDESC_END: sthx descptr lda descptr+1 ; add length specified in setup packet add wLengthL ; and store in tptr sta tptr+1 lda descptr adc wLengthH sta tptr ldhx tptr ; is calculated pointer >= end of descriptor? cphx descendptr ; if so then end_pointer = end of descriptor bge GETDESC_END2 ; else, end_pointer= calculated pointer sthx descendptr GETDESC_END2: ldhx descptr ; get pointer to start of descriptor aix #$8 ; eight bytes sent already sthx descptr ; store current pointer mov #$B8,UCR0 ; change to DATA1 sequence, SIZE=8 bytes ; turn on transmitter (TX0E) mov #GET_DESC,control ; set flag for control transfer type bra GETDESC_EXIT GETDESC_STALL: jsr FORCE_STALL GETDESC_EXIT: rts **************************************************************** * SETCON_PROC - This procedure handles the standard request to * * set the configuration of the device. * **************************************************************** SETCON_PROC: ldhx #$5 SETCON_PROC2: lda wValueH-1,x ; if any field but ValueL<>0 then bne SETCON_STALL ; go stall dbnzx SETCON_PROC2 lda wValueL ; get configuration value cmp #$01 bne SETCON_STALL ; if value<>1 then stall mov #SET_CONFIG,control ; set flag for control transfer type mov #$3,UIR2 ; clear any TXD0F, RXD0F flag mov #$B0,UCR0 ; allow IN packets, when IN packet comes bra SETCON_EXIT ; send DATA1 packet with 0 bytes SETCON_STALL: jsr FORCE_STALL SETCON_EXIT: rts **************************************************************** * SETUP_PROC - This procedure handles the SETUP packets that * * come into the USB peripheral. The only standard * * device requests handled are SET_ADDRESS, * * GET_DESCRIPTOR, and SET_CONFIGURATION. * **************************************************************** SETUP_PROC: bclr 4,UCR0 ; turn off reception from endpoint 0 bset 0,UIR2 ; reset the RXD0F flag clr control ; clear flag for control transfer lda USR0 ; check size and sequence of SETUP packet cmp #$48 ; is R0SEQ=0, SIZE=8? bne SETUP_EXIT ; if not then exit ldhx #$8 SAVE_SETUP: lda UE0D0-1,x ; save data to array sta Setup_packet-1,x ; Setup_packet holds info dbnzx SAVE_SETUP lda bmReqType ; if request type is standard and #$60 ; then go handle standard request bne SETUP_STALL ; otherwise, force stall STANDARD: lda bRequest ; get request type cbeqa #SET_ADDRESS,SET_ADDR ; if setting address then ; store new address and change after ; final IN packet cbeqa #GET_DESC,GET_DESCR ; if getting descriptors then ; ready the next IN packets for ; the descriptor information cbeqa #SET_CONFIG,SET_CON ; if setting configuration then ; move from ADDRESSED to CONFIGURED state bra SETUP_STALL ; otherwise, force stall SET_ADDR: jsr SETADDR_PROC ; packet received was SET_ADDRESS bra SETUP_EXIT ; go exit GET_DESCR: jsr GETDESC_PROC ; packet received was GET_DESCRIPTOR bra SETUP_EXIT ; go exit SET_CON: jsr SETCON_PROC ; packet received was SET_CONFIGURATION bra SETUP_EXIT ; go exit SETUP_STALL: jsr FORCE_STALL ; error, force stall on endpoint 0 SETUP_EXIT: bset 4,UCR0 ; turn on reception from endpoint 0 rts **************************************************************** * IN_PROC - This procedure handles the IN packets that come * * into the USB peripheral through endpoint 0. * **************************************************************** IN_PROC: bclr 5,UCR0 ; turn off transmits from endpoint 0 bset 1,UIR2 ; reset the TXD0F flag lda control ; is this IN packet for status stage cmp #SET_ADDRESS ; of SET_ADDRESS? bne IN_PROC2 lda addrset ; then set address of device sta UADDR ldx #DEFAULT ; device in DEFAULT state cbeqa #$80,IN_DEF ; if address is 0 then DEFAULT state ldx #ADDRESSED ; otherwise device in ADDRESSED state IN_DEF: stx USB_State ; set state of device clr addrset ; clear flag and address clr control ; end of control transfer bra IN_EXIT IN_PROC2: cmp #GET_DESC ; is this IN packet for data stage bne IN_PROC3 ; of GET_DESCRIPTOR? ldhx #$0 ; clear index into data buffer sthx buffptr IN_SEND_DATA: ldhx descptr ; get pointer to descriptor lda 0,x ; get descriptor byte aix #$1 sthx descptr ; save pointer to descriptor ldhx buffptr ; get index to data buffer sta UE0D0,x ; place byte in buffer aix #$1 sthx buffptr ; save index to data buffer ldhx descptr ; is it last descriptor byte? cphx descendptr beq LAST_DESC ldhx buffptr ; is data buffer filled? cphx #$8 beq DATAFILLED ; go send data bra IN_SEND_DATA ; else continue LAST_DESC: clr control ; if so then end of data transfer DATAFILLED: lda UCR0 ; take USB control register 0 and #$F0 ; mask off top 4 bits ora #$20 ; enable transmits from endpoint 0 eor #$80 ; toggle DATA sequence bit ora buffptr+1 ; set the size of the buffer sta UCR0 bra IN_EXIT IN_PROC3: cmp #SET_CONFIG ; is this IN packet for status stage bne IN_EXIT ; of SET_CONFIGURATION? mov #CONFIGURED,USB_State ; device in CONFIGURED state clr control ; end of control transfer ;lda #$02 ; get Port B value////////////////////////////////////////////////////////////////////// ;sta UE1D0 ; place in endpoint 1 data buffer//////////////////////////////////////////////////////// mov #$28,UCR1 ; turn on endpoint 1 transmit, size=1 byte***********************************************22 ; Sequence=0 bset 3,UIR0 ; enable interrupt for endpoint 1 transmit IN_EXIT: rts **************************************************************** * OUT_PROC - This procedure handles the OUT packets that are * * sent by the USB peripheral through endpoint 0. * **************************************************************** OUT_PROC: bclr 4,UCR0 ; turn off reception from endpoint 0 bset 0,UIR2 ; reset the RXD0F flag ; all OUT packets received for endpoint 0 ; should be for status stage of requests OUT_EXIT: bset 4,UCR0 ; turn on reception from endpoint 0 rts ************************************************************** * USB_ISR - USB Interrupt Service Routine. * * Interrupts here if USB reset, packet is received * * in endpoint 0, or packet is transmitted from * * endpoint 0 or 1. * ************************************************************** USB_ISR: brclr 6,UIR1,UISR_RXD ; Is it USB reset? mov #DEFAULT,USB_State ; device in DEFAULT state mov #$10,UCR0 ; turn on RX0 mov #$80,UADDR ; enable USB, address=default clr UCR1 ; disable all for Epnt 1 mov #$3,UIR0 ; enable TXD0IE, RXD0IE mov #$40,UIR2 ; reset USB reset flag bra UISR_EXIT ; exit interrupt UISR_RXD: brclr 0,UIR1,UISR_TXD ; Is it SETUP/OUT packet received? brclr 6,USR0,UISR_RXD2 ; is it SETUP packet? jsr SETUP_PROC ; handle SETUP packet bra UISR_EXIT ; exit interrupt UISR_RXD2: jsr OUT_PROC ; handle OUT packet bra UISR_EXIT ; exit interrupt UISR_TXD: brclr 1,UIR1,UISR_TXD1 ; Is packet sent from IN packet for endpoint 0? jsr IN_PROC ; handle IN packet for endpoint 0 bra UISR_EXIT ; exit interrupt UISR_TXD1: brclr 3,UIR1,UISR_EXIT ; Is packet sent from IN packet for endpoint 1? lda #$02 ; get Port B value sta UE1D0 ; place in endpoint 1 data buffer lda #$91 ; get Port B value sta UE1D1 ; place in endpoint 1 data buffer lda #$53 ; get Port B value sta UE1D2 ; place in endpoint 1 data buffer lda #$0c ; get Port B value sta UE1D3 ; place in endpoint 1 data buffer lda #$40 ; get Port B value sta UE1D4 ; place in endpoint 1 data buffer lda #$07 ; get Port B value sta UE1D5 ; place in endpoint 1 data buffer lda #$9f ; get Port B value sta UE1D6 ; place in endpoint 1 data buffer lda #$01 ; get Port B value sta UE1D7 ; place in endpoint 1 data buffer lda UCR1 ; toggle TX1 data sequence eor #$80 sta UCR1 bset 3,UIR2 ; reset the TXD1F flag UISR_EXIT: rti END ; 68HC908JB8 USB HID Demonstration Application * This source is (C)opyright 2002, P&E Microcomputer Systems, Inc. * Visit us at http://www.pemicro.com