📄 max3420e_evkit2_democode.asm
字号:
rjmp clrstall
; set stall bit
SETFLAG ep3stall
ori MAX_Dat,bmSTLEP3IN
rjmp stl
clrstall:
CLRFLAG ep3stall
andi MAX_Dat,!bmSTLEP3IN
stl:rjmp wregAS ; return from there
;
as: ldi MAX_Reg,rREVISION
rjmp rregAS ; do a dummy read just to set the ACKSTAT bit (return from rregAS)
; ----------
; Get Status
; ----------
Get_Status:
ldi MAX_Reg,rEP0FIFO ; in any case
lds temp,SUD+bmRequestType
cpi temp,0x80 ; directed to device?
breq GS_RWU ; yes--device status bits are self-powered & remote wakeup
cpi temp,0x81 ; directed to interface?
breq GS_IF ; yes--no status bits, just send 2 zero bytes
cpi temp,0x82 ; directed to endpoint?
breq GS_HALT ; yes--only ep status byte is HALT bit
rjmp stall
GS_RWU:
;
; There are two status bits for a Device, b1=RWU_enabled and b0=Self_Powered.
; Both bits are zero: No RWU (as reported at enumeration), and we are bus powered.
;
; bst flags,RWU_enabled ; RWU_enabled bit -> T bit
; bld MAX_Dat,1 ; T bit -> into b1
clr MAX_Dat
sz: rcall wreg
ldi MAX_Dat,0 ; second byte is 0
rcall wreg
ldi MAX_Reg,rEP0BC
ldi MAX_Dat,2 ; byte count
rjmp wregAS ; return from there
;
GS_IF:
ldi MAX_Dat,0x00 ; just send two zeros
rjmp sz ; send this byte then a zero byte & finish the transaction
;
GS_HALT:
lds temp,SUD+wIndexL ; make sure it's directed to our only data endpoint, EP3-IN
cpi temp,0x83 ; b7=1 for IN, EP=3
breq valid_ep
rjmp stall ; illegal request
valid_ep:
bst flags,ep3stall ; ep3stall bit -> T bit
bld MAX_Dat,0 ; bit 0 is the status HALT bit
rjmp sz ; send this byte then a zero byte & finish the transaction
;
;-----------------
Get_Configuration:
;-----------------
ldi MAX_Reg,rEP0FIFO
mov MAX_Dat,configval
rcall wreg
ldi MAX_Reg,rEP0BC
ldi MAX_Dat,1
rjmp wregAS ; set the ACKSTAT bit. Return from there.
;
;-----------------
Set_Configuration:
;-----------------
lds configval,SUD+wValueL ; config value in this byte
mov temp,configval ; so we can compare immediate
cpi temp,0
brne enable_suspend_IRQ ; if IF NE 0, enable suspend interrupt
rjmp as ; set the ACKSTAT bit and return
enable_suspend_IRQ:
ldi MAX_Reg,rUSBIEN
rcall rreg
ori MAX_Dat,bmSUSPENDIE
rjmp wregAS ; return from there
;
;-----------------
Get_Interface:
;-----------------
; Respond to interface=0, report alternate setting=0 (our only alternate setting)
;
lds temp,SUD+wIndexL ; wIndexL=Interface index
cpi temp,0
brne stall2 ; jump to Stall_EP0 from there
ldi MAX_Reg,rEP0FIFO
ldi MAX_Dat,0 ; alternate setting = 0
rcall wreg
ldi MAX_Reg,rEP0BC
ldi MAX_Dat,1
rjmp wregAS ; return from there
;
; Jump target for relative branches to reach the 'stall' label
;
stall2:
rjmp stall
;
;-----------------
Set_Interface:
;-----------------
;
; Our descriptor reported only one interface(0) with one AS(0)
;
lds temp,SUD+wValueL ; wValueL=AS, should be 0
tst temp
brne stall2 ; not zero--error
lds temp,SUD+wIndexL ; wIndexL is interface
tst temp
brne stall2 ; not zero--error
rjmp as ; return from there
;
;----------------------------------------------------------------
; Send a descriptor--Device, Configuration, String, HID or Report
;----------------------------------------------------------------
Get_Descriptor:
CLRFLAG UNIflag ; initial assumption--not a UNICODE string
ldi ZH,HIGH(DD*2) ; same page for all descriptors
lds reqlen,SUD+wLengthL ; assumes 64 byte maximum descriptor size
lds temp,SUD+wValueH ; descriptor type
cpi temp,GD_DEVICE
brne sd2
ldi ZL,LOW(DD*2) ; get the device descriptor pointer
lpm desclen,Z ; length byts is DD[0]
rjmp send_dscr
;
sd2:
cpi temp,GD_CONFIGURATION
brne sd3
ldi ZL,LOW((CD*2)+2) ; length byte is at offset 2 (3rd byte)
lpm desclen,Z ; rombyte=LengthL
ldi ZL,LOW(CD*2) ; point to beginning of config descriptor
rjmp send_dscr
;
sd3:
cpi temp,GD_STRING
brne sd4
SETFLAG UNIflag ; speculative
lds temp,SUD+wValueL
cpi temp,0
breq string0
dec temp
breq string1
dec temp
breq string2
dec temp
breq string3
rjmp stall
;
string0:
ldi ZL,LOW(STR0*2)
CLRFLAG UNIflag
rjmp sd5
string1:
ldi ZL,LOW(STR1*2) ; the rest of these are UNICODE
rjmp sd5
string2:
ldi ZL,LOW(STR2*2)
rjmp sd5
string3:
ldi ZL,LOW(STR3*2)
rjmp sd5
;
sd4:cpi temp,GD_HID
brne sd6
ldi ZL,LOW(HD*2)
sd5:lpm desclen,Z ; fall through to send_dscr
;
; Send a descriptor. Send the lesser of requested and actual string length.
; First retrieve and send a byte, then test the 'stringflag' to see if it's a string descriptor.
; If a string descriptor, send the first two bytes verbatim, then send the remaining bytes
; with a '0' appended to every byte (to account for the Unicode requirement).
;
send_dscr:
BRLTE reqlen,desclen,ss1
mov reqlen,desclen
ss1:push reqlen
ldi MAX_Reg,rEP0FIFO
ldi temp,0 ; temp is character counter
ss2:lpm MAX_Dat,Z+ ; get next byte and bump pointer
rcall wreg ; send the character
sbrs flags,Uniflag ; test for Unicode string
rjmp not_string
inc temp
cpi temp,3 ; nothing special for the first two chars
brcs not_string ; act like it's not a string for the first two chars
ldi MAX_Dat,0
rcall wreg
dec reqlen ; we just sent an extra zero (Unicode)
not_string:
dec reqlen
brne ss2
;
; Finished stuffing the EP0 FIFO with the requested descriptor. Load the EP0 byte count
; register to enable the IN transfer.
;
pop reqlen
ldi MAX_Reg,rEP0BC
mov MAX_Dat,reqlen
rjmp wregAS ; return from there
;
sd6:cpi temp,GD_REPORT
breq dord
rjmp stall2 ; illegal descriptor type was requested
;
; The report descriptor is different because it does not contain its own length field.
; The length is in the seventh byte of the HID descriptor
;
dord:
ldi ZL,LOW((HD*2)+7) ; length is 8th byte of HID descriptor (offset 7)
lpm desclen,Z ; read it
ldi ZL,LOW(RD*2) ; now point to the REPORT descriptor
rjmp send_dscr
;
;----------------------------------------------------------
; Send a keystroke over the interrupt endpoint EP3-IN.
; This routine is called when the EP3IN IRQ asserts,
; at the time that the previously loaded keycode is
; acccepted (ACK'd) by the host.
;
; The routine first examines the enable_send flag.
; If enable_send = 0:
; It sends [00 00 00] to indicate "keys up".
;
; If enable_send = 1:
; It reads one encoded byte in FLASH memory and decodes this
; to send keystrokes as [SB,00,KC] where SB is the shift
; byte (02 for shift, 00 for lower case),and KC a HID-encoded
; keycode. The data is packed into one byte where the msb is the
; shift indicator (shift=1), and the rest of the byte is
; the keycode.
;
; The routine first checks for a special code of 0xFF, which
; tells it to send [08 00 0x15] to open the RUN menu. Then it
; sends an ENTER code to launch the last app opened
; using the windows "Run" command.
;
; The text message to send is terminated by a 0. When this
; routine detects the 0, it resets the message pointer.
;
; The routine sends a "keys up" code [00 00 00] after every keycode.
;
;---------------------------------------------------------
send_keystroke: ; Send next HID character in HID_Message. Check for wrap (zero terminator).
;
ldi MAX_Reg,rEP3INFIFO ; we'll write this FIFO register three times
bst flags,Send_Flag ; T <- Send flag
brtc send_zeros ; Branch if Send_Flag(T)=0 (don't send)
SKIP_ON_FLAG keyupflag
rjmp sk2
CLRFLAG keyupflag ; send zeros as "all keys up"
rjmp send_zeros
sk2:ldi ZH,HIGH(KB_Message*2) ; *2 because Z counts bytes
mov ZL,pMessage
lpm temp,Z+ ; get the next byte and bump the index
mov pMessage,ZL ; save the index for next time
;
tst temp ; check for a zero (AVR assembler pads odd byte DB statements with a trailing zero)
brne nozero
rjmp sk2 ; skip the zero
nozero:
cpi temp,0xFF ; check for 0xFF message terminator
brne no_wrap ; it's not 0xFF--proceed
ldi pMessage,LOW(KB_Message*2) ; it's 0xFF--reset the message pointer
rjmp sk2 ; go again
no_wrap:
SETFLAG keyupflag ; next IN request send the all-keys-up code
;
ldi MAX_Dat,0 ; speculative load--no shift
sbrc temp,7 ; skip if b7=0 (non-shifted char)
ldi MAX_Dat,2 ; shift character--send 02
rcall wreg ; 1st byte, 0(unshifted) or 2(shifted)
ldi MAX_Dat,0
rcall wreg ; 2nd byte, always a 0 (from HID report descriptor)
andi temp,0b01111111 ; zero-out the MSB (shift indicator)
mov MAX_Dat,temp
sk: rcall wreg ; 3rd byte, the actual key code (or a zero)
ldi MAX_Reg,rEP3INBC ; load the byte count
ldi MAX_Dat,3 ; send 3 bytes & clear the IRQ
rjmp wreg ; return from there
send_zeros:
ldi MAX_Dat,0
rcall wreg ; first zero
rcall wreg ; second zero
rjmp sk ; third zero and byte count
;
; ------------------------------------------------------------------
; Read a MAX3420E register. Uses MAX_Reg(preserved), Updates MAX_Dat.
; Call 'rregAS' to set the ACKSTAT bit.
; ------------------------------------------------------------------
rregAS:
seT
rjmp rr2
rreg:
clT
rr2:mov dat,MAX_Reg ; 000rrrrr
lsl dat ; 00rrrrr0
lsl dat ; 0rrrrr00 (R)
lsl dat ; rrrrr000 (write bit is clear--b1)
bld dat,0 ; rrrrr00T (T=ACKSTAT bit)
rcall send_byte
;
; Now read the MISO data
;
SCK_LO
rd4:SCK_HI ; ready the next input bit
sec ; speculatively set CY
sbis PINB,MISO ; skip if set
clc
SCK_LO
rol MAX_Dat ; shift CY into the data byte
dec bitcount
brne rd4
SS_HI ; all done
ret
;
; ----------------------------------------------------------------------------
; Write a MAX3420E register.Uses MAX_Reg(preserved),MAX_Dat(preserved)
; ----------------------------------------------------------------------------
wregAS:
seT
rjmp wr2
wreg:
clT
wr2:mov dat,MAX_Reg ; 000rrrrr
lsl dat ; 00rrrrr0
sec
rol dat ; 0rrrrr01 (W)
lsl dat ; rrrrr010 (write bit is set--b1)
bld dat,0 ; rrrrr01T (T=ACKSTAT bit)
rcall send_byte
;
; Now the data byte in Max_Dat
;
mov dat,MAX_Dat
rcall send_byte
;
SCK_LO
MOSI_LO
SS_HI
ret
;
send_byte:
ldi bitcount,8 ; bit counter
;
SS_LO
c1: SCK_LO
rol dat ; thru carry
brcc c2
MOSI_HI
rjmp c3
c2: MOSI_LO
c3: SCK_HI
dec bitcount
brne c1
ldi bitcount,8 ; get ready for the data byte
ret
CODE_END:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -