⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb_ch9.asm

📁 基于PIC16C745单片机的一个USB样例程序
💻 ASM
📖 第 1 页 / 共 4 页
字号:
	movwf	UEIE
	
	movlw	DEFAULT_STATE
	movwf	USWSTAT
	
	bcf 	STATUS,RP0	; select bank 2
	movlw	0x01
	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 	UIR,ACTIVITY
	bsf 	UIE,ACTIVITY
	bsf 	UCTRL, SUSPND
	banksel	PIR1		; switch to bank 0
	bcf	PIR1,USBIF

	bsf	STATUS, RP1	; 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
	movf	UEIR,w		; get the error register
	andwf	UEIE,w		; mask with the enables
	clrf	UEIR
	banksel	PIR1		; switch to bank 0
	bcf 	PIR1,USBIF	; clear the USB interrupt flag.
	bsf 	STATUS,RP1	; switch to bank 2
	movwf	USBMaskedErrors	; save the masked errors	

#ifdef COUNTERRORS
	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 	UIR,UIDLE
	bsf 	UIE,UIDLE
	bcf 	UCTRL, SUSPND

	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
	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
	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
	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
	bcf 	STATUS,RP0	; bank 2
	goto	Send_0Len_pkt
	return

tryEP1  ; bank 3
	xorlw	0x08		; was it EP1?
	pagesel	tryEP2
	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)
	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
	goto	exitEP0in

; Check for Get String Descriptor
check_GSD
	movf	USB_dev_req,w
	xorlw	GET_STRING_DESCRIPTOR
	pagesel	check_SA
	btfss	STATUS,Z
	goto	check_SA
	pagesel	copy_descriptor_to_EP0
	call	copy_descriptor_to_EP0
	pagesel	exitEP0in
	goto	exitEP0in

; Check for Set Address
check_SA
	movf	USB_dev_req,w
	xorlw	SET_ADDRESS
	pagesel	check_SF
	btfss	STATUS,Z
	goto	check_SF
	pagesel	finish_set_address
	call	finish_set_address
	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
	bcf 	STATUS, RP0	; bank 2
	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
	bcf 	STATUS, RP0	; bank 2
	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	HID_SET_REPORT	; 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -