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

📄 usb_ch9.asm

📁 This firmware translates a PS/2 mouse to a USB mouse. The translator firmware is entirely interrup
💻 ASM
📖 第 1 页 / 共 4 页
字号:
    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 + -