mirror of
				https://git.proxmox.com/git/mirror_linux-firmware
				synced 2025-11-04 14:57:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1185 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
			
		
		
	
	
			1185 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
;   usbdux_firmware.asm
 | 
						|
;   Copyright (C) 2004,2009 Bernd Porr, Bernd.Porr@f2s.com
 | 
						|
;   For usbdux.c
 | 
						|
;
 | 
						|
;   This program is free software; you can redistribute it and/or modify
 | 
						|
;   it under the terms of the GNU General Public License as published by
 | 
						|
;   the Free Software Foundation; either version 2 of the License, or
 | 
						|
;   (at your option) any later version.
 | 
						|
;
 | 
						|
;   This program is distributed in the hope that it will be useful,
 | 
						|
;   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
;   GNU General Public License for more details.
 | 
						|
;
 | 
						|
;   You should have received a copy of the GNU General Public License
 | 
						|
;   along with this program; if not, write to the Free Software
 | 
						|
;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
						|
;
 | 
						|
;
 | 
						|
; Firmware: usbdux_firmware.asm for usbdux.c
 | 
						|
; Description: University of Stirling USB DAQ & INCITE Technology Limited
 | 
						|
; Devices: [ITL] USB-DUX (usbdux.o)
 | 
						|
; Author: Bernd Porr <Bernd.Porr@f2s.com>
 | 
						|
; Updated: 17 Apr 2009
 | 
						|
; Status: stable
 | 
						|
;
 | 
						|
;;;
 | 
						|
;;;
 | 
						|
;;;
 | 
						|
 | 
						|
	.inc	fx2-include.asm
 | 
						|
 | 
						|
	.equ	CHANNELLIST,80h	; channellist in indirect memory
 | 
						|
	
 | 
						|
	.equ	CMD_FLAG,90h	; flag if next IN transf is DIO
 | 
						|
	.equ	SGLCHANNEL,91h	; channel for INSN
 | 
						|
	.equ	PWMFLAG,92h	; PWM
 | 
						|
	
 | 
						|
	.equ	DIOSTAT0,98h	; last status of the digital port
 | 
						|
	.equ	DIOSTAT1,99h	; same for the second counter
 | 
						|
	
 | 
						|
	.equ	CTR0,0A0H	; counter 0
 | 
						|
	.equ	CTR1,0A2H	; counter 1
 | 
						|
			
 | 
						|
	.org	0000h		; after reset the processor starts here
 | 
						|
	ljmp	main		; jump to the main loop
 | 
						|
 | 
						|
	.org	000bh		; timer 0 irq
 | 
						|
	ljmp	timer0_isr
 | 
						|
 | 
						|
	.org	0043h		; the IRQ2-vector
 | 
						|
	ljmp	jmptbl		; irq service-routine
 | 
						|
	
 | 
						|
	.org	0100h		; start of the jump table
 | 
						|
 | 
						|
jmptbl:	ljmp	sudav_isr
 | 
						|
	nop
 | 
						|
	ljmp	sof_isr
 | 
						|
	nop
 | 
						|
	ljmp	sutok_isr
 | 
						|
	nop
 | 
						|
	ljmp	suspend_isr
 | 
						|
	nop
 | 
						|
	ljmp	usbreset_isr
 | 
						|
	nop
 | 
						|
	ljmp	hispeed_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep0ack_isr
 | 
						|
	nop
 | 
						|
	ljmp	spare_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep0in_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep0out_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep1in_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep1out_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep2_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep4_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep6_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep8_isr
 | 
						|
	nop
 | 
						|
	ljmp	ibn_isr
 | 
						|
	nop
 | 
						|
	ljmp	spare_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep0ping_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep1ping_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep2ping_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep4ping_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep6ping_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep8ping_isr
 | 
						|
	nop
 | 
						|
	ljmp	errlimit_isr
 | 
						|
	nop
 | 
						|
	ljmp	spare_isr
 | 
						|
	nop
 | 
						|
	ljmp	spare_isr
 | 
						|
	nop
 | 
						|
	ljmp	spare_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep2isoerr_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep4isoerr_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep6isoerr_isr
 | 
						|
	nop
 | 
						|
	ljmp	ep8isoerr_isr
 | 
						|
 | 
						|
	
 | 
						|
	;; dummy isr
 | 
						|
sudav_isr:	
 | 
						|
sutok_isr:	
 | 
						|
suspend_isr:	
 | 
						|
usbreset_isr:	
 | 
						|
hispeed_isr:	
 | 
						|
ep0ack_isr:	
 | 
						|
spare_isr:	
 | 
						|
ep0in_isr:	
 | 
						|
ep0out_isr:	
 | 
						|
ep1in_isr:	
 | 
						|
ibn_isr:	
 | 
						|
ep0ping_isr:	
 | 
						|
ep1ping_isr:	
 | 
						|
ep2ping_isr:	
 | 
						|
ep4ping_isr:	
 | 
						|
ep6ping_isr:	
 | 
						|
ep8ping_isr:	
 | 
						|
errlimit_isr:	
 | 
						|
ep2isoerr_isr:	
 | 
						|
ep4isoerr_isr:	
 | 
						|
ep6isoerr_isr:	
 | 
						|
ep8isoerr_isr:
 | 
						|
ep6_isr:
 | 
						|
ep2_isr:
 | 
						|
ep4_isr:	
 | 
						|
 | 
						|
	push	dps
 | 
						|
	push	dpl
 | 
						|
	push	dph
 | 
						|
	push	dpl1
 | 
						|
	push	dph1
 | 
						|
	push	acc
 | 
						|
	push	psw
 | 
						|
 | 
						|
	;; clear the USB2 irq bit and return
 | 
						|
	mov	a,EXIF
 | 
						|
	clr	acc.4
 | 
						|
	mov	EXIF,a
 | 
						|
 | 
						|
	pop	psw
 | 
						|
	pop	acc 
 | 
						|
	pop	dph1 
 | 
						|
	pop	dpl1
 | 
						|
	pop	dph 
 | 
						|
	pop	dpl 
 | 
						|
	pop	dps
 | 
						|
	
 | 
						|
	reti
 | 
						|
 | 
						|
		
 | 
						|
;;; main program
 | 
						|
;;; basically only initialises the processor and
 | 
						|
;;; then engages in an endless loop
 | 
						|
main:
 | 
						|
	mov	DPTR,#CPUCS	; CPU control register
 | 
						|
	mov	a,#00010000b	; 48Mhz
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
        mov     dptr,#REVCTL
 | 
						|
        mov     a,#00000011b    ; allows skip
 | 
						|
        lcall   syncdelaywr
 | 
						|
 | 
						|
	mov	IP,#0		; all std 8051 int have low priority
 | 
						|
	mov	EIP,#0FFH	; all FX2 interrupts have high priority
 | 
						|
	
 | 
						|
	mov	dptr,#INTSETUP	; IRQ setup register
 | 
						|
	mov	a,#08h		; enable autovector
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	lcall	initAD		; init the ports to the converters
 | 
						|
 | 
						|
	lcall	initeps		; init the isochronous data-transfer
 | 
						|
 | 
						|
	lcall	init_timer
 | 
						|
	
 | 
						|
mloop2:	nop
 | 
						|
 | 
						|
;;; pwm
 | 
						|
	mov	r0,#PWMFLAG	; pwm on?
 | 
						|
	mov	a,@r0		; get info
 | 
						|
	jz	mloop2		; it's off
 | 
						|
 | 
						|
	mov	a,GPIFTRIG	; GPIF status
 | 
						|
	anl	a,#80h		; done bit
 | 
						|
	jz	mloop2		; GPIF still busy
 | 
						|
 | 
						|
        mov     a,#01h		; WR,EP4, 01 = EP4
 | 
						|
        mov     GPIFTRIG,a	; restart it
 | 
						|
 | 
						|
	sjmp	mloop2		; loop for ever
 | 
						|
 | 
						|
 | 
						|
;;; GPIF waveform for PWM
 | 
						|
waveform:
 | 
						|
	;;      0     1     2     3     4     5     6     7(not used)
 | 
						|
	;; len (gives 50.007Hz)
 | 
						|
	.db	195,  195,  195,  195,  195,  195,  1,    1
 | 
						|
 | 
						|
	;; opcode
 | 
						|
	.db	002H, 006H, 002H, 002H, 002H, 002H, 002H, 002H
 | 
						|
	
 | 
						|
	;; out
 | 
						|
	.db	0ffH, 0ffH, 0ffH, 0ffH, 0ffH, 0ffH, 0ffH, 0ffH
 | 
						|
 | 
						|
	;; log
 | 
						|
	.db	000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H
 | 
						|
 | 
						|
 | 
						|
stopPWM:
 | 
						|
	mov	r0,#PWMFLAG	; flag for PWM
 | 
						|
	mov	a,#0		; PWM (for the main loop)
 | 
						|
	mov	@r0,a		; set it
 | 
						|
 | 
						|
	mov	dptr,#IFCONFIG	; switch off GPIF
 | 
						|
	mov	a,#10000000b	; gpif, 30MHz, internal IFCLK
 | 
						|
	lcall	syncdelaywr
 | 
						|
	ret
 | 
						|
	
 | 
						|
 | 
						|
;;; init PWM
 | 
						|
startPWM:
 | 
						|
	mov	dptr,#IFCONFIG	; switch on IFCLK signal
 | 
						|
	mov	a,#10000010b	; gpif, 30MHz, internal IFCLK
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	mov	OEB,0FFH	; output to port B
 | 
						|
 | 
						|
	mov	DPTR,#EP4CFG
 | 
						|
	mov	a,#10100000b	; valid, out, bulk
 | 
						|
	movx	@DPTR,a
 | 
						|
 | 
						|
	;; reset the endpoint
 | 
						|
	mov	dptr,#FIFORESET
 | 
						|
	mov	a,#80h		; NAK
 | 
						|
	lcall	syncdelaywr
 | 
						|
	mov	a,#84h		; reset EP4 + NAK
 | 
						|
	lcall	syncdelaywr
 | 
						|
	mov	a,#0		; normal op
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	mov	dptr,#EP4BCL
 | 
						|
	mov	a,#0H		; discard packets
 | 
						|
	lcall	syncdelaywr	; empty FIFO buffer
 | 
						|
	lcall	syncdelaywr	; empty FIFO buffer
 | 
						|
 | 
						|
	;; aborts all transfers by the GPIF
 | 
						|
	mov	dptr,#GPIFABORT
 | 
						|
	mov	a,#0ffh		; abort all transfers
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	;; wait for GPIF to finish
 | 
						|
wait_f_abort:
 | 
						|
	mov	a,GPIFTRIG	; GPIF status
 | 
						|
	anl	a,#80h		; done bit
 | 
						|
	jz	wait_f_abort	; GPIF busy
 | 
						|
 | 
						|
        mov     dptr,#GPIFCTLCFG
 | 
						|
        mov     a,#10000000b    ; tri state for CTRL
 | 
						|
        lcall   syncdelaywr
 | 
						|
 | 
						|
        mov     dptr,#GPIFIDLECTL
 | 
						|
        mov     a,#11110000b    ; all CTL outputs low
 | 
						|
        lcall   syncdelaywr
 | 
						|
 | 
						|
	;; abort if FIFO is empty
 | 
						|
        mov     a,#00000001b    ; abort if empty
 | 
						|
        mov     dptr,#EP4GPIFFLGSEL
 | 
						|
        lcall   syncdelaywr
 | 
						|
 | 
						|
	;; 
 | 
						|
        mov     a,#00000001b    ; stop if GPIF flg
 | 
						|
        mov     dptr,#EP4GPIFPFSTOP
 | 
						|
        lcall   syncdelaywr
 | 
						|
 | 
						|
	;; transaction counter
 | 
						|
	mov	a,#0ffH
 | 
						|
	mov	dptr,#GPIFTCB3
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	;; transaction counter
 | 
						|
	mov	a,#0ffH
 | 
						|
	mov	dptr,#GPIFTCB2
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	;; transaction counter
 | 
						|
	mov	a,#0ffH		; 512 bytes
 | 
						|
	mov	dptr,#GPIFTCB1
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	;; transaction counter
 | 
						|
	mov	a,#0ffH
 | 
						|
	mov	dptr,#GPIFTCB0
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	;; RDY pins. Not used here.
 | 
						|
        mov     a,#0
 | 
						|
        mov     dptr,#GPIFREADYCFG
 | 
						|
        lcall   syncdelaywr
 | 
						|
 | 
						|
	;; drives the output in the IDLE state
 | 
						|
        mov     a,#1
 | 
						|
        mov     dptr,#GPIFIDLECS
 | 
						|
        lcall   syncdelaywr
 | 
						|
 | 
						|
	;; direct data transfer from the EP to the GPIF
 | 
						|
	mov	dptr,#EP4FIFOCFG
 | 
						|
	mov	a,#00010000b	; autoout=1, byte-wide
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	;; waveform 0 is used for FIFO out
 | 
						|
	mov	dptr,#GPIFWFSELECT
 | 
						|
	mov	a,#00000000b
 | 
						|
	movx	@dptr,a
 | 
						|
	lcall	syncdelay
 | 
						|
 | 
						|
	;; transfer the delay byte from the EP to the waveform
 | 
						|
	mov	dptr,#0e781h	; EP1 buffer
 | 
						|
	movx	a,@dptr		; get the delay
 | 
						|
	mov	dptr,#waveform	; points to the waveform
 | 
						|
	mov	r2,#6		; fill 6 bytes
 | 
						|
timloop:
 | 
						|
	movx	@dptr,a		; save timing in a xxx
 | 
						|
	inc	dptr
 | 
						|
	djnz	r2,timloop	; fill the 6 delay bytes
 | 
						|
 | 
						|
	;; load waveform
 | 
						|
        mov     AUTOPTRH2,#0E4H ; XDATA0H
 | 
						|
        lcall   syncdelay
 | 
						|
        mov     AUTOPTRL2,#00H  ; XDATA0L
 | 
						|
        lcall   syncdelay
 | 
						|
 | 
						|
	mov	dptr,#waveform	; points to the waveform
 | 
						|
	
 | 
						|
        mov     AUTOPTRSETUP,#7 ; autoinc and enable
 | 
						|
        lcall   syncdelay
 | 
						|
 | 
						|
        mov     r2,#20H         ; 32 bytes to transfer
 | 
						|
 | 
						|
wavetr:
 | 
						|
        movx    a,@dptr
 | 
						|
	inc	dptr
 | 
						|
	push	dpl
 | 
						|
	push	dph
 | 
						|
	push	dpl1
 | 
						|
	push	dph1
 | 
						|
        mov     dptr,#XAUTODAT2
 | 
						|
        movx    @dptr,a
 | 
						|
        lcall   syncdelay
 | 
						|
	pop	dph1 
 | 
						|
	pop	dpl1
 | 
						|
	pop	dph 
 | 
						|
	pop	dpl
 | 
						|
        djnz    r2,wavetr
 | 
						|
 | 
						|
	mov	dptr,#OUTPKTEND
 | 
						|
	mov	a,#084H
 | 
						|
	lcall	syncdelaywr
 | 
						|
	lcall	syncdelaywr
 | 
						|
 | 
						|
	mov	r0,#PWMFLAG	; flag for PWM
 | 
						|
	mov	a,#1		; PWM (for the main loop)
 | 
						|
	mov	@r0,a		; set it
 | 
						|
 | 
						|
	ret
 | 
						|
 | 
						|
 | 
						|
 | 
						|
;;; initialise the ports for the AD-converter
 | 
						|
initAD:
 | 
						|
	mov	OEA,#27H	;PortA0,A1,A2,A5 Outputs
 | 
						|
	mov	IOA,#22H	;/CS = 1, disable transfers to the converters
 | 
						|
	ret
 | 
						|
 | 
						|
 | 
						|
;;; init the timer for the soft counters
 | 
						|
init_timer:
 | 
						|
	;; init the timer for 2ms sampling rate
 | 
						|
	mov	CKCON,#00000001b; CLKOUT/12 for timer
 | 
						|
	mov	TL0,#010H	; 16
 | 
						|
	mov	TH0,#0H		; 256
 | 
						|
	mov	IE,#82H		; switch on timer interrupt (80H for all IRQs)
 | 
						|
	mov	TMOD,#00000000b	; 13 bit counters
 | 
						|
	setb	TCON.4		; enable timer 0
 | 
						|
	ret
 | 
						|
 | 
						|
 | 
						|
;;; from here it's only IRQ handling...
 | 
						|
	
 | 
						|
;;; A/D-conversion:
 | 
						|
;;; control-byte in a,
 | 
						|
;;; result in r3(low) and r4(high)
 | 
						|
;;; this routine is optimised for speed
 | 
						|
readAD:				; mask the control byte
 | 
						|
	anl	a,#01111100b	; only the channel, gain+pol are left
 | 
						|
	orl	a,#10000001b	; start bit, external clock
 | 
						|
	;; set CS to low
 | 
						|
	clr	IOA.1		; set /CS to zero
 | 
						|
	;; send the control byte to the AD-converter
 | 
						|
	mov 	R2,#8		; bit-counter
 | 
						|
bitlp:	jnb     ACC.7,bitzero	; jump if Bit7 = 0?
 | 
						|
	setb	IOA.2		; set the DIN bit
 | 
						|
	sjmp	clock		; continue with the clock
 | 
						|
bitzero:clr	IOA.2		; clear the DIN bit
 | 
						|
clock:	setb	IOA.0		; SCLK = 1
 | 
						|
	clr	IOA.0		; SCLK = 0
 | 
						|
        rl      a               ; next Bit
 | 
						|
        djnz    R2,bitlp
 | 
						|
 | 
						|
	;; continue the aquisition (already started)
 | 
						|
	clr	IOA.2		; clear the DIN bit
 | 
						|
	mov 	R2,#5		; five steps for the aquision
 | 
						|
clockaq:setb	IOA.0		; SCLK = 1
 | 
						|
	clr	IOA.0		; SCLK = 0
 | 
						|
        djnz    R2,clockaq	; loop
 | 
						|
	
 | 
						|
	;; read highbyte from the A/D-converter
 | 
						|
	;; and do the conversion
 | 
						|
	mov	r4,#0 		; Highbyte goes into R4
 | 
						|
	mov	R2,#4		; COUNTER 4 data bits in the MSB
 | 
						|
	mov	r5,#08h		; create bit-mask
 | 
						|
gethi:				; loop get the 8 highest bits from MSB downw
 | 
						|
	setb	IOA.0		; SCLK = 1
 | 
						|
	clr	IOA.0		; SCLK = 0
 | 
						|
	mov	a,IOA		; from port A
 | 
						|
	jnb	ACC.4,zerob	; the in-bit is zero
 | 
						|
	mov	a,r4		; get the byte
 | 
						|
	orl	a,r5		; or the bit to the result
 | 
						|
	mov	r4,a		; save it again in r4
 | 
						|
zerob:	mov	a,r5		; get r5 in order to shift the mask
 | 
						|
	rr	a		; rotate right
 | 
						|
	mov	r5,a		; back to r5
 | 
						|
	djnz	R2,gethi
 | 
						|
	;; read the lowbyte from the A/D-converter
 | 
						|
	mov	r3,#0 		; Lowbyte goes into R3
 | 
						|
	mov	r2,#8		; COUNTER 8 data-bits in the LSB
 | 
						|
	mov	r5,#80h		; create bit-mask
 | 
						|
getlo:				; loop get the 8 highest bits from MSB downw
 | 
						|
	setb	IOA.0		; SCLK = 1
 | 
						|
	clr	IOA.0		; SCLK = 0
 | 
						|
	mov	a,IOA		; from port A
 | 
						|
	jnb	ACC.4,zerob2	; the in-bit is zero
 | 
						|
	mov	a,r3		; get the result-byte
 | 
						|
	orl	a,r5		; or the bit to the result
 | 
						|
	mov	r3,a		; save it again in r4
 | 
						|
zerob2:	mov	a,r5		; get r5 in order to shift the mask
 | 
						|
	rr	a		; rotate right
 | 
						|
	mov	r5,a		; back to r5
 | 
						|
	djnz	R2,getlo
 | 
						|
	setb	IOA.1		; set /CS to one
 | 
						|
	;;
 | 
						|
	ret
 | 
						|
	
 | 
						|
 | 
						|
	
 | 
						|
;;; aquires data from A/D channels and stores them in the EP6 buffer
 | 
						|
conv_ad:
 | 
						|
	mov	AUTOPTRH1,#0F8H	; auto pointer on EP6
 | 
						|
	mov	AUTOPTRL1,#00H
 | 
						|
	mov	AUTOPTRSETUP,#7
 | 
						|
	mov	r0,#CHANNELLIST	; points to the channellist
 | 
						|
 | 
						|
	mov	a,@r0		; number of channels
 | 
						|
	mov	r1,a		; counter
 | 
						|
 | 
						|
	mov 	DPTR,#XAUTODAT1	; auto pointer
 | 
						|
convloop:
 | 
						|
	inc	r0
 | 
						|
	mov 	a,@r0		; Channel
 | 
						|
	lcall 	readAD
 | 
						|
	mov 	a,R3		;
 | 
						|
	movx 	@DPTR,A
 | 
						|
	mov 	a,R4		;
 | 
						|
	movx 	@DPTR,A
 | 
						|
	djnz	r1,convloop
 | 
						|
 | 
						|
	ret
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
;;; initilise the transfer
 | 
						|
;;; It is assumed that the USB interface is in alternate setting 3
 | 
						|
initeps:
 | 
						|
	mov	dptr,#FIFORESET
 | 
						|
	mov	a,#80H		
 | 
						|
	movx	@dptr,a		; reset all fifos
 | 
						|
	mov	a,#2	
 | 
						|
	movx	@dptr,a		; 
 | 
						|
	mov	a,#4		
 | 
						|
	movx	@dptr,a		; 
 | 
						|
	mov	a,#6		
 | 
						|
	movx	@dptr,a		; 
 | 
						|
	mov	a,#8		
 | 
						|
	movx	@dptr,a		; 
 | 
						|
	mov	a,#0		
 | 
						|
	movx	@dptr,a		; normal operat
 | 
						|
	
 | 
						|
	mov	DPTR,#EP2CFG
 | 
						|
	mov	a,#10010010b	; valid, out, double buff, iso
 | 
						|
	movx	@DPTR,a
 | 
						|
 | 
						|
	mov	dptr,#EP2FIFOCFG
 | 
						|
	mov	a,#00000000b	; manual
 | 
						|
	movx	@dptr,a
 | 
						|
 | 
						|
	mov	dptr,#EP2BCL	; "arm" it
 | 
						|
	mov	a,#00h
 | 
						|
	movx	@DPTR,a		; can receive data
 | 
						|
	lcall	syncdelay	; wait to sync
 | 
						|
	movx	@DPTR,a		; can receive data
 | 
						|
	lcall	syncdelay	; wait to sync
 | 
						|
	movx	@DPTR,a		; can receive data
 | 
						|
	lcall	syncdelay	; wait to sync
 | 
						|
	
 | 
						|
	mov	DPTR,#EP1OUTCFG
 | 
						|
	mov	a,#10100000b	; valid
 | 
						|
	movx	@dptr,a
 | 
						|
 | 
						|
	mov	dptr,#EP1OUTBC	; "arm" it
 | 
						|
	mov	a,#00h
 | 
						|
	movx	@DPTR,a		; can receive data
 | 
						|
	lcall	syncdelay	; wait until we can write again
 | 
						|
	movx	@dptr,a		; make shure its really empty
 | 
						|
	lcall	syncdelay	; wait
 | 
						|
 | 
						|
	mov	DPTR,#EP6CFG	; ISO data from here to the host
 | 
						|
	mov	a,#11010010b	; Valid
 | 
						|
	movx	@DPTR,a		; ISO transfer, double buffering
 | 
						|
 | 
						|
	mov	DPTR,#EP8CFG	; EP8
 | 
						|
	mov	a,#11100000b	; BULK data from here to the host
 | 
						|
	movx	@DPTR,a		;
 | 
						|
 | 
						|
	mov	dptr,#EPIE	; interrupt enable
 | 
						|
	mov	a,#10001000b	; enable irq for ep1out,8
 | 
						|
	movx	@dptr,a		; do it
 | 
						|
 | 
						|
	mov	dptr,#EPIRQ	; clear IRQs
 | 
						|
	mov	a,#10100000b
 | 
						|
	movx	@dptr,a
 | 
						|
 | 
						|
	;; enable interrups
 | 
						|
        mov     DPTR,#USBIE	; USB int enables register
 | 
						|
        mov     a,#2            ; enables SOF (1ms/125us interrupt)
 | 
						|
        movx    @DPTR,a         ; 
 | 
						|
 | 
						|
	mov	EIE,#00000001b	; enable INT2 in the 8051's SFR
 | 
						|
	mov	IE,#80h		; IE, enable all interrupts
 | 
						|
 | 
						|
	ret
 | 
						|
 | 
						|
 | 
						|
;;; counter
 | 
						|
;;; r0: DIOSTAT
 | 
						|
;;; r1:	counter address
 | 
						|
;;; r2:	up/down-mask
 | 
						|
;;; r3:	reset-mask
 | 
						|
;;; r4:	clock-mask
 | 
						|
counter:	
 | 
						|
	mov	a,IOB		; actual IOB input state
 | 
						|
	mov	r5,a		; save in r5
 | 
						|
	anl	a,r3		; bit mask for reset
 | 
						|
	jz	no_reset	; reset if one
 | 
						|
	clr	a		; set counter to zero
 | 
						|
	mov	@r1,a
 | 
						|
	inc	r4
 | 
						|
	mov	@r1,a
 | 
						|
	sjmp	ctr_end
 | 
						|
no_reset:	
 | 
						|
	mov	a,@r0		; get last state
 | 
						|
	xrl	a,r5		; has it changed?
 | 
						|
	anl	a,r5		; is it now on?
 | 
						|
	anl	a,r4		; mask out the port
 | 
						|
	jz	ctr_end		; no rising edge
 | 
						|
	mov	a,r5		; get port B again
 | 
						|
	anl	a,r2		; test if up or down
 | 
						|
	jnz	ctr_up		; count up
 | 
						|
	mov	a,@r1
 | 
						|
	dec	a
 | 
						|
	mov	@r1,a
 | 
						|
	cjne	a,#0ffh,ctr_end	; underflow?
 | 
						|
	inc	r1		; high byte
 | 
						|
	mov	a,@r1
 | 
						|
	dec	a
 | 
						|
	mov	@r1,a
 | 
						|
	sjmp	ctr_end
 | 
						|
ctr_up:				; count up
 | 
						|
	mov	a,@r1
 | 
						|
	inc	a
 | 
						|
	mov	@r1,a
 | 
						|
	jnz	ctr_end
 | 
						|
	inc	r1		; high byte
 | 
						|
	mov	a,@r1
 | 
						|
	inc	a
 | 
						|
	mov	@r1,a
 | 
						|
ctr_end:
 | 
						|
	mov	a,r5
 | 
						|
	mov	@r0,a
 | 
						|
	ret
 | 
						|
 | 
						|
;;; implements two soft counters with up/down and reset
 | 
						|
timer0_isr:
 | 
						|
	push	dps
 | 
						|
	push	acc
 | 
						|
	push	psw
 | 
						|
	push	00h		; R0
 | 
						|
	push	01h		; R1
 | 
						|
	push	02h		; R2
 | 
						|
	push	03h		; R3
 | 
						|
	push	04h		; R4
 | 
						|
	push	05h		; R5
 | 
						|
		
 | 
						|
	mov	r0,#DIOSTAT0	; status of port
 | 
						|
	mov	r1,#CTR0	; address of counter0
 | 
						|
	mov	a,#00000001b	; bit 0
 | 
						|
	mov	r4,a		; clock
 | 
						|
	rl	a		; bit 1
 | 
						|
	mov	r2,a		; up/down
 | 
						|
	rl	a		; bit 2
 | 
						|
	mov	r3,a		; reset mask
 | 
						|
	lcall	counter
 | 
						|
	inc	r0		; to DISTAT1
 | 
						|
	inc	r1		; to CTR1
 | 
						|
	inc	r1
 | 
						|
	mov	a,r3
 | 
						|
	rl	a		; bit 3
 | 
						|
	rl	a		; bit 4
 | 
						|
	mov	r4,a		; clock
 | 
						|
	rl	a		; bit 5
 | 
						|
	mov	r2,a		; up/down
 | 
						|
	rl	a		; bit 6
 | 
						|
	mov	r3,a		; reset
 | 
						|
	lcall	counter
 | 
						|
	
 | 
						|
	pop	05h		; R5
 | 
						|
	pop	04h		; R4
 | 
						|
	pop	03h		; R3
 | 
						|
	pop	02h		; R2
 | 
						|
	pop	01h		; R1
 | 
						|
	pop	00h		; R0
 | 
						|
	pop	psw
 | 
						|
	pop	acc 
 | 
						|
	pop	dps
 | 
						|
 | 
						|
	reti
 | 
						|
 | 
						|
;;; interrupt-routine for SOF
 | 
						|
;;; is for full speed
 | 
						|
sof_isr:
 | 
						|
	push	dps
 | 
						|
	push	dpl
 | 
						|
	push	dph
 | 
						|
	push	dpl1
 | 
						|
	push	dph1
 | 
						|
	push	acc
 | 
						|
	push	psw
 | 
						|
	push	00h		; R0
 | 
						|
	push	01h		; R1
 | 
						|
	push	02h		; R2
 | 
						|
	push	03h		; R3
 | 
						|
	push	04h		; R4
 | 
						|
	push	05h		; R5
 | 
						|
	push	06h		; R6
 | 
						|
	push	07h		; R7
 | 
						|
		
 | 
						|
	mov	a,EP2468STAT
 | 
						|
	anl	a,#20H		; full?
 | 
						|
	jnz	epfull		; EP6-buffer is full
 | 
						|
 | 
						|
	lcall	conv_ad		; conversion
 | 
						|
 | 
						|
	mov	DPTR,#EP6BCH	; byte count H
 | 
						|
	mov	a,#0		; is zero
 | 
						|
	lcall	syncdelaywr	; wait until we can write again
 | 
						|
	
 | 
						|
	mov	DPTR,#EP6BCL	; byte count L
 | 
						|
	mov	a,#10H		; is 8x word = 16 bytes
 | 
						|
	lcall	syncdelaywr	; wait until we can write again
 | 
						|
	
 | 
						|
epfull:
 | 
						|
	;; do the D/A conversion
 | 
						|
	mov	a,EP2468STAT
 | 
						|
	anl	a,#01H		; empty
 | 
						|
	jnz	epempty		; nothing to get
 | 
						|
 | 
						|
	mov	dptr,#0F000H	; EP2 fifo buffer
 | 
						|
	lcall	dalo		; conversion
 | 
						|
 | 
						|
	mov	dptr,#EP2BCL	; "arm" it
 | 
						|
	mov	a,#00h
 | 
						|
	lcall	syncdelaywr	; wait for the rec to sync
 | 
						|
	lcall	syncdelaywr	; wait for the rec to sync
 | 
						|
 | 
						|
epempty:	
 | 
						|
	;; clear INT2
 | 
						|
	mov	a,EXIF		; FIRST clear the USB (INT2) interrupt request
 | 
						|
	clr	acc.4
 | 
						|
	mov	EXIF,a		; Note: EXIF reg is not 8051 bit-addressable
 | 
						|
	
 | 
						|
	mov	DPTR,#USBIRQ	; points to the SOF
 | 
						|
	mov	a,#2		; clear the SOF
 | 
						|
	movx	@DPTR,a
 | 
						|
 | 
						|
nosof:	
 | 
						|
	pop	07h
 | 
						|
	pop	06h
 | 
						|
	pop	05h
 | 
						|
	pop	04h		; R4
 | 
						|
	pop	03h		; R3
 | 
						|
	pop	02h		; R2
 | 
						|
	pop	01h		; R1
 | 
						|
	pop	00h		; R0
 | 
						|
	pop	psw
 | 
						|
	pop	acc 
 | 
						|
	pop	dph1 
 | 
						|
	pop	dpl1
 | 
						|
	pop	dph 
 | 
						|
	pop	dpl 
 | 
						|
	pop	dps
 | 
						|
	reti
 | 
						|
 | 
						|
 | 
						|
reset_ep8:
 | 
						|
	;; erase all data in ep8
 | 
						|
	mov	dptr,#FIFORESET
 | 
						|
	mov	a,#80H		; NAK
 | 
						|
	lcall	syncdelaywr
 | 
						|
	mov	dptr,#FIFORESET
 | 
						|
	mov	a,#8		; reset EP8
 | 
						|
	lcall	syncdelaywr
 | 
						|
	mov	dptr,#FIFORESET
 | 
						|
	mov	a,#0		; normal operation
 | 
						|
	lcall	syncdelaywr
 | 
						|
	ret
 | 
						|
 | 
						|
 | 
						|
reset_ep6:
 | 
						|
	;; throw out old data
 | 
						|
	mov	dptr,#FIFORESET
 | 
						|
	mov	a,#80H		; NAK
 | 
						|
	lcall	syncdelaywr
 | 
						|
	mov	dptr,#FIFORESET
 | 
						|
	mov	a,#6		; reset EP6
 | 
						|
	lcall	syncdelaywr
 | 
						|
	mov	dptr,#FIFORESET
 | 
						|
	mov	a,#0		; normal operation
 | 
						|
	lcall	syncdelaywr
 | 
						|
	ret
 | 
						|
 | 
						|
;;; interrupt-routine for ep1out
 | 
						|
;;; receives the channel list and other commands
 | 
						|
ep1out_isr:
 | 
						|
	push	dps
 | 
						|
	push	dpl
 | 
						|
	push	dph
 | 
						|
	push	dpl1
 | 
						|
	push	dph1
 | 
						|
	push	acc
 | 
						|
	push	psw
 | 
						|
	push	00h		; R0
 | 
						|
	push	01h		; R1
 | 
						|
	push	02h		; R2
 | 
						|
	push	03h		; R3
 | 
						|
	push	04h		; R4
 | 
						|
	push	05h		; R5
 | 
						|
	push	06h		; R6
 | 
						|
	push	07h		; R7
 | 
						|
		
 | 
						|
	mov	dptr,#0E780h	; FIFO buffer of EP1OUT
 | 
						|
	movx	a,@dptr		; get the first byte
 | 
						|
	mov	r0,#CMD_FLAG	; pointer to the command byte
 | 
						|
	mov 	@r0,a		; store the command byte for ep8
 | 
						|
 | 
						|
	mov	dptr,#ep1out_jmp; jump table for the different functions
 | 
						|
	rl	a		; multiply by 2: sizeof sjmp
 | 
						|
	jmp	@a+dptr		; jump to the jump table
 | 
						|
	;; jump table, corresponds to the command bytes defined
 | 
						|
	;; in usbdux.c
 | 
						|
ep1out_jmp:
 | 
						|
	sjmp	storechannellist; a=0
 | 
						|
	sjmp	single_da	; a=1
 | 
						|
	sjmp	config_digital_b; a=2
 | 
						|
	sjmp	write_digital_b	; a=3
 | 
						|
	sjmp	storesglchannel	; a=4
 | 
						|
	sjmp	readcounter	; a=5
 | 
						|
	sjmp	writecounter	; a=6
 | 
						|
	sjmp	pwm_on		; a=7
 | 
						|
	sjmp	pwm_off		; a=8
 | 
						|
 | 
						|
pwm_on:
 | 
						|
	lcall	startPWM
 | 
						|
	sjmp	over_da
 | 
						|
 | 
						|
pwm_off:
 | 
						|
	lcall	stopPWM
 | 
						|
	sjmp	over_da
 | 
						|
 | 
						|
	;; read the counter
 | 
						|
readcounter:
 | 
						|
	lcall	reset_ep8	; reset ep8
 | 
						|
	lcall	ep8_ops		; fill the counter data in there
 | 
						|
	sjmp	over_da		; jump to the end
 | 
						|
 | 
						|
	;; write zeroes to the counters
 | 
						|
writecounter:
 | 
						|
	mov	dptr,#0e781h	; buffer
 | 
						|
	mov	r0,#CTR0	; r0 points to counter 0
 | 
						|
	movx	a,@dptr		; channel number
 | 
						|
	jz	wrctr0		; first channel
 | 
						|
	mov	r1,a		; counter
 | 
						|
wrctrl:
 | 
						|
	inc	r0		; next counter
 | 
						|
	inc	r0		; next counter
 | 
						|
	djnz	r1,wrctrl	; advance to the right counter
 | 
						|
wrctr0:
 | 
						|
	inc	dptr		; get to the value
 | 
						|
	movx	a,@dptr		; get value
 | 
						|
	mov	@r0,a		; save in ctr
 | 
						|
	inc	r0		; next byte
 | 
						|
	inc	dptr
 | 
						|
	movx	a,@dptr		; get value
 | 
						|
	mov	@r0,a		; save in ctr
 | 
						|
	sjmp	over_da		; jump to the end
 | 
						|
 | 
						|
storesglchannel:
 | 
						|
	mov	r0,#SGLCHANNEL	; the conversion bytes are now stored in 80h
 | 
						|
	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
 | 
						|
	movx	a,@dptr		; 
 | 
						|
	mov	@r0,a
 | 
						|
 | 
						|
	lcall	reset_ep8	; reset FIFO
 | 
						|
	;; Save new A/D data in EP8. This is the first byte
 | 
						|
	;; the host will read during an INSN. If there are
 | 
						|
	;; more to come they will be handled by the ISR of
 | 
						|
	;; ep8.
 | 
						|
	lcall	ep8_ops		; get A/D data
 | 
						|
		
 | 
						|
	sjmp	over_da
 | 
						|
 | 
						|
	
 | 
						|
;;; Channellist:
 | 
						|
;;; the first byte is zero:
 | 
						|
;;; we've just received the channel list
 | 
						|
;;; the channel list is stored in the addresses from CHANNELLIST which
 | 
						|
;;; are _only_ reachable by indirect addressing
 | 
						|
storechannellist:
 | 
						|
	mov	r0,#CHANNELLIST	; the conversion bytes are now stored in 80h
 | 
						|
	mov	r2,#9		; counter
 | 
						|
	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
 | 
						|
chanlloop:	
 | 
						|
	movx	a,@dptr		; 
 | 
						|
	mov	@r0,a
 | 
						|
	inc	dptr
 | 
						|
	inc	r0
 | 
						|
	djnz	r2,chanlloop
 | 
						|
 | 
						|
	lcall	reset_ep6	; reset FIFO
 | 
						|
	
 | 
						|
	;; load new A/D data into EP6
 | 
						|
	;; This must be done. Otherwise the ISR is never called.
 | 
						|
	;; The ISR is only called when data has _left_ the
 | 
						|
	;; ep buffer here it has to be refilled.
 | 
						|
	lcall	ep6_arm		; fill with the first data byte
 | 
						|
	
 | 
						|
	sjmp	over_da
 | 
						|
 | 
						|
;;; Single DA conversion. The 2 bytes are in the FIFO buffer
 | 
						|
single_da:
 | 
						|
	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
 | 
						|
	lcall	dalo		; conversion
 | 
						|
	sjmp	over_da
 | 
						|
 | 
						|
;;; configure the port B as input or output (bitwise)
 | 
						|
config_digital_b:
 | 
						|
	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
 | 
						|
	movx	a,@dptr		; get the second byte
 | 
						|
	mov	OEB,a		; set the output enable bits
 | 
						|
	sjmp	over_da
 | 
						|
	
 | 
						|
;;; Write one byte to the external digital port B
 | 
						|
;;; and prepare for digital read
 | 
						|
write_digital_b:
 | 
						|
	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
 | 
						|
	movx	a,@dptr		; get the second byte
 | 
						|
	mov	OEB,a		; output enable
 | 
						|
	inc	dptr		; next byte
 | 
						|
	movx	a,@dptr		; bits
 | 
						|
	mov	IOB,a		; send the byte to the I/O port
 | 
						|
 | 
						|
	lcall	reset_ep8	; reset FIFO of ep 8
 | 
						|
 | 
						|
	;; fill ep8 with new data from port B
 | 
						|
	;; When the host requests the data it's already there.
 | 
						|
	;; This must be so. Otherwise the ISR is not called.
 | 
						|
	;; The ISR is only called when a packet has been delivered
 | 
						|
	;; to the host. Thus, we need a packet here in the
 | 
						|
	;; first instance.
 | 
						|
	lcall	ep8_ops		; get digital data
 | 
						|
 | 
						|
	;; 
 | 
						|
	;; for all commands the same
 | 
						|
over_da:	
 | 
						|
	mov	dptr,#EP1OUTBC
 | 
						|
	mov	a,#00h
 | 
						|
	lcall	syncdelaywr	; arm
 | 
						|
	lcall	syncdelaywr	; arm
 | 
						|
	lcall	syncdelaywr	; arm
 | 
						|
 | 
						|
	;; clear INT2
 | 
						|
	mov	a,EXIF		; FIRST clear the USB (INT2) interrupt request
 | 
						|
	clr	acc.4
 | 
						|
	mov	EXIF,a		; Note: EXIF reg is not 8051 bit-addressable
 | 
						|
 | 
						|
	mov	DPTR,#EPIRQ	; 
 | 
						|
	mov	a,#00001000b	; clear the ep1outirq
 | 
						|
	movx	@DPTR,a
 | 
						|
 | 
						|
	pop	07h
 | 
						|
	pop	06h
 | 
						|
	pop	05h
 | 
						|
	pop	04h		; R4
 | 
						|
	pop	03h		; R3
 | 
						|
	pop	02h		; R2
 | 
						|
	pop	01h		; R1
 | 
						|
	pop	00h		; R0
 | 
						|
	pop	psw
 | 
						|
	pop	acc 
 | 
						|
	pop	dph1 
 | 
						|
	pop	dpl1
 | 
						|
	pop	dph 
 | 
						|
	pop	dpl 
 | 
						|
	pop	dps
 | 
						|
	reti
 | 
						|
 | 
						|
 | 
						|
	
 | 
						|
;;; all channels
 | 
						|
dalo:
 | 
						|
	movx	a,@dptr		; number of channels
 | 
						|
	inc	dptr		; pointer to the first channel
 | 
						|
	mov	r0,a		; 4 channels
 | 
						|
nextDA:	
 | 
						|
	movx	a,@dptr		; get the first low byte
 | 
						|
	mov	r3,a		; store in r3 (see below)
 | 
						|
	inc	dptr		; point to the high byte
 | 
						|
	movx	a,@dptr		; get the high byte
 | 
						|
	mov	r4,a		; store in r4 (for writeDA)
 | 
						|
	inc	dptr		; point to the channel number
 | 
						|
	movx	a,@dptr		; get the channel number
 | 
						|
	inc	dptr		; get ready for the next channel
 | 
						|
	lcall	writeDA		; write value to the DAC
 | 
						|
	djnz	r0,nextDA	; next channel
 | 
						|
	ret
 | 
						|
 | 
						|
 | 
						|
 | 
						|
;;; D/A-conversion:
 | 
						|
;;; control-byte in a,
 | 
						|
;;; value in r3(low) and r4(high)
 | 
						|
writeDA:			; mask the control byte
 | 
						|
	anl	a,#11000000b	; only the channel is left
 | 
						|
	orl	a,#00110000b	; internal clock, bipolar mode, +/-5V
 | 
						|
	orl	a,r4		; or the value of R4 to it
 | 
						|
	;; set CS to low
 | 
						|
	clr	IOA.5		; set /CS to zero
 | 
						|
	;; send the first byte to the DA-converter
 | 
						|
	mov 	R2,#8		; bit-counter
 | 
						|
DA1:    jnb     ACC.7,zeroda	; jump if Bit7 = 0?
 | 
						|
	setb	IOA.2		; set the DIN bit
 | 
						|
	sjmp	clkda		; continue with the clock
 | 
						|
zeroda: clr	IOA.2		; clear the DIN bit
 | 
						|
clkda:	setb	IOA.0		; SCLK = 1
 | 
						|
	clr	IOA.0		; SCLK = 0
 | 
						|
        rl      a               ; next Bit
 | 
						|
        djnz    R2,DA1
 | 
						|
 | 
						|
	
 | 
						|
	;; send the second byte to the DA-converter
 | 
						|
	mov	a,r3		; low byte
 | 
						|
	mov 	R2,#8		; bit-counter
 | 
						|
DA2:    jnb     ACC.7,zeroda2	; jump if Bit7 = 0?
 | 
						|
	setb	IOA.2		; set the DIN bit
 | 
						|
	sjmp	clkda2		; continue with the clock
 | 
						|
zeroda2:clr	IOA.2		; clear the DIN bit
 | 
						|
clkda2:	setb	IOA.0		; SCLK = 1
 | 
						|
	clr	IOA.0		; SCLK = 0
 | 
						|
        rl      a               ; next Bit
 | 
						|
        djnz    R2,DA2
 | 
						|
	;; 
 | 
						|
	setb	IOA.5		; set /CS to one
 | 
						|
	;; 
 | 
						|
noDA:	ret
 | 
						|
	
 | 
						|
 | 
						|
 | 
						|
;;; arm ep6
 | 
						|
ep6_arm:
 | 
						|
	lcall	conv_ad
 | 
						|
	
 | 
						|
	mov	DPTR,#EP6BCH	; byte count H
 | 
						|
	mov	a,#0		; is zero
 | 
						|
	lcall	syncdelaywr	; wait until the length has arrived
 | 
						|
	
 | 
						|
	mov	DPTR,#EP6BCL	; byte count L
 | 
						|
	mov	a,#10H		; is one
 | 
						|
	lcall	syncdelaywr	; wait until the length has been proc
 | 
						|
	ret
 | 
						|
	
 | 
						|
 | 
						|
 | 
						|
;;; converts one analog/digital channel and stores it in EP8
 | 
						|
;;; also gets the content of the digital ports B and D depending on
 | 
						|
;;; the COMMAND flag
 | 
						|
ep8_ops:
 | 
						|
	mov	dptr,#0fc01h	; ep8 fifo buffer
 | 
						|
	clr	a		; high byte
 | 
						|
	movx	@dptr,a		; set H=0
 | 
						|
	mov	dptr,#0fc00h	; low byte
 | 
						|
	mov	r0,#CMD_FLAG
 | 
						|
	mov	a,@r0
 | 
						|
	movx	@dptr,a		; save command byte
 | 
						|
 | 
						|
	mov	dptr,#ep8_jmp	; jump table for the different functions
 | 
						|
	rl	a		; multiply by 2: sizeof sjmp
 | 
						|
	jmp	@a+dptr		; jump to the jump table
 | 
						|
	;; jump table, corresponds to the command bytes defined
 | 
						|
	;; in usbdux.c
 | 
						|
ep8_jmp:
 | 
						|
	sjmp	ep8_err		; a=0, err
 | 
						|
	sjmp	ep8_err		; a=1, err
 | 
						|
	sjmp	ep8_err		; a=2, err
 | 
						|
	sjmp	ep8_dio		; a=3, digital read
 | 
						|
	sjmp	ep8_sglchannel	; a=4, analog A/D
 | 
						|
	sjmp	ep8_readctr	; a=5, read counter
 | 
						|
	sjmp	ep8_err		; a=6, write counter
 | 
						|
 | 
						|
	;; reads all counters
 | 
						|
ep8_readctr:
 | 
						|
	mov	r0,#CTR0	; points to counter0
 | 
						|
	mov	dptr,#0fc02h	; ep8 fifo buffer
 | 
						|
	mov	r1,#8		; transfer 4 16bit counters
 | 
						|
ep8_ctrlp:
 | 
						|
	mov	a,@r0		; get the counter
 | 
						|
	movx	@dptr,a		; save in the fifo buffer
 | 
						|
	inc	r0		; inc pointer to the counters
 | 
						|
	inc	dptr		; inc pointer to the fifo buffer
 | 
						|
	djnz	r1,ep8_ctrlp	; loop until ready
 | 
						|
	
 | 
						|
	sjmp	ep8_send	; send the data
 | 
						|
	
 | 
						|
	;; read one A/D channel
 | 
						|
ep8_sglchannel:		
 | 
						|
	mov	r0,#SGLCHANNEL	; points to the channel
 | 
						|
	mov 	a,@r0		; Ch0
 | 
						|
	
 | 
						|
	lcall 	readAD		; start the conversion
 | 
						|
		
 | 
						|
	mov 	DPTR,#0fc02h	; EP8 FIFO 
 | 
						|
	mov 	a,R3		; get low byte
 | 
						|
	movx 	@DPTR,A		; store in FIFO
 | 
						|
	inc	dptr		; next fifo entry
 | 
						|
	mov 	a,R4		; get high byte
 | 
						|
	movx 	@DPTR,A		; store in FIFO
 | 
						|
 | 
						|
	sjmp	ep8_send	; send the data
 | 
						|
 | 
						|
	;; read the digital lines
 | 
						|
ep8_dio:	
 | 
						|
	mov 	DPTR,#0fc02h	; store the contents of port B
 | 
						|
	mov	a,IOB		; in the next
 | 
						|
	movx	@dptr,a		; entry of the buffer
 | 
						|
 | 
						|
	inc	dptr
 | 
						|
	clr	a		; high byte is zero
 | 
						|
	movx	@dptr,a		; next byte of the EP
 | 
						|
	
 | 
						|
ep8_send:	
 | 
						|
	mov	DPTR,#EP8BCH	; byte count H
 | 
						|
	mov	a,#0		; is zero
 | 
						|
	lcall	syncdelaywr
 | 
						|
	
 | 
						|
	mov	DPTR,#EP8BCL	; byte count L
 | 
						|
	mov	a,#10H		; 16 bytes
 | 
						|
	lcall	syncdelaywr	; send the data over to the host
 | 
						|
 | 
						|
ep8_err:	
 | 
						|
	ret
 | 
						|
 | 
						|
 | 
						|
 | 
						|
;;; EP8 interrupt: gets one measurement from the AD converter and
 | 
						|
;;; sends it via EP8. The channel # is stored in address 80H.
 | 
						|
;;; It also gets the state of the digital registers B and D.
 | 
						|
ep8_isr:	
 | 
						|
	push	dps
 | 
						|
	push	dpl
 | 
						|
	push	dph
 | 
						|
	push	dpl1
 | 
						|
	push	dph1
 | 
						|
	push	acc
 | 
						|
	push	psw
 | 
						|
	push	00h		; R0
 | 
						|
	push	01h		; R1
 | 
						|
	push	02h		; R2
 | 
						|
	push	03h		; R3
 | 
						|
	push	04h		; R4
 | 
						|
	push	05h		; R5
 | 
						|
	push	06h		; R6
 | 
						|
	push	07h		; R7
 | 
						|
		
 | 
						|
	lcall	ep8_ops
 | 
						|
	
 | 
						|
	;; clear INT2
 | 
						|
	mov	a,EXIF		; FIRST clear the USB (INT2) interrupt request
 | 
						|
	clr	acc.4
 | 
						|
	mov	EXIF,a		; Note: EXIF reg is not 8051 bit-addressable
 | 
						|
 | 
						|
	mov	DPTR,#EPIRQ	; 
 | 
						|
	mov	a,#10000000b	; clear the ep8irq
 | 
						|
	movx	@DPTR,a
 | 
						|
 | 
						|
	pop	07h
 | 
						|
	pop	06h
 | 
						|
	pop	05h
 | 
						|
	pop	04h		; R4
 | 
						|
	pop	03h		; R3
 | 
						|
	pop	02h		; R2
 | 
						|
	pop	01h		; R1
 | 
						|
	pop	00h		; R0
 | 
						|
	pop	psw
 | 
						|
	pop	acc 
 | 
						|
	pop	dph1 
 | 
						|
	pop	dpl1
 | 
						|
	pop	dph 
 | 
						|
	pop	dpl 
 | 
						|
	pop	dps
 | 
						|
	reti
 | 
						|
 | 
						|
 | 
						|
;; need to delay every time the byte counters
 | 
						|
;; for the EPs have been changed.
 | 
						|
 | 
						|
syncdelay:
 | 
						|
	nop
 | 
						|
	nop
 | 
						|
	nop
 | 
						|
	nop
 | 
						|
	nop
 | 
						|
	nop
 | 
						|
	nop
 | 
						|
	nop
 | 
						|
	nop
 | 
						|
	ret
 | 
						|
 | 
						|
syncdelaywr:
 | 
						|
	movx	@dptr,a
 | 
						|
	lcall	syncdelay
 | 
						|
	ret
 | 
						|
 | 
						|
 | 
						|
.End
 | 
						|
 | 
						|
 |