usbduxfast_firmware.asm 9.19 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
;   usbduxfast_firmware.asm
;   Copyright (C) 2004,2009 Bernd Porr, Bernd.Porr@f2s.com
;
;   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: usbduxfast_firmware.asm for usbdux.c
; Description: Firmware for usbduxfast
; Devices: [ITL] USB-DUX (usbdux.o)
; Author: Bernd Porr <Bernd.Porr@f2s.com>
; Updated: 17 Apr 2009
; Status: stable
;
;;;
;;;
;;;

	.inc	fx2-include.asm

	.equ	WFLOADED,70H	; waveform is loaded

	.org	0000h		; after reset the processor starts here
	ljmp	main		; jump to the main loop

	.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
sof_isr:
sudav_isr:	
sutok_isr:	
suspend_isr:	
usbreset_isr:	
hispeed_isr:	
ep0ack_isr:	
spare_isr:	
ep0in_isr:	
ep0out_isr:	
ep1out_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:
ep8_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,#REVCTL
	mov	a,#00000011b	; allows skip
	lcall	syncdelaywr

	mov	DPTR,#CPUCS	; CPU control register
	mov	a,#00010000b	; 48Mhz
	lcall	syncdelaywr

	mov	dptr,#IFCONFIG	; switch on IFCLK signal
	mov	a,#10100010b	; gpif, 30MHz
	lcall	syncdelaywr

	mov	dptr,#FIFORESET
	mov	a,#80h
	lcall	syncdelaywr
	mov	a,#8
	lcall	syncdelaywr
	mov	a,#2		
	lcall	syncdelaywr
	mov	a,#4		
	lcall	syncdelaywr
	mov	a,#6		
	lcall	syncdelaywr
	mov	a,#0		
	lcall	syncdelaywr

	mov	dptr,#INTSETUP	; IRQ setup register
	mov	a,#08h		; enable autovector
	lcall	syncdelaywr

	lcall	initeps		; init the isochronous data-transfer

	lcall	initGPIF

;;; main loop

mloop2:
	lcall	gpif_run
	sjmp	mloop2		; do nothing. The rest is done by the IRQs


gpif_run:
	mov	a,WFLOADED
	jz	no_trig		; do not trigger
	mov	a,GPIFTRIG	; GPIF status
	anl	a,#80h		; done bit
	jz	no_trig		; GPIF busy

;;; gpif has stopped
	mov	a,#06h		; RD,EP6
	mov	GPIFTRIG,a
no_trig:
	ret

	

initGPIF:
	mov	DPTR,#EP6CFG	; BLK data from here to the host
	mov	a,#11100000b	; Valid, quad buffering
	lcall	syncdelaywr	; write

	mov	dptr,#EP6FIFOCFG
	mov	a,#00001001b	; autoin, wordwide
	lcall	syncdelaywr

	mov	dptr,#EP6AUTOINLENH
	mov	a,#00000010b	; 512 bytes
	lcall	syncdelaywr	; write

	mov	dptr,#EP6AUTOINLENL
	mov	a,#00000000b	; 0
	lcall	syncdelaywr	; write

	mov	dptr,#GPIFWFSELECT
	mov	a,#11111100b	; waveform 0 for FIFO RD
	lcall	syncdelaywr

	mov	dptr,#GPIFCTLCFG
	mov	a,#10000000b	; tri state for CTRL
	lcall	syncdelaywr

	mov	dptr,#GPIFIDLECTL
	mov	a,#11111111b	; all CTL outputs high
	lcall	syncdelaywr
	mov	a,#11111101b	; reset counter
	lcall	syncdelaywr
	mov	a,#11111111b	; reset to high again
	lcall	syncdelaywr

	mov	a,#00000010b	; abort when full
	mov	dptr,#EP6GPIFFLGSEL
	lcall	syncdelaywr

	mov	a,#00000001b	; stop when buffer overfl
	mov	dptr,#EP6GPIFPDFSTOP
	lcall	syncdelaywr

	mov	a,#0
	mov	dptr,#GPIFREADYCFG
	lcall	syncdelaywr

	mov	a,#0
	mov	dptr,#GPIFIDLECS
	lcall	syncdelaywr

; waveform 1
; this is a dummy waveform which is used
; during the upload of another waveform into
; wavefrom 0
; it branches directly into the IDLE state
	mov	dptr,#0E420H
	mov	a,#00111111b	; branch to IDLE
	lcall	syncdelaywr

	mov	dptr,#0E428H	; opcode
	mov	a,#00000001b	; deceision point
	lcall	syncdelaywr

	mov	dptr,#0E430H
	mov	a,#0FFH		; output is high
	lcall	syncdelaywr

	mov	dptr,#0E438H
	mov	a,#0FFH		; logic function
	lcall	syncdelaywr

; signals that no waveform 0 is loaded so far
	mov	WFLOADED,#0	; waveform flag

	ret



;;; initilise the transfer
;;; It is assumed that the USB interface is in alternate setting 1
initeps:
	mov	DPTR,#EP4CFG
	mov	a,#10100000b	; valid, bulk, out
	lcall	syncdelaywr

	mov	dptr,#EP4BCL	; "arm" it
	mov	a,#00h
	lcall	syncdelaywr	; wait until we can write again
	lcall	syncdelaywr	; wait
	lcall	syncdelaywr	; wait

	mov	DPTR,#EP8CFG
	mov	a,#0		; disable EP8, it overlaps with EP6!!
	lcall	syncdelaywr

	mov	dptr,#EPIE	; interrupt enable
	mov	a,#00100000b	; enable irq for ep4
	lcall	syncdelaywr	; do it

	mov	dptr,#EPIRQ	; clear IRQs
	mov	a,#00100100b
	movx	@dptr,a

        mov     DPTR,#USBIE	; USB int enable register
        mov     a,#0            ; SOF etc
        movx    @DPTR,a         ;

        mov     DPTR,#GPIFIE	; GPIF int enable register
        mov     a,#0            ; done IRQ
        movx    @DPTR,a         ;

	mov	EIE,#00000001b	; enable INT2 in the 8051's SFR
	mov	IE,#80h		; IE, enable all interrupts

	ret


;;; interrupt-routine for ep4
;;; receives the channel list and other commands
ep4_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,#0f400h	; FIFO buffer of EP4
	movx	a,@dptr		; get the first byte

	mov	dptr,#ep4_jmp	; jump table for the different functions
	rl	a		; multiply by 2: sizeof sjmp
	jmp	@a+dptr		; jump to the jump table

ep4_jmp:
	sjmp	storewaveform	; a=0
	sjmp	init_ep6	; a=1
	
init_ep6:
	; stop ep6
	; just now do nothing

	ljmp	over_wf


storewaveform:
	mov	WFLOADED,#0	; waveform flag

	mov	dptr,#EP6FIFOCFG
	mov	a,#00000000b	;
	lcall	syncdelaywr

	mov	dptr,#GPIFABORT
	mov	a,#0ffh		; abort all transfers
	lcall	syncdelaywr

wait_f_abort:
	mov	a,GPIFTRIG	; GPIF status
	anl	a,#80h		; done bit
	jz	wait_f_abort	; GPIF busy

	mov	dptr,#GPIFWFSELECT
	mov	a,#11111101b	; select dummy waveform
	movx	@dptr,a
	lcall	syncdelay

	mov	dptr,#FIFORESET
	mov	a,#80h		; NAK
	lcall	syncdelaywr
	mov	a,#6		; reset EP6
	lcall	syncdelaywr
	mov	a,#0		; normal op
	lcall	syncdelaywr

; change to dummy waveform 1
	mov	a,#06h		; RD,EP6
	mov	GPIFTRIG,a

; wait a bit
	mov	r2,255
loopx:
	djnz	r2,loopx

; abort waveform if not already so
	mov	dptr,#GPIFABORT
	mov	a,#0ffh		; abort all transfers
	lcall	syncdelaywr

; wait again
	mov	r2,255
loopx2:
	djnz	r2,loopx2

; check for DONE
wait_f_abort2:
	mov	a,GPIFTRIG	; GPIF status
	anl	a,#80h		; done bit
	jz	wait_f_abort2	; GPIF busy

; upload the new waveform into waveform 0
	mov	AUTOPTRH2,#0E4H	; XDATA0H
	lcall	syncdelay
	mov	AUTOPTRL2,#00H	; XDATA0L
	lcall	syncdelay

	mov	AUTOPTRH1,#0F4H	; EP4 high
	lcall	syncdelay
	mov	AUTOPTRL1,#01H	; EP4 low
	lcall	syncdelay

	mov	AUTOPTRSETUP,#7	; autoinc and enable
	lcall	syncdelay

	mov 	r2,#20H		; 32 bytes to transfer

wavetr:
	mov 	dptr,#XAUTODAT1
	movx	a,@dptr
	lcall	syncdelay
	mov	dptr,#XAUTODAT2
	movx	@dptr,a
	lcall	syncdelay
	djnz	r2,wavetr

	mov	dptr,#EP6FIFOCFG
	mov	a,#00001001b	; autoin, wordwide
	lcall	syncdelaywr

	mov	dptr,#GPIFWFSELECT
	mov	a,#11111100b
	movx	@dptr,a
	lcall	syncdelay

	mov	dptr,#FIFORESET
	mov	a,#80h		; NAK
	lcall	syncdelaywr
	mov	a,#6		; reset EP6
	lcall	syncdelaywr
	mov	a,#0		; normal op
	lcall	syncdelaywr

	mov	dptr,#0E400H+10H; waveform 0: first CTL byte
	movx	a,@dptr		; get it
	orl	a,#11111011b	; force all bits to one except the range bit
	mov	dptr,#GPIFIDLECTL
	lcall	syncdelaywr

	mov	WFLOADED,#1	; waveform flag

; do the common things here	
over_wf:	
	mov	dptr,#EP4BCL
	mov	a,#00h
	movx	@DPTR,a		; arm it
	lcall	syncdelay	; wait
	movx	@DPTR,a		; arm it
	lcall	syncdelay	; wait

	;; 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,#00100000b	; clear the ep4irq
	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:
	lcall	syncdelay
	movx	@dptr,a
	ret


.End