📄 usb_ch9.asm
字号:
return
; ******************************************************************
; The SIE detected an error. This code increments the appropriate
; error counter and clears the flag.
; ******************************************************************
USBError
global USBError
banksel UIR
bcf UIR,UERR
movf UEIR,w ; get the error register
andwf UEIE,w ; mask with the enables
clrf UEIR
banksel USBMaskedErrors ; switch to bank 2
movwf USBMaskedErrors ; save the masked errors
#ifdef COUNTERRORS
pagesel CRC5Error
btfss USBMaskedErrors,PID_ERR
goto CRC5Error
INCREMENT16 USB_PID_ERR
CRC5Error
pagesel CRC16Error
btfss USBMaskedErrors,CRC5
goto CRC16Error
INCREMENT16 USB_CRC5_ERR
CRC16Error
pagesel DFN8Error
btfss USBMaskedErrors,CRC16
goto DFN8Error
INCREMENT16 USB_CRC16_ERR
DFN8Error
pagesel BTOError
btfss USBMaskedErrors,DFN8
goto BTOError
INCREMENT16 USB_DFN8_ERR
BTOError
pagesel WRTError
btfss USBMaskedErrors,BTO_ERR
goto WRTError
INCREMENT16 USB_BTO_ERR
WRTError
pagesel OWNError
btfss USBMaskedErrors,WRT_ERR
goto OWNError
INCREMENT16 USB_WRT_ERR
OWNError
pagesel BTSError
btfss USBMaskedErrors,OWN_ERR
goto BTSError
INCREMENT16 USB_OWN_ERR
BTSError
pagesel EndError
btfss USBMaskedErrors,BTS_ERR
goto EndError
INCREMENT16 USB_BTS_ERR
EndError
#endif
bcf STATUS,RP1 ; Bank 0
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
global TokenDone
COPYBUFFERDESCRIPTOR ; copy BD from dual port to unbanked RAM
banksel USTAT
movf USTAT,w ; get the status register
bcf UIR,TOK_DNE ; clearing the token done interrupt.
bcf STATUS,RP0 ; 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
pagesel tryEP1activity
btfss STATUS,Z ; is it EP0?
goto tryEP1activity
movlw 0x20
pagesel maskport
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
#endif
; check UOWN bit here if desired
banksel BufferDescriptor
movf BufferDescriptor,w ; get the first byte of the BD
andlw 0x3c ; save the PIDs
movwf PIDs
xorlw TOKEN_IN
pagesel TokenInPID
btfsc STATUS,Z
goto TokenInPID
movf PIDs,w
xorlw TOKEN_OUT
pagesel TokenOutPID
btfsc STATUS,Z
goto TokenOutPID
movf PIDs,w
xorlw TOKEN_SETUP
pagesel TokenSetupPID
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
pagesel tryEP1
btfss STATUS,Z ; was it EP0?
goto tryEP1 ; no, try EP1
movf USB_dev_req,w
xorlw HID_SET_REPORT
pagesel ResetEP0OutBuffer
btfss STATUS,Z
goto ResetEP0OutBuffer
HIDSetReport
; ******************************************************************
; You must write your own SET_REPORT routine. The following
; commented out code is provided if you desire to make a SET_REPORT
; look like a EP1 OUT Interrupt transfer. Uncomment it and use it
; if you desire this functionality.
; ******************************************************************
; 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
pagesel Send_0Len_pkt
goto Send_0Len_pkt
tryEP1 ; bank 2
xorlw 0x08 ; was it EP1?
pagesel tryEP2
btfss STATUS,Z
goto tryEP2
; **** Add Callout here to service EP1 in transactions. ****
return
tryEP2 ; bank 2
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)
pagesel tryEP1in
btfss STATUS,Z ; was it EP0?
goto tryEP1in ; no, try EP1
movf USB_dev_req,w
xorlw GET_DESCRIPTOR
pagesel check_GSD
btfss STATUS,Z
goto check_GSD
pagesel copy_descriptor_to_EP0
call copy_descriptor_to_EP0
pagesel exitEP0in
goto exitEP0in
; Check for Get String Descriptor
check_GSD
movf USB_dev_req,w
xorlw GET_STRING_DESCRIPTOR
pagesel check_SF
btfss STATUS,Z
goto check_SF
pagesel copy_descriptor_to_EP0
call copy_descriptor_to_EP0
pagesel exitEP0in
goto exitEP0in
check_SF
movf USB_dev_req,w
xorlw SET_FEATURE
pagesel check_CF
btfss STATUS,Z
goto check_CF
pagesel exitEP0in
goto exitEP0in
check_CF
movf USB_dev_req,w
xorlw CLEAR_FEATURE
pagesel Class_Specific
btfss STATUS,Z
goto Class_Specific
movf BufferData+4, w ; clear endpoint 1 stall bit
xorlw 1
pagesel clear_EP2
btfss STATUS,Z
goto clear_EP2
bsf STATUS, RP0 ; bank 3
bsf UEP1, EP_STALL
pagesel exitEP0in
goto exitEP0in
clear_EP2
movf BufferData+wIndex, w ; clear endpoint 2 stall bit
xorlw 2
pagesel exitEP0in
btfss STATUS,Z
goto exitEP0in
bsf STATUS, RP0 ; bank 3
bsf UEP2, EP_STALL
pagesel exitEP0in
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?
pagesel tryEP1in
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
movwf BufferData+5
incf FSR,f
movf INDF,w
movwf BufferData+6
incf FSR,f
movf INDF,w
movwf BufferData+7
bsf STATUS, RP0 ; bank 3
movlw 0x08
movwf BD0OBC ; reset the byte count too.
movwf BD0IST ; return the in buffer to us (dequeue any pending requests)
bcf STATUS, RP0 ; bank 2
movf BufferData+bmRequestType, w
xorlw 0x21 ; set EP0 OUT UOWNs back to SIE
movlw 0x88 ; set DATA0/DATA1 packet according to request type
btfsc STATUS, Z
movlw 0xC8
bsf STATUS, RP0 ; bank 3
movwf BD0OST
bcf UCTRL,PKT_DIS ; Assuming there is nothing to dequeue, clear the packet disable bit
bcf STATUS,RP0 ; bank 2
clrf USB_dev_req ; clear the device request..
movf BufferData+bmRequestType,w
pagesel HostToDevice
btfsc STATUS,Z
goto HostToDevice
movf BufferData+bmRequestType,w
xorlw 0x01 ; test for host to Interface tokens
pagesel HostToInterface
btfsc STATUS,Z
goto HostToInterface
movf BufferData+bmRequestType,w
xorlw 0x02 ; test for host to Endpoint tokens
pagesel HostToEndpoint
btfsc STATUS,Z
goto HostToEndpoint
movf BufferData+bmRequestType,w
xorlw 0x80 ; test for device to Host tokens
pagesel DeviceToHost
btfsc STATUS,Z
goto DeviceToHost
movf BufferData+bmRequestType,w
xorlw 0x81 ; test for device to Interface tokens
pagesel InterfaceToHost
btfsc STATUS,Z
goto InterfaceToHost
movf BufferData+bmRequestType,w
xorlw 0x82 ; test for device to Endpoint tokens
pagesel EndpointToHost
btfsc STATUS,Z
goto EndpointToHost
movf BufferData+bmRequestType,w
andlw 0x60 ; mask off type bits
xorlw 0x20 ; test for class specific
pagesel ClassSpecificRequest
btfsc STATUS,Z ; was it a standard request?
goto ClassSpecificRequest ; nope, see if it was a class specific request
CheckForVendorRequest
movf BufferData+bmRequestType,w
andlw 0x60 ; mask off type bits
xorlw 0x40 ; test for vendor specific
pagesel wrongstate
btfss STATUS,Z ; was it a standard request?
goto wrongstate
pagesel CheckVendor
goto CheckVendor ; nope, see if it was a vendor specific
; now test bRequest to see what the request was.
CheckForStandardRequest
; bmRequestType told us it was a Host to Device transfer. Now look at
; the specifics to see what's up
HostToDevice ; starts in bank 2
movf BufferData+bRequest,w ; what was our request
xorlw CLEAR_FEATURE
pagesel Clear_Device_Feature
btfsc STATUS,Z
goto Clear_Device_Feature
movf BufferData+bRequest,w ; was our request Set Address
xorlw SET_ADDRESS
pagesel Set_Address
btfsc STATUS,Z
goto Set_Address
movf BufferData+bRequest,w ; was our request Set Configuration
xorlw SET_CONFIGURATION
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -