📄 max3420e_evkit2_democode.asm
字号:
//---------------------------------------------------------------------------
// Copyright (C) 2006 Maxim Integrated Products, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL MAXIM INTEGRATED PRODUCTS INC. BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//---------------------------------------------------------------------------
;
; Atmel AtTiny2313 Firmware for Maxim 3420E EVKIT-2
;
; MAX3420E HID Keyboard emulator.
;
; At power on, if any of the pushbuttons 0-3 (SW1-SW4) is pressed, enter a test loop
; that reads the pushbuttons and copies their states to the four LEDS 0-3 (D1-D4). The
; LEDS are active-high, and the pushbuttons are active-low, so pressing a pushbutton
; should turn the corresponding LED off. When finished with this test, press buttons
; 0 and 3 simultaneously to proceed to the USB sample application.
;
; The sample application (which automatically runs if no buttons are pressed at power-on)
; implements a HID keyboard emulator. Pressing the SEND button (button 3) starts and stops
; typing an abbreviated version of the MAX3420E data sheet into any Windows window that
; can accept text and which currently has the focus. CAUTION--This includes any open
; window, such as email, a Word document, program editor, etc. Be sure you have a simple
; app like Notepad or Wordpad open and active before pushing the SEND button.
;
; Buttons:
; 0 (not used)
; 1 (not used)
; 2 (not used)
; 3 Start/Stop sending characters as keyboard
;
; Lights:
; 0 Blinks to show program is running
; 1 MAX3420E detected a USB bus reset
; 2 SUSPEND (PC stopped USB activity)
; 3 SEND light. Toggles when pushbutton 3 pressed.
;
.include "tn2313def_lth.inc"
.include "USB_constants.inc"
.include "HID_KB_2313_Descriptors_and_Data.inc"
.include "MAX3420E_Macros.inc"
;
; AtTiny2313 PORT B bit assignments
;
.EQU MOSI = 5 ; out
.EQU MISO = 6 ; in
.EQU SCK = 7 ; out
.EQU INTR = 3 ; in
.EQU SSN = 4 ; out
;
.EQU BUTTC = 250 ; time constant to check pushbuttons
.EQU BLINKTC = 150 ; decremented every buttime
; Assign names to registers. R0-R15 for variables that are not loaded with immediate values.
.DEF configval = R0 ; Initialize to 0, set to contents of host Set_Config request
.DEF dat = R3
.DEF rval = R4
.DEF desclen = R5 ; descriptor length, read from ROM
; Registers that require load-immediate addressing
.DEF flags = R16; ; flags b7=inhibit_send, b6=RWU_enabled, b5=Suspended, b4=ep3stall
.equ Send_Flag = 7
.equ bmSend_Flag = 0b10000000 ; for eor instruction
.equ RWU_enabled = 6
.equ Suspended = 5
.equ ep3stall = 4
.equ setclrfeature = 3
.equ UNIflag = 2 ; Unicode string descriptor requested
.equ butstate = 1 ; send/stop button state
.equ keyupflag = 0 ; send keys-up after every keystroke
.DEF button_time = R17 ; Time delay for polling the pushbuttons. 0-255.
.DEF MAX_Reg = R18 ; Used by rreg and wreg
.DEF MAX_Dat = R19 ; Used by rreg and wreg
.DEF bitcount = R20 ; used by rreg & wreg
.DEF temp = R21 ; ditto
.DEF pMessage = R22 ; Message pointer
.DEF reqlen = R23 ; Requested length
.DEF blink_time = R24 ; Time between light blinks. This 8 bit timer runs 0-255
;
; R25 is reserved for SRAM macros.
; R26 is reserved for the WAIT_TICK macro (not used in this app)
; Note: R26-27=X, R28-29=Y, R30-31=Z
; This program uses only Z as an index register, so R26-R29 are free.
;
.DSEG
SUD: .BYTE 8 ; 8 setup bytes
.CSEG
.ORG 0 ; Interrupt Vectors
rjmp RESET ; RESET
reti ; INT0
reti ; INT1
reti ; TIM1_CAPT
reti ; TIM1_COMPA
reti ; TIM1_OVF
reti ; TIM0_OVF
reti ; USART0_RXC
reti ; USART0_DRE
reti ; USART0_TXC
reti ; ANA_COMP
reti ; PCINT (8 more interrupt vectors but we aren't using them)
;
;------------------------------------------------------
RESET:
;
ldi R16,LOW(RAMEND)
out SPL,r16 ; set stack pointer to top of RAM
clr flags ; initalze all flag bits
clr configval ; we're initially unconfigured
;
SCK_LO ; initialize the SPI outputs before enabling them as outputs
SS_HI
MOSI_LO
ldi r20,0b10110000 ; AtTiny2313: bits 7,5,4 are SPI outputs, bits 6 (MISO),3 (INT) are inputs
out DDRB,r20 ; make them so
WREGI rPINCTL,(bmFDUPSPI+bmPOSINT+1) ; Must do this to set up SPI full duplex before accessing any regs. GPX = VBDetect
rcall Reset_MAX
;
; At power on, check for any button press. If so, enter a test loop that copies button states to the
; four LEDS attached to the MAX3420E GP0 pins. If not, proceed directly to the HID Keyboard application.
;
mRREG rIOPINS ; GPIN3 GPIN2 GPIN1 GPIN0 GPOUT3 GPOUT2 GPOUT1 GPOUT0
andi MAX_dat,0b11110000 ; consider only the input pins
cpi MAX_dat,0b11110000 ; all up?
breq doApp ; go right to the app if nothing pressed. Otherwise, drop thru to button/light test.
;
testbuts:
mRREG rIOPINS
swap MAX_dat
mWREG rIOPINS,MAX_dat ; PB's & LEDS: 1=off, 0=on
andi MAX_dat,0b00001111
cpi MAX_dat,0b00000110 ; pressing both (active low) buttons 0 & 3 stop this test
brne testbuts
;
doApp:
WREGI rIOPINS,0x00 ; all lights off
WREGI rUSBCTL,bmCONNECT
;
Initialize:
WREGI rEPIEN,(bmSUDAVIE+bmIN3BAVIE)
WREGI rUSBIEN,(bmUSBRESIE) ; NOTE: The suspend interrupt is enabled when we are configured as a USB device (Set_Configuration)
WREGI rCPUCTL,bmIE ; enable the INT output pin
ldi blink_time,BLINKTC
;
ldi pMessage,LOW(KB_Message*2); Initialize a pointer to the message to type
rcall send_keystroke ; preload the first KB bytes to clear the IN3BAVIRQ
;
; ******************************************************************************
; Endless loop to check for blink timer, suspend interrupt, and any USB requests
;
mainloop:
sbis pinb,3 ; MAX3420E INT bit tied to PORTB.3 & configured for pos edge
rjmp L5
; Check for Setup Data Available IRQ
mRREG rEPIRQ
mov rval,MAX_Dat
sbrs rval,5 ; EPIRQ reg bit 5 is SUDAVIRQ
rjmp L2
WREGI rEPIRQ,bmSUDAVIRQ ; clear the IRQ bit
rcall Do_SETUP
; Check for EP3 Buffer Available IRQ
L2: sbrs rval,4 ; EPIRQ reg bit 4 is IN3BAVIRQ
rjmp L3
rcall send_keystroke
; Check for USB reset IRQ
L3: mRREG rUSBIRQ
mov rval,MAX_Dat
sbrs rval,3 ; USBIRQ reg bit 3 is URESIRQ
rjmp L4
WREGI rUSBIRQ,bmUSBRESIRQ ; clear the IRQ bit
WREGI rIOPINS,0x02 ; L1 on
ldi MAX_Reg,rUSBIRQ
LR1:rcall rreg
andi MAX_Dat,bmUSBRESDNIRQ ; check for reset done
breq LR1
WREGI rUSBIRQ,bmUSBRESDNIRQ ; clear the IRQ
WREGI rIOPINS,0x00 ; all lights off
rjmp Initialize ; re-enable the interrupts
; Check for SUSPEND IRQ only if we're configured
L4: tst configval
breq L5 ; skip if we're not configured
sbrs rval,4 ; USBIRQ reg bit 4 is SUSPEND IRQ
rjmp L5
rcall Suspend ; stays in this subroutine until RESUME by host
;
L5: dec button_time
brne mainloop ; check buttons if timer expires
;
; Check the button. GPIN-3 = toggle send/stop (was GPIN-1 for AtTiny13)
;
mRREG rIOPINS
bst MAX_Dat,7 ; T <- GPI-3
brtc but_down ; active low--branch if button down
;
bst flags,butstate ; T<-butstate. Button is up--was it up (1) last time?
brts L7 ; yes--do nothing
SETFLAG butstate ; no--just show it's up now
rjmp L7
but_down:
bst flags,butstate ; button is down--was it down (0) last time?
brtc L7 ; yes--do nothing
CLRFLAG butstate ; no--update it and toggle the SEND light
;
; Toggle the Send_Flag
;
ldi temp,bmSend_Flag ; Send_Flag is bit 7 of flags reg
eor flags,temp ; toggle the send bit
bst flags,Send_Flag ; Send_Flag -> T
bld MAX_Dat,3 ; MAX_Dat.3 <- T
mWREG rIOPINS,Max_Dat ; update the SEND light (GPO-3)
;
; Blink a light whenever the blink_count hits zero
;
L7: dec blink_time
brne L8
ldi blink_time,BLINKTC
seT
sbrc MAX_Dat,0 ; check GPOUT0: IOPINS.0 (in MAX_Dat)
clT
bld MAX_Dat,0
rcall wreg
L8: rjmp mainloop
;
; *******************************************************************************
Suspend:
WREGI rUSBIRQ,(bmSUSPIRQ+bmBUSACTIRQ) ; clear the IRQ bit & remove bus activity remnants
WREGI rUSBIEN,BMBUSACTIE ; only check for this interrupt
WREGI rIOPINS,0b00000100 ; turn on GPO-2 light (only) to show SUSPEND
;
; Now wait for the BUSACT IRQ
;
s1: sbis pinb,3 ; MAX3420E INT bit tied to PORTB.3 & configured for pos edge
rjmp s1 ; skip this if INT happened ;
;
suspend_done:
WREGI rUSBIEN,(bmUSBRESIE+bmSUSPENDIE) ;disable BUSACTIE and re-enable BUSRES and SUSPEND IE's
ldi MAX_Reg,rIOPINS
rcall rreg
andi MAX_Dat,0b11111011 ; turn off GPO-2 (SUSPEND) light
rcall wreg
ret
;
; ----------------------------------------------------------------------
; Reset the MAX3420E. Set the CHIPRES bit, delay, clear the CHIPRES bit.
; Then wait for OSCOK IRQ to assert.
; ----------------------------------------------------------------------
Reset_MAX:
WREGI rUSBCTL,bmCHIPRES
ldi MAX_Dat,0 ; remove the chip reset
rcall wreg
;
; Resetting the chip stops the oscillator. Wait for it to stabilize
; by checking the OSCOK interrupt. Note: no need to first clear this
; IRQ because the chip reset does it.
;
ldi MAX_Reg,rUSBIRQ ; the OSCOKIRQ bit lives in this register
rm2:
rcall rreg
andi MAX_Dat,bmOSCOKIRQ
breq rm2
WREGI rUSBIRQ,bmOSCOKIRQ ; clear the OSC IRQ bit
ret
; --------------------
; USB Request routines
; --------------------
;
Do_SETUP: ; Copy 8 setup bytes into SUD array in RAM
ldi MAX_Reg,rSUDFIFO
ldi ZL,LOW(SUD)
ldi ZH,0
ldi temp,8 ; fetch 8 bytes
su1:
rcall rreg ; result in MAX_Dat
st Z+,MAX_Dat
dec temp
brne su1
;
; Respond to standard requests only (HID KB data requests are be requested via IN requests to EP3-IN)
;
lds temp,SUD+bmRequestType
andi temp,0b01100000 ; check b6-b5 for request type
cpi temp,0b00000000 ; 00 is standard request
breq std_request ; don't need to check for 01, class request since we have the INT IN endpoint for data
stall: ; vendor request (10) or undefined.
ldi MAX_Reg,rEPSTALLS
ldi MAX_Dat,0x23
rjmp wreg ; return from there. DON'T set ACKSTAT bit.
;
std_request:
lds temp,SUD+bRequest
cpi temp,13 ; make sure it's 0-12
brcc stall ; carry set for 12-13, clear for 13-13
ldi ZH,HIGH(sr_jump_table)
ldi ZL,LOW(sr_jump_table)
add ZL,temp
brcc nc
inc ZH
nc: ijmp ; PC=Z+temp
;
sr_jump_table: ; Standard Request Jump Table
rjmp Get_Status ; 0
rjmp Clear_Feature ; 1
rjmp stall ; 2--Reserved (Stall)
rjmp Set_Feature ; 3
rjmp stall ; 4--Reserved (Stall)
rjmp as ; 5--Set_Address: do nothing but complete the CTL xfr
rjmp Get_Descriptor ; 6
rjmp stall ; 7--Set_Descriptor (Stall)
rjmp Get_Configuration ; 8
rjmp Set_Configuration ; 9
rjmp Get_Interface ; 10
rjmp Set_Interface ; 11
rjmp stall ; 12--Sync_Frame (Stall)
;
Set_Feature:
SETFLAG setclrfeature
rjmp feature
Clear_Feature:
CLRFLAG setclrfeature ; fall through to 'feature'
;
; ----------------------------------------------------------------
; GET/SET_Feature Request.The 'setclrfeature' flag says which one.
; ----------------------------------------------------------------
feature: ; check for bmRequestType = 0x02 AND wValueL = 0 AND wIndexL = 0x83
lds temp,SUD+bmRequestType
cpi temp,0x02 ; dir is h->p, recipient is EP ?
brne stall
lds temp,SUD+wValueL
cpi temp,0 ; wValueL is feature selector, 00 is EP halt
brne stall
lds temp,SUD+wIndexL
cpi temp,0x83 ; 83 is value for EP3-IN
brne stall ; we only support EP-STALL
;
; It's a Set/Clr_Feature--endpoint halt request
;
ldi MAX_Reg,rEPSTALLS ; get the existing stall bits
rcall rreg ; value in MAX_Dat
SKIP_ON_FLAG setclrfeature
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -