📄 usb_ch9.asm
字号:
call USBActivity
pagesel ServiceUSBInt
goto ServiceUSBInt
ExitServiceUSBInt
banksel PIR1
bcf PIR1,USBIF
return
; ******************************************************************
; USB Reset interrupt triggered (SE0)
; initialize the Buffer Descriptor Table,
; Transition to the DEFAULT state,
; Set address to 0
; enable the USB
; ******************************************************************
USBReset ; START IN BANK2
clrf USB_Curr_Config
clrf IS_IDLE
bsf STATUS, RP0 ; bank 3
bcf UIR,TOK_DNE ; hit this 4 times to clear out the
bcf UIR,TOK_DNE ; USTAT FIFO
bcf UIR,TOK_DNE
bcf UIR,TOK_DNE
movlw 0x88 ; set owns bit (SIE can write)
movwf BD0OST
movlw USB_Buffer ; Endpoint 0 OUT gets a buffer
movwf BD0OAL ; set up buffer address
movlw 0x8
movwf BD0OBC
movlw 0x08 ; Clear owns bit (PIC can write)
movwf BD0IST
movlw USB_Buffer+8 ; Endpoint 0 IN gets a buffer
movwf BD0IAL ; set up buffer address
clrf UADDR ; set USB Address to 0
clrf UIR ; clear all the USB interrupt flags
banksel PIR1 ; switch to bank 0
bcf PIR1,USBIF
; Set up the Endpoint Control Registers. The following patterns are defined
; ENDPT_DISABLED - endpoint not used
; ENDPT_IN_ONLY - endpoint supports IN transactions only
; ENDPT_OUT_ONLY - endpoint supports OUT transactions only
; ENDPT_CONTROL - Supports IN, OUT and CONTROL transactions - Only use with EP0
; ENDPT_NON_CONTROL - Supports both IN and OUT transactions
banksel UEP0
movlw ENDPT_CONTROL
movwf UEP0 ; endpoint 0 is a control pipe and requires an ACK
movlw 0x3B ; enable all interrupts except activity
movwf UIE
movlw 0xFF ; enable all error interrupts
movwf UEIE
movlw DEFAULT_STATE
movwf USWSTAT
bcf STATUS,RP0 ; select bank 2
movlw 0x00
movwf USB_status_device ; Self powered, remote wakeup disabled
bcf STATUS,RP1 ; bank 0
#ifdef SHOW_ENUM_STATUS
bsf PORTB,1 ; set bit one to indicate Reset status
#endif
bsf STATUS,RP1
return ; to keep straight with host controller tests
; ******************************************************************
; Enable Wakeup on interupt and Activity interrupt then put the
; device to sleep to save power. Activity on the D+/D- lines will
; set the ACTIVITY interrupt, waking up the part.
; ******************************************************************
USBSleep ; starts from bank2
bsf STATUS, RP0 ; up to bank 3
bcf UIE,UIDLE
bcf UIR,UIDLE
bcf UIE,ACTIVITY
bcf UIR,ACTIVITY
banksel PIR1 ; switch to bank 0
bcf PIR1,USBIF
banksel IS_IDLE ; switch to bank 2
bsf IS_IDLE, 0
return
; ******************************************************************
; This is activated by the STALL bit in the UIR register. It really
; just tells us that the SIE sent a STALL handshake. So far, Don't
; see that any action is required. Clear the bit and move on.
; ******************************************************************
USBStall ; starts in bank 2
bsf STATUS, RP0 ; bank 3
bcf UIR, STALL ; clear STALL
banksel PIR1 ; switch to bank 0
bcf PIR1,USBIF
bsf STATUS,RP1 ; bank 2
return
; ******************************************************************
; The SIE detected an error. This code increments the appropriate
; error counter and clears the flag.
; ******************************************************************
USBError ; starts in bank 2
bsf STATUS, RP0 ; bank 3
bcf UIR,UERR
banksel PIR1 ; switch to bank 0
bcf PIR1,USBIF ; clear the USB interrupt flag.
bsf STATUS,RP1 ; switch to bank 2
#ifdef COUNTERRORS
banksel UEIR
movf UEIR,w ; get the error register
andwf UEIE,w ; mask with the enables
clrf UEIR
bcf STATUS, RP0 ; Bank 2
movwf USBMaskedErrors ; save the masked errors
btfss USBMaskedErrors,PID_ERR
goto CRC5Error
INCREMENT16 USB_PID_ERR
CRC5Error
btfss USBMaskedErrors,CRC5
goto CRC16Error
INCREMENT16 USB_CRC5_ERR
CRC16Error
btfss USBMaskedErrors,CRC16
goto DFN8Error
INCREMENT16 USB_CRC16_ERR
DFN8Error
btfss USBMaskedErrors,DFN8
goto BTOError
INCREMENT16 USB_DFN8_ERR
BTOError
btfss USBMaskedErrors,BTO_ERR
goto WRTError
INCREMENT16 USB_BTO_ERR
WRTError
btfss USBMaskedErrors,WRT_ERR
goto OWNError
INCREMENT16 USB_WRT_ERR
OWNError
btfss USBMaskedErrors,OWN_ERR
goto BTSError
INCREMENT16 USB_OWN_ERR
BTSError
btfss USBMaskedErrors,BTS_ERR
goto EndError
INCREMENT16 USB_BTS_ERR
EndError
#endif
banksel USBMaskedInterrupts
return
; ******************************************************************
; Service the Activity Interrupt. This is only enabled when the
; device is put to sleep as a result of inactivity on the bus. This
; code wakes up the part, disables the activity interrupt and reenables
; the idle interrupt.
; ******************************************************************
USBActivity ; starts in bank 2
bsf STATUS, RP0 ; Bank 3
bcf UIE,ACTIVITY ; clear the Activity and Idle bits
bcf UIR,ACTIVITY
bcf UIE,UIDLE
bcf UIR,UIDLE
banksel PIR1 ; switch to bank 0
bcf PIR1,USBIF ; clear the USB interrupt flag.
bsf STATUS,RP1 ; switch to bank 2
clrf IS_IDLE
return
; ******************************************************************
; Process token done interrupt... Most of the work gets done through
; this interrupt. Token Done is signaled in response to an In, Out,
; or Setup transaction.
; ******************************************************************
TokenDone ; starts in bank 2
COPYBUFFERDESCRIPTOR ; copy BD from dual port to unbanked RAM
banksel USTAT
movf USTAT,w ; copy USTAT register before...
bcf UIR,TOK_DNE ; clearing the token done interrupt.
banksel PIR1 ; switch to bank 0
bcf PIR1,USBIF ; clear the USB interrupt flag.
bsf STATUS,RP1 ; switch to bank 2
movwf USB_USTAT ; Save USTAT in bank 2
#ifdef SHOW_ENUM_STATUS
; This toggles the activity bits on portB (EP0 -> Bit 5; EP1 -> bit 6; EP2 -> bit 7)
bcf STATUS,RP1 ; bank 0
andlw 0x18 ; save endpoint bits
btfss STATUS,Z ; is it EP0?
goto tryEP1activity
movlw 0x20
goto maskport
tryEP1activity
xorlw 0x08 ; is it bit one?
btfss STATUS,Z
movlw 0x80 ; No, It's not EP0, nor 1 so it must be EP2. toggle bit 7
btfsc STATUS,Z
movlw 0x40 ; Yes, toggle bit 6 to Show EP1 activity
maskport
xorwf PORTB,f
bsf STATUS,RP1 ; bank 2
#endif
; check UOWN bit here if desired
movf BufferDescriptor,w ; get the first byte of the BD
andlw 0x3c ; save the PIDs
movwf PIDs
xorlw TOKEN_IN
btfsc STATUS,Z
goto TokenInPID
movf PIDs,w
xorlw TOKEN_OUT
btfsc STATUS,Z
goto TokenOutPID
movf PIDs,w
xorlw TOKEN_SETUP
btfsc STATUS,Z
goto TokenSetupPID
return ; should never get here...
; ******************************************************************
; Process out tokens
; For EP0, just turn the buffer around. There should be no EP0
; tokens to deal with.
; EP1 and EP2 have live data destined for the application
; ******************************************************************
TokenOutPID ; STARTS IN BANK2
movf USB_USTAT,w ; get the status register
btfss STATUS,Z ; was it EP0?
goto tryEP1 ; no, try EP1
movf USB_dev_req,w
xorlw HID_SET_REPORT
btfss STATUS,Z
goto ResetEP0OutBuffer
HIDSetReport
; Copy buffer to EP1 Out so it looks like it was received from an EP1 OUT
movlw 0xFF
movwf USB_dev_req ; clear the request type
banksel BD1IST
movf BD0OST,w
movwf BD1OST ; Copy status register to EP1 Out
movf BD0OAL,w ; get EP0 Out buffer address
bcf STATUS,RP0 ; bank 2
movwf hid_source_ptr
bsf STATUS,RP0 ; bank 3
movf BD1OAL,w ; get EP1 Out Buffer Address
bcf STATUS,RP0 ; bank 2
movwf hid_dest_ptr
bsf STATUS,RP0 ; bank 3
movf BD0OBC,w ; Get byte count
movwf BD1OBC ; copy to EP1 Byte count
bcf STATUS,RP0 ; bank 2
movwf counter
bankisel BD1IST ; indirectly to bank 3
HIDSRCopyLoop
movf hid_source_ptr,w
movwf FSR
movf INDF,w
movwf temp
movf hid_dest_ptr,w
movwf FSR
movf temp,w
movwf INDF
incf hid_source_ptr,f
incf hid_dest_ptr,f
decfsz counter,f
goto HIDSRCopyLoop
bsf STATUS,RP0 ; bank 3
movlw 0x08
movwf BD0OST ; REset EP0 Status back to SIE
ResetEP0OutBuffer
bsf STATUS,RP0 ; no, just reset buffer and move on.
movlw 0x08 ; it's EP0.. buffer already copied,
movwf BD0OBC ; just reset the buffer
movlw 0x88
movwf BD0OST ; set OWN and DTS Bit
bcf STATUS,RP0 ; bank 2
goto Send_0Len_pkt
return
tryEP1 ; bank 3
xorlw 0x08 ; was it EP1?
btfss STATUS,Z
goto tryEP2
; **** Add Callout here to service EP1 in transactions. ****
return
tryEP2 ; bank 3
movf USB_USTAT,w
xorlw 0x10 ; was it EP2?
btfsc STATUS,Z
return ; unrecognized EP (Should never take this exit)
; **** Add Callout here to service EP2 in transactions. ****
return
; ******************************************************************
; Process in tokens
; ******************************************************************
TokenInPID ; starts in bank2
; Assumes EP0 vars are setup in a previous call to setup.
EP0_in
movf USB_USTAT,w ; get the status register
andlw 0x18 ; save only EP bits (we already know it's an IN)
btfss STATUS,Z ; was it EP0?
goto tryEP1in ; no, try EP1
movf USB_dev_req,w
xorlw GET_DESCRIPTOR
btfss STATUS,Z
goto check_GSD
pagesel copy_descriptor_to_EP0
call copy_descriptor_to_EP0
goto exitEP0in
; Check for Get String Descriptor
check_GSD
movf USB_dev_req,w
xorlw GET_STRING_DESCRIPTOR
btfss STATUS,Z
goto check_SA
call copy_descriptor_to_EP0
goto exitEP0in
; Check for Set Address
check_SA
movf USB_dev_req,w
xorlw SET_ADDRESS
btfss STATUS,Z
goto check_SF
call finish_set_address
goto exitEP0in
check_SF
movf USB_dev_req,w
xorlw SET_FEATURE
btfss STATUS,Z
goto check_CF
goto exitEP0in
check_CF
movf USB_dev_req,w
xorlw CLEAR_FEATURE
btfss STATUS,Z
goto Class_Specific
goto exitEP0in
Class_Specific
pagesel Check_Class_Specific_IN
goto Check_Class_Specific_IN
exitEP0in
return
; ******************************************************************
; though not required, it might be nice to have a callback function here
; that would take some action like setting up the next buffer when the
; previous one is complete. Not necessary because the same functionality
; can be provided through the PutUSB call.
; ******************************************************************
tryEP1in ; starts in bank 2
xorlw 0x08 ; was it EP1?
btfss STATUS,Z
goto tryEP2in
; **** Add Callout here to service EP1 in transactions. ****
return
tryEP2in ; starts in bank 2
; **** Add Callout here to service EP2 in transactions. ****
return
; ******************************************************************
; Return a zero length packet on EP0 In
; ******************************************************************
Send_0Len_pkt
global Send_0Len_pkt
banksel BD0IBC
clrf BD0IBC ; set byte count to 0
movlw 0xc8
movwf BD0IST ; set owns bit
bcf STATUS,RP0 ; back to bank 2
clrf USB_dev_req
return
; ********************************************************************
; process setup tokens
; ******************************************************************
TokenSetupPID ; starts in bank 2
bsf STATUS,IRP ; indirectly to pages 2/3
movf BufferDescriptor+ADDRESS,w ; get the status register
movwf FSR ; save in the FSR.
movf INDF,w
movwf BufferData ; in shared RAM
incf FSR,f
movf INDF,w
movwf BufferData+1
incf FSR,f
movf INDF,w
movwf BufferData+2
incf FSR,f
movf INDF,w
movwf BufferData+3
incf FSR,f
movf INDF,w
movwf BufferData+4
incf FSR,f
movf INDF,w
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -