You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
547 lines
9.2 KiB
547 lines
9.2 KiB
; 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 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|